Initial commit
This commit is contained in:
334
assets/templates/gitlab-ci/node-ci.yml
Normal file
334
assets/templates/gitlab-ci/node-ci.yml
Normal file
@@ -0,0 +1,334 @@
|
||||
# GitLab CI/CD Pipeline for Node.js
|
||||
# Optimized with caching, parallel execution, and deployment
|
||||
|
||||
stages:
|
||||
- security
|
||||
- validate
|
||||
- test
|
||||
- build
|
||||
- deploy
|
||||
|
||||
# Global variables
|
||||
variables:
|
||||
NODE_VERSION: "20"
|
||||
npm_config_cache: "$CI_PROJECT_DIR/.npm"
|
||||
CYPRESS_CACHE_FOLDER: "$CI_PROJECT_DIR/.cache/Cypress"
|
||||
|
||||
# Global cache configuration
|
||||
cache:
|
||||
key:
|
||||
files:
|
||||
- package-lock.json
|
||||
paths:
|
||||
- node_modules/
|
||||
- .npm/
|
||||
- .cache/Cypress/
|
||||
policy: pull
|
||||
|
||||
# Reusable configuration
|
||||
.node_template:
|
||||
image: node:${NODE_VERSION}
|
||||
before_script:
|
||||
- node --version
|
||||
- npm --version
|
||||
- npm ci
|
||||
|
||||
# Validation stage
|
||||
lint:
|
||||
extends: .node_template
|
||||
stage: validate
|
||||
cache:
|
||||
key:
|
||||
files:
|
||||
- package-lock.json
|
||||
paths:
|
||||
- node_modules/
|
||||
- .npm/
|
||||
policy: pull-push
|
||||
script:
|
||||
- npm run lint
|
||||
- npm run format:check
|
||||
only:
|
||||
- merge_requests
|
||||
- main
|
||||
- develop
|
||||
|
||||
# Test stage
|
||||
unit-test:
|
||||
extends: .node_template
|
||||
stage: test
|
||||
parallel:
|
||||
matrix:
|
||||
- NODE_VERSION: ["18", "20", "22"]
|
||||
script:
|
||||
- npm run test:unit -- --coverage
|
||||
coverage: '/All files[^|]*\|[^|]*\s+([\d\.]+)/'
|
||||
artifacts:
|
||||
reports:
|
||||
coverage_report:
|
||||
coverage_format: cobertura
|
||||
path: coverage/cobertura-coverage.xml
|
||||
paths:
|
||||
- coverage/
|
||||
expire_in: 30 days
|
||||
|
||||
integration-test:
|
||||
extends: .node_template
|
||||
stage: test
|
||||
services:
|
||||
- postgres:15
|
||||
- redis:7-alpine
|
||||
variables:
|
||||
POSTGRES_DB: testdb
|
||||
POSTGRES_USER: testuser
|
||||
POSTGRES_PASSWORD: testpass
|
||||
DATABASE_URL: "postgresql://testuser:testpass@postgres:5432/testdb"
|
||||
REDIS_URL: "redis://redis:6379"
|
||||
script:
|
||||
- npm run test:integration
|
||||
artifacts:
|
||||
when: always
|
||||
reports:
|
||||
junit: test-results/junit.xml
|
||||
paths:
|
||||
- test-results/
|
||||
expire_in: 7 days
|
||||
|
||||
# Build stage
|
||||
build:
|
||||
extends: .node_template
|
||||
stage: build
|
||||
cache:
|
||||
key:
|
||||
files:
|
||||
- package-lock.json
|
||||
paths:
|
||||
- node_modules/
|
||||
- .npm/
|
||||
policy: pull
|
||||
script:
|
||||
- npm run build
|
||||
- echo "BUILD_VERSION=$(node -p "require('./package.json').version")" >> build.env
|
||||
artifacts:
|
||||
paths:
|
||||
- dist/
|
||||
reports:
|
||||
dotenv: build.env
|
||||
expire_in: 7 days
|
||||
only:
|
||||
- main
|
||||
- develop
|
||||
- tags
|
||||
|
||||
# Security: Secret Scanning
|
||||
secret-scan:trufflehog:
|
||||
stage: security
|
||||
image: trufflesecurity/trufflehog:latest
|
||||
script:
|
||||
- trufflehog filesystem . --json --fail > trufflehog-report.json || true
|
||||
- |
|
||||
if [ -s trufflehog-report.json ]; then
|
||||
echo "❌ Secrets detected!"
|
||||
cat trufflehog-report.json
|
||||
exit 1
|
||||
fi
|
||||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
- trufflehog-report.json
|
||||
expire_in: 30 days
|
||||
allow_failure: false
|
||||
only:
|
||||
- merge_requests
|
||||
- main
|
||||
- develop
|
||||
|
||||
secret-scan:gitleaks:
|
||||
stage: security
|
||||
image: zricethezav/gitleaks:latest
|
||||
script:
|
||||
- gitleaks detect --source . --report-format json --report-path gitleaks-report.json
|
||||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
- gitleaks-report.json
|
||||
expire_in: 30 days
|
||||
allow_failure: true
|
||||
only:
|
||||
- merge_requests
|
||||
- main
|
||||
- develop
|
||||
|
||||
# Security: SAST
|
||||
sast:semgrep:
|
||||
stage: security
|
||||
image: returntocorp/semgrep
|
||||
script:
|
||||
- semgrep scan --config=auto --sarif --output=semgrep.sarif .
|
||||
- semgrep scan --config=p/owasp-top-ten --json --output=semgrep-owasp.json .
|
||||
artifacts:
|
||||
reports:
|
||||
sast: semgrep.sarif
|
||||
paths:
|
||||
- semgrep.sarif
|
||||
- semgrep-owasp.json
|
||||
expire_in: 30 days
|
||||
allow_failure: false
|
||||
only:
|
||||
- merge_requests
|
||||
- main
|
||||
- develop
|
||||
|
||||
sast:nodejs:
|
||||
stage: security
|
||||
image: node:20-alpine
|
||||
script:
|
||||
- npm install -g eslint eslint-plugin-security
|
||||
- eslint . --plugin=security --format=json --output-file=eslint-security.json || true
|
||||
artifacts:
|
||||
paths:
|
||||
- eslint-security.json
|
||||
expire_in: 30 days
|
||||
only:
|
||||
exists:
|
||||
- package.json
|
||||
allow_failure: true
|
||||
|
||||
# Security: Dependency Scanning
|
||||
dependency-scan:npm:
|
||||
extends: .node_template
|
||||
stage: security
|
||||
cache:
|
||||
key:
|
||||
files:
|
||||
- package-lock.json
|
||||
paths:
|
||||
- node_modules/
|
||||
- .npm/
|
||||
policy: pull-push
|
||||
script:
|
||||
- npm audit --audit-level=moderate --json > npm-audit.json || true
|
||||
- npm audit --audit-level=high # Fail on high severity
|
||||
artifacts:
|
||||
paths:
|
||||
- npm-audit.json
|
||||
expire_in: 30 days
|
||||
allow_failure: false
|
||||
only:
|
||||
- merge_requests
|
||||
- main
|
||||
- develop
|
||||
|
||||
# GitLab built-in security templates
|
||||
include:
|
||||
- template: Security/SAST.gitlab-ci.yml
|
||||
- template: Security/Dependency-Scanning.gitlab-ci.yml
|
||||
|
||||
# E2E tests (only on main)
|
||||
e2e-test:
|
||||
extends: .node_template
|
||||
stage: test
|
||||
needs: [build]
|
||||
dependencies:
|
||||
- build
|
||||
script:
|
||||
- npm run test:e2e
|
||||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
- cypress/videos/
|
||||
- cypress/screenshots/
|
||||
expire_in: 7 days
|
||||
only:
|
||||
- main
|
||||
|
||||
# Deploy to staging
|
||||
deploy:staging:
|
||||
stage: deploy
|
||||
image: node:${NODE_VERSION}
|
||||
needs: [build]
|
||||
dependencies:
|
||||
- build
|
||||
environment:
|
||||
name: staging
|
||||
url: https://staging.example.com
|
||||
on_stop: stop:staging
|
||||
script:
|
||||
- echo "Deploying to staging..."
|
||||
- npm install -g aws-cli
|
||||
- aws s3 sync dist/ s3://${STAGING_BUCKET}
|
||||
- aws cloudfront create-invalidation --distribution-id ${STAGING_CF_DIST} --paths "/*"
|
||||
only:
|
||||
- develop
|
||||
when: manual
|
||||
|
||||
stop:staging:
|
||||
stage: deploy
|
||||
image: node:${NODE_VERSION}
|
||||
environment:
|
||||
name: staging
|
||||
action: stop
|
||||
script:
|
||||
- echo "Stopping staging environment..."
|
||||
when: manual
|
||||
only:
|
||||
- develop
|
||||
|
||||
# Deploy to production
|
||||
deploy:production:
|
||||
stage: deploy
|
||||
image: node:${NODE_VERSION}
|
||||
needs: [build, e2e-test]
|
||||
dependencies:
|
||||
- build
|
||||
environment:
|
||||
name: production
|
||||
url: https://example.com
|
||||
before_script:
|
||||
- echo "Deploying version ${BUILD_VERSION} to production"
|
||||
script:
|
||||
- npm install -g aws-cli
|
||||
- aws s3 sync dist/ s3://${PRODUCTION_BUCKET}
|
||||
- aws cloudfront create-invalidation --distribution-id ${PRODUCTION_CF_DIST} --paths "/*"
|
||||
# Health check
|
||||
- sleep 10
|
||||
- curl -f https://example.com/health || exit 1
|
||||
after_script:
|
||||
- echo "Deployed successfully"
|
||||
only:
|
||||
- main
|
||||
when: manual
|
||||
|
||||
# Create release
|
||||
release:
|
||||
stage: deploy
|
||||
image: registry.gitlab.com/gitlab-org/release-cli:latest
|
||||
needs: [deploy:production]
|
||||
script:
|
||||
- echo "Creating release for version ${BUILD_VERSION}"
|
||||
release:
|
||||
tag_name: 'v${BUILD_VERSION}'
|
||||
description: 'Release v${BUILD_VERSION}'
|
||||
only:
|
||||
- main
|
||||
|
||||
# Workflow rules
|
||||
workflow:
|
||||
rules:
|
||||
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
||||
- if: '$CI_COMMIT_BRANCH == "main"'
|
||||
- if: '$CI_COMMIT_BRANCH == "develop"'
|
||||
- if: '$CI_COMMIT_TAG'
|
||||
|
||||
# Additional optimizations
|
||||
.interruptible_template:
|
||||
interruptible: true
|
||||
|
||||
lint:
|
||||
extends: [.node_template, .interruptible_template]
|
||||
|
||||
unit-test:
|
||||
extends: [.node_template, .interruptible_template]
|
||||
|
||||
integration-test:
|
||||
extends: [.node_template, .interruptible_template]
|
||||
Reference in New Issue
Block a user