nodejs-quickstart-structure 2.0.0 โ†’ 2.0.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 CHANGED
@@ -1,5 +1,17 @@
1
1
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
2
2
 
3
+ ## [2.0.1] - 2026-04-07
4
+
5
+ ### Added
6
+ - **Universal CI/CD Support (Phase 8)**: Expanded the generator's CI/CD capabilities to include out-of-the-box support for **Bitbucket Pipelines** and **CircleCI**.
7
+ - **Modernized Pipe & Orb Integration**:
8
+ - Bitbucket templates now utilize official Atlassian Pipes for automated Snyk security scans and SonarCloud analysis.
9
+ - CircleCI configurations (v2.1) are optimized with official Orbs (`circleci/node`, `snyk/snyk`) for advanced dependency caching and security execution.
10
+ - **Project Blueprints (CI/CD Guide)**: Launched a comprehensive "CI/CD Setup Guide" in the VitePress documentation, providing step-by-step configuration workflows for all 5 supported platforms (GitHub, GitLab, Jenkins, Bitbucket, CircleCI).
11
+ - **CLI Ecosystem Sync**: Updated the interactive prompts and command-line flags to seamlessly integrate the new CI/CD choices while maintaining 100% backward compatibility.
12
+ - **Enterprise Readness Documentation**: Updated the generated `README.md` templates to officially include Bitbucket and CircleCI in the supported feature set.
13
+
14
+
3
15
  ## [2.0.0] - 2026-04-02
4
16
 
5
17
  ### Added
