deploy-stack 0.17.5 ā 0.17.7
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 +8 -1
- package/bin/cli.js +17 -6
- package/docs/ROADMAP.md +10 -4
- package/docs/examples.md +16 -1
- package/docs/guides/headless.md +6 -3
- package/docs/guides/secrets-management.md +35 -9
- package/package.json +1 -1
- package/src/commands/init.js +1 -1
- package/src/commands/secrets.js +38 -9
- package/src/core/telemetry.js +1 -2
- package/src/utils/prompts.js +1 -1
package/README.md
CHANGED
|
@@ -132,6 +132,7 @@ your-project/
|
|
|
132
132
|
* **[Next.js Fullstack App](https://github.com/anton-codes-iac/deploy-stack-nextjs-example):** A complete Next.js deployment showcasing the generated Terraform, CloudFront setup, and automated OIDC workflow.
|
|
133
133
|
* **[Docker Compose to AWS Migration](https://github.com/anton-codes-iac/deploy-stack-docker-compose-example):** Demonstrates automatic translation of local `docker-compose.yml` sidecars (like Redis) into a multi-container AWS ECS Task Definition communicating over `localhost`.
|
|
134
134
|
* **[Heroku to AWS Migration (Django)](https://github.com/anton-codes-iac/deploy-stack-heroku-django-example):** A classic Heroku-style monolith migrated via the Procfile Importer.
|
|
135
|
+
* **[Zero-Secret AWS Secrets Manager Injection](https://github.com/anton-codes-iac/deploy-stack-secrets-example):** A production-grade Node.js architecture demonstrating zero-plaintext secret injection. Encrypts local `.env` variables directly into AWS and maps them into ECS memory at container boot, verified against GitHub's API.
|
|
135
136
|
|
|
136
137
|
š **[View all 14+ reference implementations in our Examples Gallery](./docs/examples.md)**
|
|
137
138
|
|
|
@@ -165,7 +166,13 @@ npx deploy-stack --no-telemetry
|
|
|
165
166
|
### Current Focus (Phase 7: Team Workflows & Ecosystem Integrations)
|
|
166
167
|
- [x] **Ephemeral PR Previews:** Generate GitHub Actions workflows that spin up temporary ECS Fargate tasks and post live preview URLs directly in pull request comments to streamline team code reviews.
|
|
167
168
|
- [x] **AI Context Synchronization:** Implement `deploy-stack sync-ai` to automatically generate `.cursorrules` and AI context files, ensuring coding assistants generate accurate deployment commands tailored to the project.
|
|
168
|
-
- [ ] **Native Ecosystem Integrations:** Publish seamless, push-button plugins across major
|
|
169
|
+
- [ ] **Native Ecosystem Integrations & Scaffolding:** Publish seamless, push-button plugins and templates across major framework package registries:
|
|
170
|
+
- [x] `vite-plugin-deploy-stack` (Vite / React / Vue SPA ecosystem)
|
|
171
|
+
- [x] `svelte-adapter-deploy-stack` (SvelteKit adapter integration)
|
|
172
|
+
- [x] `cookiecutter-django-deploy-stack` (Listed on Django Packages)
|
|
173
|
+
- [ ] `cookiecutter-fastapi-deploy-stack` (Cookiecutter for modern async Python)
|
|
174
|
+
- [ ] `nest-deploy-stack` (Native `nest add` schematic for NestJS)
|
|
175
|
+
- [ ] `rails-template-deploy-stack` (Zero-click Ruby on Rails application template)
|
|
169
176
|
- [ ] **Automated Troubleshooting:** Build `deploy-stack diagnose` (alias: `wtf`) to automatically analyze and troubleshoot common day-2 AWS operational issues (e.g., Fargate OOM kills, ALB 502s) directly from the terminal.
|
|
170
177
|
|
|
171
178
|
š **[See the full project history and future plans in ROADMAP.md](./ROADMAP.md)**
|
package/bin/cli.js
CHANGED
|
@@ -10,20 +10,29 @@ import { syncAi } from '../src/commands/sync-ai.js';
|
|
|
10
10
|
|
|
11
11
|
// 1. Extract the telemetry flag and set the environment variable
|
|
12
12
|
const rawArgs = process.argv.slice(2);
|
|
13
|
-
const hasNoTelemetry = rawArgs.
|
|
13
|
+
const hasNoTelemetry = rawArgs.some(arg => arg === '--no-telemetry' || arg.startsWith('--no-telemetry='));
|
|
14
14
|
|
|
15
15
|
if (hasNoTelemetry) {
|
|
16
16
|
process.env.DO_NOT_TRACK = '1';
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
// 2. Filter out the telemetry flag from the args so the subcommands don't see it
|
|
20
|
-
const args = rawArgs.filter((arg) => arg !== '--no-telemetry');
|
|
20
|
+
const args = rawArgs.filter((arg) => arg !== '--no-telemetry' && !arg.startsWith('--no-telemetry='));
|
|
21
21
|
|
|
22
|
-
// 3.
|
|
22
|
+
// 3. Isolate positional commands from flags
|
|
23
|
+
// This ensures flags (e.g., --dry-run) don't accidentally become file paths
|
|
24
|
+
const positionalArgs = args.filter(arg => !arg.startsWith('--'));
|
|
25
|
+
|
|
26
|
+
// Safely capture the base command for telemetry (ignoring file paths)
|
|
27
|
+
const baseCommand = positionalArgs.length > 0 ? positionalArgs.slice(0, 2).join(' ') : 'init';
|
|
28
|
+
process.env.CLI_COMMAND = baseCommand;
|
|
29
|
+
|
|
30
|
+
// 4. Parse headless flags
|
|
23
31
|
const isHeadless = args.includes('--headless');
|
|
24
32
|
const isDryRun = args.includes('--dry-run');
|
|
25
33
|
const getFlag = (flagName) => {
|
|
26
|
-
const match = args.find(a => a.startsWith(`--${flagName}=`));
|
|
34
|
+
const match = args.find(a => a === `--${flagName}` || a.startsWith(`--${flagName}=`));
|
|
35
|
+
if (match === `--${flagName}`) return true;
|
|
27
36
|
return match ? match.split('=')[1] : undefined;
|
|
28
37
|
};
|
|
29
38
|
const headlessOptions = isHeadless ? {
|
|
@@ -34,10 +43,12 @@ const headlessOptions = isHeadless ? {
|
|
|
34
43
|
size: getFlag('size'),
|
|
35
44
|
healthCheckPath: getFlag('healthCheckPath'),
|
|
36
45
|
desiredCount: getFlag('desiredCount'),
|
|
37
|
-
branch: getFlag('branch')
|
|
46
|
+
branch: getFlag('branch'),
|
|
47
|
+
needsDatabase: getFlag('needsDatabase'),
|
|
48
|
+
enablePrPreviews: getFlag('enablePrPreviews')
|
|
38
49
|
} : {};
|
|
39
50
|
|
|
40
|
-
//
|
|
51
|
+
// 5. Handle commands
|
|
41
52
|
if (args[0] === 'secrets' && args[1] === 'push') {
|
|
42
53
|
const envFile = args[2] || '.env';
|
|
43
54
|
const projectName = path.basename(process.cwd());
|
package/docs/ROADMAP.md
CHANGED
|
@@ -24,7 +24,13 @@
|
|
|
24
24
|
|
|
25
25
|
### Phase 7: Team Workflows & Ecosystem Integrations (Current)
|
|
26
26
|
*Focus: Enhance collaborative development and expand native support across major framework ecosystems.*
|
|
27
|
-
- [x] **Ephemeral PR Previews:** Generate GitHub Actions workflows that spin up temporary ECS Fargate tasks and post live URLs directly in
|
|
28
|
-
- [x] **AI Context Synchronization:** Implement `deploy-stack sync-ai` to automatically generate `.cursorrules` and AI context files, ensuring
|
|
29
|
-
- [ ] **Native Ecosystem Integrations:** Publish push-button plugins across major frameworks
|
|
30
|
-
- [
|
|
27
|
+
- [x] **Ephemeral PR Previews:** Generate GitHub Actions workflows that spin up temporary ECS Fargate tasks and post live preview URLs directly in pull request comments to streamline team code reviews.
|
|
28
|
+
- [x] **AI Context Synchronization:** Implement `deploy-stack sync-ai` to automatically generate `.cursorrules` and AI context files, ensuring coding assistants generate accurate deployment commands tailored to the project.
|
|
29
|
+
- [ ] **Native Ecosystem Integrations:** Publish seamless, push-button plugins across major frameworks.
|
|
30
|
+
- [x] `vite-plugin-deploy-stack` (Live on NPM)
|
|
31
|
+
- [x] `svelte-adapter-deploy-stack` (SvelteKit adapter integration)
|
|
32
|
+
- [x] `cookiecutter-django-deploy-stack` (Listed on Django Packages)
|
|
33
|
+
- [ ] `cookiecutter-fastapi-deploy-stack` (Cookiecutter for modern async Python)
|
|
34
|
+
- [ ] `nest-deploy-stack` (Native `nest add` schematic for NestJS)
|
|
35
|
+
- [ ] `rails-template-deploy-stack` (Zero-click Ruby on Rails application template)
|
|
36
|
+
- [ ] **Automated Troubleshooting:** Build `deploy-stack diagnose` (alias: `wtf`) to automatically analyze and troubleshoot common day-2 AWS operational issues (e.g., Fargate OOM kills, ALB 502s) directly from the terminal.
|
package/docs/examples.md
CHANGED
|
@@ -7,6 +7,9 @@ These repositories demonstrate how `deploy-stack` handles various frameworks and
|
|
|
7
7
|
* **[Vercel to AWS Migration (Next.js)](https://github.com/anton-codes-iac/deploy-stack-vercel-nextjs-example):** Demonstrates automatic translation of Vercel edge routing (`vercel.json`) to native AWS Application Load Balancer rules.
|
|
8
8
|
* **[Docker Compose to AWS Migration](https://github.com/anton-codes-iac/deploy-stack-docker-compose-example):** Demonstrates automatic translation of local `docker-compose.yml` sidecars (like Redis) into a multi-container AWS ECS Task Definition communicating over `localhost`.
|
|
9
9
|
|
|
10
|
+
### DevSecOps & Security Architectures
|
|
11
|
+
* **[Zero-Secret AWS Secrets Manager Injection](https://github.com/anton-codes-iac/deploy-stack-secrets-example):** A production-grade Node.js architecture demonstrating zero-plaintext secret injection. It pushes local `.env` variables directly to AWS and maps them into ECS memory at runtime, exposing a live endpoint querying GitHub's API.
|
|
12
|
+
|
|
10
13
|
### Frontend & Fullstack Frameworks
|
|
11
14
|
* **[Next.js Fullstack App](https://github.com/anton-codes-iac/deploy-stack-nextjs-example):** A complete Next.js deployment showcasing the generated Terraform, CloudFront setup, and automated OIDC workflow.
|
|
12
15
|
* **[Vite / React SPA](https://github.com/anton-codes-iac/deploy-stack-vite-example):** Demonstrates SPA routing and `dist/` auto-detection.
|
|
@@ -20,4 +23,16 @@ These repositories demonstrate how `deploy-stack` handles various frameworks and
|
|
|
20
23
|
* **[Python FastAPI](https://github.com/anton-codes-iac/deploy-stack-fastapi-example):** A Python API demonstrating unprivileged port mapping.
|
|
21
24
|
* **[Ruby on Rails](https://github.com/anton-codes-iac/deploy-stack-rails-example):** A production Rails 7+ setup featuring an auto-provisioned PostgreSQL database and secure `.auto.tfvars` Master Key injection.
|
|
22
25
|
* **[Django / Python](https://github.com/anton-codes-iac/deploy-stack-django-example):** A secure Gunicorn/WSGI implementation with PostgreSQL and unprivileged container adapters.
|
|
23
|
-
* **[Go / Fiber](https://github.com/anton-codes-iac/deploy-stack-go-example):** A distroless, compiled Go binary deployment demonstrating ultra-low memory footprints and instant boot times.
|
|
26
|
+
* **[Go / Fiber](https://github.com/anton-codes-iac/deploy-stack-go-example):** A distroless, compiled Go binary deployment demonstrating ultra-low memory footprints and instant boot times.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## š§© Ecosystem Plugins & Starters
|
|
31
|
+
|
|
32
|
+
In addition to standalone reference repositories, `deploy-stack` provides native integrations that hook directly into framework build pipelines and community template engines:
|
|
33
|
+
|
|
34
|
+
* **[astro-deploy-stack](https://www.npmjs.com/package/astro-deploy-stack):** Push-button deployment plugin for Astro sites.
|
|
35
|
+
* **[nuxt-deploy-stack](https://www.npmjs.com/package/nuxt-deploy-stack):** Nitro-optimized deployment integration for Nuxt 3 applications.
|
|
36
|
+
* **[vite-plugin-deploy-stack](https://www.npmjs.com/package/vite-plugin-deploy-stack):** Zero-config Vite build plugin for single-page applications.
|
|
37
|
+
* **[svelte-adapter-deploy-stack](https://www.npmjs.com/package/svelte-adapter-deploy-stack):** Native SvelteKit adapter producing optimized Fargate container builds.
|
|
38
|
+
* **[cookiecutter-django-deploy-stack](https://github.com/anton-codes-iac/cookiecutter-django-deploy-stack):** Community Django starter listed on [Django Packages](https://djangopackages.org/packages/p/cookiecutter-django-deploy-stack/) with built-in Fargate and managed RDS scaffolding.
|
package/docs/guides/headless.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Headless Mode & Automation Guide
|
|
2
2
|
|
|
3
|
-
The `deploy-stack` CLI is designed to be fully automatable for CI/CD pipelines, custom scripts, and framework plugins (like `vite-plugin-deploy-stack`).
|
|
3
|
+
The `deploy-stack` CLI is designed to be fully automatable for CI/CD pipelines, custom scripts, Cookiecutters, and framework plugins (like `vite-plugin-deploy-stack`).
|
|
4
4
|
|
|
5
5
|
By passing the `--headless` flag, you bypass all interactive terminal prompts.
|
|
6
6
|
|
|
@@ -24,10 +24,13 @@ You can append any of these flags to customize the generated architecture. These
|
|
|
24
24
|
| `--desiredCount=<number>` | Number of container replicas to run (`1` or `2`). | `1` |
|
|
25
25
|
| `--branch=<name>` | The primary Git deployment branch for CI/CD. | `main` |
|
|
26
26
|
| `--dir=<path>` | The directory to generate files into (use `.` for current).| `.` |
|
|
27
|
+
| `--needsDatabase` | Provisions a managed AWS RDS PostgreSQL database alongside Fargate. | `false` |
|
|
27
28
|
| `--enablePrPreviews` | Generates workflows for Ephemeral PR Previews. | `false` |
|
|
28
29
|
| `--yes` | Automatically bypasses confirmation prompts during apply/destroy. | `false` |
|
|
29
30
|
| `--no-telemetry` | Disables anonymous usage analytics. | `false` |
|
|
30
31
|
|
|
32
|
+
*(Note: Boolean flags like `--needsDatabase` and `--enablePrPreviews` can be passed alone or as `--flag=true`).*
|
|
33
|
+
|
|
31
34
|
## Example Usage
|
|
32
35
|
|
|
33
36
|
**Standard Static Site Automation (e.g., Vite/React):**
|
|
@@ -40,7 +43,7 @@ npx deploy-stack --headless --framework=static --region=eu-west-1 --size=micro
|
|
|
40
43
|
npx deploy-stack --headless --framework=nextjs --size=small --desiredCount=2 --yes
|
|
41
44
|
```
|
|
42
45
|
|
|
43
|
-
**
|
|
46
|
+
**Django Setup with Managed RDS Database:**
|
|
44
47
|
```bash
|
|
45
|
-
npx deploy-stack --headless --framework=
|
|
48
|
+
npx deploy-stack --headless --framework=django --needsDatabase
|
|
46
49
|
```
|
|
@@ -2,23 +2,49 @@
|
|
|
2
2
|
|
|
3
3
|
Managing `.env` files across a team and syncing them to the cloud is a notorious pain point. `deploy-stack` solves this by natively integrating with **AWS Secrets Manager**, ensuring zero plaintext secrets ever touch your GitHub repository or CI/CD pipelines.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## The Secrets Lifecycle
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
To maintain zero-secret Git repositories and safe infrastructure provisioning, secrets follow a strict 4-step lifecycle:
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
1. Scaffold āāāā¶ 2. Provision Vault āāāā¶ 3. Push Secrets āāāā¶ 4. Deploy to App
|
|
11
|
+
(deploy-stack) (deploy-stack apply) (secrets push .env) (git push)
|
|
12
|
+
Generates Terraform Creates empty vault Uploads encrypted keys ECS container boots
|
|
13
|
+
& secret_keys.json in AWS Secrets Mgr & updates secret_keys with injected env
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
### Step 1: Provision the Vault (Day 1)
|
|
19
|
+
Your Secrets Manager vault is declared in `terraform/secrets.tf`. Provision the base infrastructure first:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx deploy-stack apply
|
|
23
|
+
```
|
|
24
|
+
*This creates an empty, secure secret vault named `<project-name>-secrets` in your AWS account.*
|
|
25
|
+
|
|
26
|
+
### Step 2: Push Secrets to AWS
|
|
27
|
+
Once the vault exists, push your local `.env` values directly to AWS:
|
|
8
28
|
|
|
9
29
|
```bash
|
|
10
|
-
npx deploy-stack secrets push .env
|
|
30
|
+
npx deploy-stack secrets push .env
|
|
11
31
|
```
|
|
12
32
|
|
|
13
|
-
|
|
14
|
-
1. The CLI reads your local `.env
|
|
33
|
+
**What happens under the hood?**
|
|
34
|
+
1. The CLI reads your local `.env` file.
|
|
15
35
|
2. It encrypts the key-value pairs and pushes them securely into AWS Secrets Manager under your project's namespace (e.g., `my-project-secrets`).
|
|
16
36
|
3. It generates a local `terraform/secret_keys.json` file containing *only the names* of your keys (e.g., `["API_KEY", "STRIPE_SECRET"]`), **not the values**.
|
|
17
37
|
|
|
18
|
-
|
|
38
|
+
> š” **Tip:** The `secrets push` command takes the file path as the first argument. If you need to use other flags, ensure they are appended at the end of the command:
|
|
39
|
+
> `npx deploy-stack secrets push .env --any-other-flags`
|
|
19
40
|
|
|
20
|
-
|
|
41
|
+
### Step 3: Map Secrets into the Container
|
|
42
|
+
Commit the updated `terraform/secret_keys.json` and push to GitHub:
|
|
21
43
|
|
|
22
|
-
|
|
44
|
+
```bash
|
|
45
|
+
git add terraform/secret_keys.json
|
|
46
|
+
git commit -m "chore: map new secrets to ECS"
|
|
47
|
+
git push origin main
|
|
48
|
+
```
|
|
23
49
|
|
|
24
|
-
|
|
50
|
+
Terraform reads `secret_keys.json` during the GitHub Actions deployment and maps each key directly into your ECS Task Definition. When your Fargate container boots up, AWS injects the secret values into `process.env` (Node) or `os.environ` (Python) in memory.
|
package/package.json
CHANGED
package/src/commands/init.js
CHANGED
|
@@ -117,7 +117,7 @@ export async function mainStack({ isHeadless = false, headlessOptions = {} } = {
|
|
|
117
117
|
} catch (error) {
|
|
118
118
|
s.stop('ā Failed to provision remote state or authenticate with AWS.');
|
|
119
119
|
console.error(color.red(`AWS Error: ${error.message}`));
|
|
120
|
-
trackEvent('cli-error', { step: 'aws_provisioning', error_code: error.name || 'UNKNOWN' });
|
|
120
|
+
trackEvent('cli-error', { step: 'aws_provisioning', error_code: error.name || 'UNKNOWN', error_message: error.message });
|
|
121
121
|
await flushTelemetry();
|
|
122
122
|
process.exit(1);
|
|
123
123
|
}
|
package/src/commands/secrets.js
CHANGED
|
@@ -13,7 +13,16 @@ export async function pushSecrets(envFilePath, projectName) {
|
|
|
13
13
|
try {
|
|
14
14
|
// 1. Read and parse the local .env file
|
|
15
15
|
const envPath = path.resolve(process.cwd(), envFilePath);
|
|
16
|
-
|
|
16
|
+
let envContent;
|
|
17
|
+
try {
|
|
18
|
+
envContent = await fs.readFile(envPath, 'utf-8');
|
|
19
|
+
} catch (fsError) {
|
|
20
|
+
if (fsError.code === 'ENOENT') {
|
|
21
|
+
throw new Error(`File not found: ${envFilePath}. Please ensure the file exists before pushing.`);
|
|
22
|
+
}
|
|
23
|
+
throw fsError; // Re-throw if it's a permissions issue
|
|
24
|
+
}
|
|
25
|
+
|
|
17
26
|
const parsedSecrets = dotenv.parse(envContent);
|
|
18
27
|
|
|
19
28
|
if (Object.keys(parsedSecrets).length === 0) {
|
|
@@ -21,12 +30,23 @@ export async function pushSecrets(envFilePath, projectName) {
|
|
|
21
30
|
return;
|
|
22
31
|
}
|
|
23
32
|
|
|
24
|
-
// 2.
|
|
25
|
-
|
|
26
|
-
|
|
33
|
+
// 2. Dynamically resolve the exact region from Terraform
|
|
34
|
+
let targetRegion = process.env.AWS_REGION;
|
|
35
|
+
try {
|
|
36
|
+
const mainTfPath = path.join(process.cwd(), 'terraform', 'main.tf');
|
|
37
|
+
const mainTfContent = await fs.readFile(mainTfPath, 'utf-8');
|
|
38
|
+
const regionMatch = mainTfContent.match(/region\s*=\s*"([^"]+)"/);
|
|
39
|
+
if (regionMatch) {
|
|
40
|
+
targetRegion = regionMatch[1];
|
|
41
|
+
}
|
|
42
|
+
} catch (e) {
|
|
43
|
+
// Silently fallback to AWS profile defaults if file read fails
|
|
44
|
+
}
|
|
27
45
|
|
|
28
|
-
// 3.
|
|
29
|
-
|
|
46
|
+
// 3. Initialize the AWS Client locked to the correct region
|
|
47
|
+
const client = new SecretsManagerClient(targetRegion ? { region: targetRegion } : {});
|
|
48
|
+
|
|
49
|
+
// 4. Update the secret string in AWS
|
|
30
50
|
const command = new UpdateSecretCommand({
|
|
31
51
|
SecretId: `${projectName}-secrets`,
|
|
32
52
|
SecretString: JSON.stringify(parsedSecrets),
|
|
@@ -39,7 +59,7 @@ export async function pushSecrets(envFilePath, projectName) {
|
|
|
39
59
|
|
|
40
60
|
await fs.writeFile(keysFilePath, JSON.stringify(keys, null, 2));
|
|
41
61
|
|
|
42
|
-
s.stop(`ā
Successfully pushed ${Object.keys(parsedSecrets).length} secrets to AWS!`);
|
|
62
|
+
s.stop(`ā
Successfully pushed ${Object.keys(parsedSecrets).length} secrets to AWS (${targetRegion || 'default region'})!`);
|
|
43
63
|
console.log(color.cyan(`\nUpdated ${keysFilePath}`));
|
|
44
64
|
console.log(color.green('Commit this file and push to GitHub to trigger a deployment with your new variables.'));
|
|
45
65
|
console.log(color.blue(`\nš Learn how secrets reach your app: ${color.underline('https://github.com/anton-codes-iac/deploy-stack/blob/main/docs/guides/secrets-management.md')}`));
|
|
@@ -52,13 +72,22 @@ export async function pushSecrets(envFilePath, projectName) {
|
|
|
52
72
|
await flushTelemetry();
|
|
53
73
|
|
|
54
74
|
} catch (error) {
|
|
55
|
-
|
|
75
|
+
if (error.name === 'ResourceNotFoundException') {
|
|
76
|
+
s.stop(color.red(`ā Secrets Vault "${projectName}-secrets" does not exist in AWS yet.`));
|
|
77
|
+
console.log(color.yellow('\nš” Next Step:'));
|
|
78
|
+
console.log(`Run ${color.cyan('npx --yes deploy-stack apply')} first to provision the infrastructure and Secrets Manager vault.`);
|
|
79
|
+
console.log(`Once applied, run ${color.cyan(`npx deploy-stack secrets push ${envFilePath}`)} to upload your environment variables.\n`);
|
|
80
|
+
} else {
|
|
81
|
+
s.stop(`ā Failed to push secrets: ${error.message}`);
|
|
82
|
+
}
|
|
56
83
|
|
|
57
84
|
trackEvent('secrets_pushed', {
|
|
58
85
|
projectName,
|
|
59
86
|
success: false,
|
|
60
|
-
error_code: error.name || 'UNKNOWN'
|
|
87
|
+
error_code: error.name || 'UNKNOWN',
|
|
88
|
+
error_message: error.message
|
|
61
89
|
});
|
|
62
90
|
await flushTelemetry();
|
|
91
|
+
process.exit(1);
|
|
63
92
|
}
|
|
64
93
|
}
|
package/src/core/telemetry.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import crypto from 'crypto';
|
|
2
2
|
|
|
3
3
|
const TELEMETRY_ENDPOINT = 'https://eu.i.posthog.com/capture/';
|
|
4
|
-
|
|
5
4
|
const POSTHOG_API_KEY = 'phc_o2wgA3jVT9rVDiGSDzFAR42zZeiVGhhCY53HXVHUcYGT';
|
|
6
|
-
|
|
7
5
|
const pendingRequests = [];
|
|
8
6
|
|
|
9
7
|
export function trackEvent(eventName, properties) {
|
|
@@ -27,6 +25,7 @@ export function trackEvent(eventName, properties) {
|
|
|
27
25
|
os: process.platform,
|
|
28
26
|
node_version: process.version,
|
|
29
27
|
is_ci: Boolean(process.env.CI || process.env.CONTINUOUS_INTEGRATION),
|
|
28
|
+
cli_command: process.env.CLI_COMMAND || 'unknown',
|
|
30
29
|
...properties
|
|
31
30
|
}
|
|
32
31
|
};
|
package/src/utils/prompts.js
CHANGED
|
@@ -46,7 +46,7 @@ export async function getProjectConfig(isHeadless, headlessOptions, targetDir, d
|
|
|
46
46
|
desiredCount: headlessOptions.desiredCount || '1',
|
|
47
47
|
branch: headlessOptions.branch || 'main',
|
|
48
48
|
needsDatabase: headlessOptions.needsDatabase === 'true' || headlessOptions.needsDatabase === true,
|
|
49
|
-
enablePrPreviews: headlessOptions.enablePrPreviews ||
|
|
49
|
+
enablePrPreviews: headlessOptions.enablePrPreviews === 'true' || headlessOptions.enablePrPreviews === true,
|
|
50
50
|
setupType: 'headless'
|
|
51
51
|
};
|
|
52
52
|
}
|