package/README.md CHANGED
@@ -40,7 +40,7 @@ The v2.0.0 release is a major leap forward, turning the generator into a **Commu
40
40
  - [๐Ÿš€ Quick Start](#-quick-start)
41
41
  - [โœจ Key Features](#-key-features)
42
42
  - [๐Ÿ›ก๏ธ Professional Standards](#-professional-standards)
43
- - [๐Ÿงฉ 1,680+ Project Combinations](#-1680-project-combinations)
43
+ - [๐Ÿงฉ 2,640+ Project Combinations](#-2640-project-combinations)
44
44
  - [โš™๏ธ Configuration Options](#-configuration-options)
45
45
  - [๐Ÿ—๏ธ Generated Project Structure](#-generated-project-structure)
46
46
  - [๐Ÿ“– Documentation](#-documentation)
@@ -88,19 +88,19 @@ We don't just generate boilerplate; we generate **production-ready** foundations
88
88
  - **๐Ÿ›ก๏ธ Enterprise Security**: Integrated **Snyk (SCA)**, **SonarCloud (SAST)**, `Helmet`, `HPP`, and Rate-Limiting.
89
89
  - **๐Ÿšจ Robust Error Handling**: Centralized global error middleware with custom error classes (`ApiError`, `NotFoundError`, etc.) โ€” consistent across REST & GraphQL.
90
90
  - **๐Ÿงช Testing Excellence**: Integrated `Jest` and `Supertest` with **>80% Unit Test coverage** out of the box.
91
- - **๐Ÿ”„ DevOps & CI/CD**: Optimized **Multi-Stage Dockerfiles**, health checks, infrastructure retry logic, and workflows for **GitHub Actions**, **Jenkins**, and **GitLab CI**.
91
+ - **๐Ÿ”„ DevOps & CI/CD**: Optimized **Multi-Stage Dockerfiles**, health checks, infrastructure retry logic, and workflows for **GitHub Actions**, **Jenkins**, **GitLab CI**, **CircleCI**, and **Bitbucket Pipelines**.
92
92
  - **๐Ÿš€ Scalable Deployment**: Integrated **PM2 Ecosystem** config for zero-downtime reloads.
93
93
 
94
94
  ---
95
95
 
96
- ## ๐Ÿงฉ 1,680+ Project Combinations
96
+ ## ๐Ÿงฉ 2,640+ Project Combinations
97
97
 
98
98
  The CLI supports a massive number of configurations to fit your exact needs:
99
99
 
100
100
  - **240 Core Combinations**:
101
101
  - **MVC Architecture**: 180 variants (Languages ร— View Engines ร— Databases ร— Communication Patterns ร— Caching)
102
102
  - **Clean Architecture**: 60 variants (Languages ร— Databases ร— Communication Patterns ร— Caching)
103
- - **1,680+ Total Scenarios**:
103
+ - **2,640+ Total Scenarios**:
104
104
  - Every combination can be generated across 3 CI/CD providers.
105
105
  - Optional **Enterprise-Grade Security Hardening** doubles the scenarios.
106
106
  - Every single scenario is verified to be compatible with our **80% Coverage Threshold** policy.
@@ -117,7 +117,7 @@ The CLI will guide you through:
117
117
  5. **Database**: `MySQL` | `PostgreSQL` | `MongoDB`
118
118
  6. **Communication**: `REST` | `GraphQL` | `Kafka`
119
119
  7. **Caching**: `None` | `Redis` | `Memory Cache`
120
- 8. **CI/CD**: `GitHub Actions` | `Jenkins` | `GitLab CI`
120
+ 8. **CI/CD**: `GitHub Actions` | `Jenkins` | `GitLab CI` | `CircleCI` | `Bitbucket Pipelines`
121
121
  9. **Security**: (Optional) Snyk & SonarCloud Hardening
122
122
 
123
123
  ---
package/bin/index.js CHANGED
@@ -29,7 +29,7 @@ program
29
29
  .option('-d, --database <database>', 'Database (MySQL, PostgreSQL)')
30
30
  .option('--db-name <name>', 'Database name')
31
31
  .option('-c, --communication <communication>', 'Communication (REST APIs, GraphQL, Kafka)')
32
- .option('--ci-provider <provider>', 'CI/CD Provider (None, GitHub Actions, Jenkins, GitLab CI)')
32
+ .option('--ci-provider <provider>', 'CI/CD Provider (None, GitHub Actions, Jenkins, GitLab CI, Bitbucket Pipelines, CircleCI)')
33
33
  .option('--include-security', 'Include Enterprise Security Hardening')
34
34
  .option('--no-include-security', 'Exclude Enterprise Security Hardening')
35
35
  .option('--caching <type>', 'Caching Layer (None/Redis)')
@@ -120,6 +120,16 @@ export const setupCiCd = async (templatesDir, targetDir, config) => {
120
120
  const gitlabTemplate = await fs.readFile(path.join(templatesDir, 'common', '.gitlab-ci.yml.ejs'), 'utf-8');
121
121
  const gitlabContent = ejs.render(gitlabTemplate, { ...config });
122
122
  await fs.writeFile(path.join(targetDir, '.gitlab-ci.yml'), gitlabContent);
123
+ } else if (ciProvider === 'Bitbucket Pipelines') {
124
+ const bitbucketTemplate = await fs.readFile(path.join(templatesDir, 'common', 'bitbucket-pipelines.yml.ejs'), 'utf-8');
125
+ const bitbucketContent = ejs.render(bitbucketTemplate, { ...config });
126
+ await fs.writeFile(path.join(targetDir, 'bitbucket-pipelines.yml'), bitbucketContent);
127
+ } else if (ciProvider === 'CircleCI') {
128
+ const circleCiDir = path.join(targetDir, '.circleci');
129
+ await fs.ensureDir(circleCiDir);
130
+ const circleCiTemplate = await fs.readFile(path.join(templatesDir, 'common', '_circleci/config.yml.ejs'), 'utf-8');
131
+ const circleCiContent = ejs.render(circleCiTemplate, { ...config });
132
+ await fs.writeFile(path.join(circleCiDir, 'config.yml'), circleCiContent);
123
133
  }
124
134
  };
125
135
 
package/lib/prompts.js CHANGED
@@ -74,7 +74,7 @@ export const getProjectDetails = async (options = {}) => {
74
74
  type: 'select',
75
75
  name: 'ciProvider',
76
76
  message: 'Select CI/CD Provider:',
77
- choices: ['None', 'GitHub Actions', 'Jenkins', 'GitLab CI'],
77
+ choices: ['None', 'GitHub Actions', 'Jenkins', 'GitLab CI', 'CircleCI', 'Bitbucket Pipelines'],
78
78
  default: 'None',
79
79
  when: !options.ciProvider
80
80
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodejs-quickstart-structure",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "type": "module",
5
5
  "description": "The ultimate nodejs quickstart structure CLI to scaffold Node.js microservices with MVC or Clean Architecture",
6
6
  "main": "bin/index.js",
@@ -1,5 +1,7 @@
1
1
  variables:
2
2
  NODE_ENV: 'test'
3
+ WAIT_ON_HOST: docker
4
+ TEST_URL: http://docker:3001
3
5
 
4
6
  stages:
5
7
  - lint
@@ -30,7 +32,7 @@ run_unit_tests:
30
32
  stage: test
31
33
  image: node:22-slim
32
34
  script:
33
- - npm run test:coverage
35
+ - npm run test:coverage -- --maxWorkers=2
34
36
 
35
37
  run_e2e_tests:
36
38
  stage: test
@@ -3,6 +3,15 @@ pipeline {
3
3
 
4
4
  environment {
5
5
  CI = 'true'
6
+ DOCKER_BUILDKIT = '0'
7
+ PORT = '3001'
8
+ DB_PORT = '3307'
9
+ WAIT_ON_HOST = 'host.docker.internal'
10
+ TEST_URL = 'http://host.docker.internal:3001'
11
+ }
12
+
13
+ tools {
14
+ nodejs 'nodejs'
6
15
  }
7
16
 
8
17
  stages {
@@ -21,7 +30,7 @@ pipeline {
21
30
 
22
31
  stage('Unit Test') {
23
32
  steps {
24
- sh 'npm run test:coverage'
33
+ sh 'npm run test:coverage -- --maxWorkers=2'
25
34
  }
26
35
  }
27
36
 
@@ -31,7 +31,7 @@ This project follows a strict **7-Step Production-Ready Process** to ensure qual
31
31
  - **Database**: <%= database %> <% if (database !== 'None') { %>(via <%= database === 'MongoDB' ? 'Mongoose' : 'Sequelize' %>)<% } %>.
32
32
  - **Security**: Helmet, CORS, Rate Limiting, HPP, Snyk SCA.
33
33
  - **Quality**: 80%+ Test Coverage, Eslint, Prettier, Husky.
34
- - **DevOps**: Multi-stage Docker, CI/CD ready (GitHub/GitLab/Jenkins).
34
+ - **DevOps**: Multi-stage Docker, CI/CD ready (GitHub/GitLab/Jenkins/Bitbucket/CircleCI).
35
35
  <% if (includeSecurity) { %>- **Enterprise Hardening**: SonarCloud SAST, Security Policies.<% } %>
36
36
 
37
37
  ## ๐Ÿ“‚ Project Structure
@@ -0,0 +1,96 @@
1
+ version: 2.1
2
+
3
+ orbs:
4
+ node: circleci/node@5.2.0
5
+ <% if (includeSecurity) { %>
6
+ snyk: snyk/snyk@2.1.0
7
+ <% } %>
8
+
9
+ executors:
10
+ node-executor:
11
+ docker:
12
+ - image: cimg/node:22.0
13
+ machine-executor:
14
+ machine:
15
+ image: ubuntu-2204:current
16
+
17
+ jobs:
18
+ lint:
19
+ executor: node-executor
20
+ steps:
21
+ - checkout
22
+ - node/install-packages
23
+ - run: npm run lint
24
+
25
+ unit_test:
26
+ executor: node-executor
27
+ steps:
28
+ - checkout
29
+ - node/install-packages
30
+ - run:
31
+ name: Run Unit Tests with Coverage
32
+ command: npm run test:coverage -- --maxWorkers=2
33
+
34
+ e2e_test:
35
+ executor: machine-executor
36
+ steps:
37
+ - checkout
38
+ - node/install:
39
+ node-version: '22.0'
40
+ - run: npm ci
41
+ - run: npm run test:e2e
42
+
43
+ <% if (includeSecurity) { %>
44
+ security_scan:
45
+ executor: node-executor
46
+ steps:
47
+ - checkout
48
+ - node/install-packages
49
+ - snyk/scan:
50
+ fail-on-issues: true
51
+ severity-threshold: high
52
+
53
+ sonarqube_analysis:
54
+ executor: node-executor
55
+ steps:
56
+ - checkout
57
+ - node/install-packages
58
+ - run:
59
+ name: SonarQube Analysis
60
+ command: |
61
+ # Assuming sonar-scanner is available or run via npx
62
+ npx sonar-scanner
63
+ <% } %>
64
+
65
+ build:
66
+ executor: node-executor
67
+ steps:
68
+ - checkout
69
+ - node/install-packages
70
+ - run: npm run build --if-present
71
+
72
+ workflows:
73
+ build_and_test:
74
+ jobs:
75
+ - lint
76
+ - unit_test:
77
+ requires:
78
+ - lint
79
+ - e2e_test:
80
+ requires:
81
+ - unit_test
82
+ <% if (includeSecurity) { %>
83
+ - security_scan:
84
+ requires:
85
+ - unit_test
86
+ - sonarqube_analysis:
87
+ requires:
88
+ - unit_test
89
+ <% } %>
90
+ - build:
91
+ requires:
92
+ - e2e_test
93
+ <% if (includeSecurity) { %>
94
+ - security_scan
95
+ - sonarqube_analysis
96
+ <% } %>
@@ -30,7 +30,7 @@ jobs:
30
30
  run: npm run lint
31
31
 
32
32
  - name: Run Unit Tests
33
- run: npm run test:coverage
33
+ run: npm run test:coverage -- --maxWorkers=2
34
34
 
35
35
  - name: Run E2E Tests
36
36
  run: npm run test:e2e
@@ -0,0 +1,60 @@
1
+ image: node:22-slim
2
+
3
+ pipelines:
4
+ default:
5
+ - step:
6
+ name: Install Dependencies
7
+ caches:
8
+ - node
9
+ script:
10
+ - npm ci
11
+ - parallel:
12
+ - step:
13
+ name: Lint Code
14
+ script:
15
+ - npm ci
16
+ - npm run lint
17
+ - step:
18
+ name: Run Unit Tests
19
+ script:
20
+ - npm ci
21
+ - npm run test:coverage -- --maxWorkers=2
22
+ - step:
23
+ name: Run E2E Tests
24
+ image: docker:20.10.16
25
+ services:
26
+ - docker
27
+ script:
28
+ - apk add --no-cache nodejs npm docker-compose
29
+ - npm ci
30
+ - export DOCKER_BUILDKIT=0
31
+ - npm run test:e2e
32
+ <% if (includeSecurity) { %>
33
+ - parallel:
34
+ - step:
35
+ name: Snyk Security Scan
36
+ script:
37
+ - pipe: snyk/snyk-scan:1.0.0
38
+ variables:
39
+ SNYK_TOKEN: $SNYK_TOKEN
40
+ LANGUAGE: "npm"
41
+ SEVERITY_THRESHOLD: "high"
42
+ - step:
43
+ name: SonarQube Analysis
44
+ script:
45
+ - pipe: sonarsource/sonarcloud-scan:2.0.0
46
+ variables:
47
+ SONAR_TOKEN: $SONAR_TOKEN
48
+ <% } %>
49
+ - step:
50
+ name: Build Application
51
+ script:
52
+ - npm ci
53
+ - npm run build --if-present
54
+
55
+ definitions:
56
+ services:
57
+ docker:
58
+ memory: 2048
59
+ caches:
60
+ node: ~/.npm
@@ -1,4 +1,3 @@
1
- import { User } from '@/domain/user';
2
1
  import { UserRepository } from '@/infrastructure/repositories/UserRepository';
3
2
  <%_ if (caching === 'Redis') { -%>
4
3
  import cacheService from '@/infrastructure/caching/redisClient';
@@ -122,10 +122,12 @@ services:
122
122
  FLYWAY_URL: jdbc:mysql://db:3306/<%= dbName %>
123
123
  FLYWAY_USER: root
124
124
  FLYWAY_PASSWORD: root
125
+ FLYWAY_BASELINE_ON_MIGRATE: "true"
125
126
  <%_ } -%><%_ if (database === 'PostgreSQL') { -%>
126
127
  FLYWAY_URL: jdbc:postgresql://db:5432/<%= dbName %>
127
128
  FLYWAY_USER: postgres
128
129
  FLYWAY_PASSWORD: root
130
+ FLYWAY_BASELINE_ON_MIGRATE: "true"
129
131
  <%_ } -%>
130
132
  depends_on:
131
133
  - db
@@ -28,7 +28,8 @@
28
28
  "micromatch": "^4.0.8",
29
29
  "braces": "^3.0.3",
30
30
  "picomatch": "^4.0.4",
31
- "lodash": "^4.17.23"
31
+ "lodash": "^4.17.23",
32
+ "debounce": "^1.2.1"
32
33
  },
33
34
  "dependencies": {
34
35
  "express": "^4.18.2",
@@ -3,13 +3,21 @@ const { execSync } = require('child_process');
3
3
  const path = require('path');
4
4
 
5
5
  // Set a specific port for E2E tests to avoid collisions with local development
6
- process.env.PORT = '3001';
7
- const TEST_PORT = process.env.PORT;
6
+ const TEST_PORT = <% if (database === 'MySQL') { %>process.env.PORT || '3001'<% } else { %>process.env.PORT || '3001'<% } %>;
7
+ const WAIT_ON_HOST = process.env.WAIT_ON_HOST || '127.0.0.1';
8
8
 
9
9
  const execute = (command) => {
10
- console.log(`\n> ${command}`);
11
- // Run commands from the project root instead of the scripts folder
12
- execSync(command, { stdio: 'inherit', cwd: path.resolve(__dirname, '../') });
10
+ console.log(`\n> ${command}`);
11
+ // Run commands from the project root instead of the scripts folder
12
+ execSync(command, {
13
+ stdio: 'inherit',
14
+ cwd: path.resolve(__dirname, '../'),
15
+ env: {
16
+ ...process.env,
17
+ PORT: TEST_PORT,
18
+ DB_PORT: process.env.DB_PORT || '3306'
19
+ }
20
+ });
13
21
  };
14
22
 
15
23
  let composeCmd = 'docker-compose';
@@ -26,7 +34,7 @@ try {
26
34
  let isAlreadyUp = false;
27
35
  try {
28
36
  // Silently check if the endpoint is already live (1.5-second timeout)
29
- execSync(`npx wait-on http-get://127.0.0.1:${TEST_PORT}/health -t 1500`, {
37
+ execSync(`npx wait-on http-get://${WAIT_ON_HOST}:${TEST_PORT}/health -t 1500`, {
30
38
  stdio: 'ignore',
31
39
  cwd: path.resolve(__dirname, '../')
32
40
  });
@@ -42,10 +50,18 @@ try {
42
50
  execute(`${composeCmd} up -d --build`);
43
51
  currentProcessStartedDocker = true;
44
52
 
45
- console.log('Waiting for application healthcheck to turn green (120s timeout)...');
46
- // Using wait-on to poll the universal /health endpoint injected into all architectures
47
- execute(`npx wait-on http-get://127.0.0.1:${TEST_PORT}/health -t 120000`);
48
- console.log('Infrastructure is healthy!');
53
+ console.log(`Waiting for application healthcheck to turn green (420s timeout)...`);
54
+ try {
55
+ // Using WAIT_ON_HOST to allow containerized CI to hit host ports (e.g. host.docker.internal)
56
+ execute(`npx wait-on http-get://${WAIT_ON_HOST}:${TEST_PORT}/health -t 420000`);
57
+ console.log('Infrastructure is healthy!');
58
+ } catch (e) {
59
+ console.error('\nโŒ Healthcheck timed out! Printing infrastructure logs for debugging:');
60
+ console.error('------------------------------------------------------------');
61
+ execute(`${composeCmd} logs --tail=100`);
62
+ console.error('------------------------------------------------------------');
63
+ throw e;
64
+ }
49
65
  }
50
66
 
51
67
  console.log('Running E2E tests...');