View on GitHub

incap

Test Project: MEAN stack with Typescript

CI/CD and Code Analysis Strategy

Overview

INCAP implements a comprehensive DevOps strategy with multiple quality gates, automated testing, security scanning, and continuous deployment. The pipeline ensures code quality, security compliance, and reliable delivery.

CI/CD Pipeline Architecture

┌─────────────────────────────────────────────────────────────────┐
│                    Git Workflow                                  │
│  1. Developer commits to feature branch                          │
│  2. Push to GitHub                                              │
│  3. Create Pull Request to master                               │
└────────────────────────────┬────────────────────────────────────┘
                             ↓
┌─────────────────────────────────────────────────────────────────┐
│              AppVeyor CI/CD Pipeline (Triggered)                │
└────────────────────────────┬────────────────────────────────────┘
                             ↓
        ┌────────────────────┼────────────────────┐
        ↓                    ↓                    ↓
    ┌─────────┐         ┌─────────┐         ┌──────────┐
    │  Build  │         │  Test   │         │ Analysis │
    │  Phase  │         │  Phase  │         │  Phase   │
    └────┬────┘         └────┬────┘         └────┬─────┘
         ↓                   ↓                   ↓
    ┌─────────────────────────────────────────────────┐
    │  Post-Build Actions                             │
    │  - Upload test results                          │
    │  - Upload coverage reports                      │
    │  - Run SonarQube analysis                       │
    │  - Run security scanning                        │
    └────────────────────┬────────────────────────────┘
                         ↓
        ┌────────────────────────────────────┐
        │  All Quality Gates Pass?            │
        └────┬──────────────────────────┬────┘
             │                          │
            Yes                        No
             │                          │
             ↓                          ↓
    ┌─────────────────┐        ┌──────────────────┐
    │ Approve PR      │        │ Reject PR        │
    │ for Merge       │        │ with feedback    │
    └────────┬────────┘        └──────────────────┘
             │
             ↓
    ┌──────────────────────────────┐
    │  Merge to Master             │
    │  Triggers Deployment         │
    └──────────────────────────────┘

AppVeyor Configuration

Build Environment

File: appveyor.yml

Infrastructure:

version: 1.0.{build}
image: Visual Studio 2022
skip_branch_with_pr: true

Node.js Setup

install:
  - ps: Update-NodeJsInstallation 24.13.0 x64
  - npm install sonar-scanner -g
  - npm install -g snyk
  - npm install -g @angular/cli
  - curl -o codecov.exe https://uploader.codecov.io/latest/windows/codecov.exe

Installed Tools:

Caching Strategy

cache:
  - C:\Users\appveyor\AppData\Roaming\npm\node_modules -> package.json
  - C:\Users\appveyor\AppData\Roaming\npm-cache -> package.json
  - frontend\node_modules -> package.json

Benefits:

Build Script

build_script:
  - ps: .\rebuild.ps1

rebuild.ps1 Workflow:

# Parallel execution
$build_front = Start-Job -ScriptBlock { .\rebuild.cmd frontend } -Name "Build.frontend"
$build_back = Start-Job -ScriptBlock { .\rebuild.cmd backend } -Name "Build.backend"

# Wait for both to complete
Wait-Job -Id @($build_front.Id, $build_back.Id) -Timeout 6000

What rebuild.cmd does (inferred):

Testing Pipeline

Vitest Framework

Features:

Frontend Testing

// vitest.config.ts
export default defineConfig({
  test: {
    environment: 'jsdom',           // Browser environment
    include: ['**/*.spec.ts'],      // All test files
    globals: true,                  // Global test APIs
    coverage: {
      provider: 'v8',               // V8 coverage
      reporter: ['text', 'lcov'],   // Output formats
      reportsDirectory: 'coverage'   // Output directory
    },
    reporters: ['default', 'junit'], // Console + XML output
    outputFile: {
      junit: 'tests-results/tests-results.xml'
    }
  }
});

Backend Testing

// vitest.config.ts
export default defineConfig({
  test: {
    environment: 'node',            // Node.js environment
    include: ['**/*.spec.ts'],
    globals: true,
    setupFiles: ['./vitest.setup.ts'],
    coverage: {
      provider: 'v8',
      reporter: ['text', 'lcov'],
      all: true,                    // All files in coverage
      exclude: ['node_modules', 'dist', ...]
    },
    reporters: [
      'default',
      ['junit', { outputFile: 'tests-results/tests-results.xml' }]
    ]
  }
});

Test Execution in CI

after_build:
  # Upload JUnit XML test results
  - curl -F "file=@backend\\tests-results\\tests-results.xml" 
          "https://ci.appveyor.com/api/testresults/junit/%APPVEYOR_JOB_ID%"
  - curl -F "file=@frontend\\tests-results\\tests-results.xml" 
          "https://ci.appveyor.com/api/testresults/junit/%APPVEYOR_JOB_ID%"

Coverage Upload

npm run coverage    # Generates coverage reports
codecov.exe        # Uploads to Coveralls

Code Quality Analysis

SonarCloud Integration

Configuration (sonar-project.properties):

sonar.host.url=https://sonarcloud.io
sonar.organization=tuanicom-github
sonar.projectKey=tuanicom_incap
sonar.projectName=incap
sonar.projectVersion=1.0

sonar.sources=frontend/src/app,backend
sonar.tests=frontend/src/app,backend
sonar.test.inclusions=**/*.spec.ts

sonar.javascript.lcov.reportPaths=frontend/coverage/lcov.info,backend/coverage/lcov.info
sonar.eslint.reportPaths=frontend/eslint.json,backend/eslint.json

sonar.sourceEncoding=UTF-8

Project Configuration:

SonarCloud Analysis in CI

after_build:
  - set JAVA_HOME=C:\Program Files\Java\jdk19
  - set PATH=%JAVA_HOME%\bin;%PATH%
  
  # Handle pulls vs. branches differently
  - if defined APPVEYOR_PULL_REQUEST_NUMBER (
      set "SONAR_ARGS=-Dsonar.pullrequest.base=%APPVEYOR_REPO_BRANCH% 
                      -Dsonar.pullrequest.branch=%APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH% 
                      -Dsonar.pullrequest.key=%APPVEYOR_PULL_REQUEST_NUMBER%"
    ) else (
      set "SONAR_ARGS=-Dsonar.branch.name=%APPVEYOR_REPO_BRANCH%"
    )
  
  - call sonar-scanner %SONAR_ARGS%

SonarCloud Metrics:

SonarCloud Dashboard

Visibility:

Security Scanning

Snyk Integration

Purpose: Identify vulnerable dependencies

Configuration (in package.json):

"snyk": true,
"scripts": {
  "snyk": "snyk auth & snyk wizard",
  "snyk-test": "snyk test",
  "snyk-protect": "snyk-protect",
  "prepare": "npm run snyk-protect"
}

CI Execution:

Snyk Dashboard

Coverage:

Code Linting

ESLint Configuration

Frontend (angular-eslint):

// eslint.config.mjs
{
  rules: {
    '@angular-eslint/directive-selector': ['error', { type: 'attribute' }],
    '@angular-eslint/component-selector': ['error', { type: 'element' }],
    'import/no-unresolved': 'error',
    '@typescript-eslint/strict-null-checks': 'warn'
  }
}

Backend (typescript-eslint):

// eslint.config.mjs
{
  rules: {
    '@typescript-eslint/no-unused-vars': 'warn',
    'no-console': 'warn',
    'import/order': 'warn'
  }
}

Output Format: JSON for CI integration

after_build:
  - curl -F "file=@frontend/eslint.json" 
          "https://ci.appveyor.com/api/artifacts"
  - curl -F "file=@backend/eslint.json" 
          "https://ci.appveyor.com/api/artifacts"

Coverage Tracking

Coveralls.io Integration

Process:

1. Generate coverage reports (vitest)
   └─ LCOV format (industry standard)
2. Upload to Coveralls
   └─ codecov.exe (for Windows builds)
3. Track coverage trends
   └─ Badge in README

Coverage Report Locations:

SonarCloud Integration:

sonar.javascript.lcov.reportPaths=frontend/coverage/lcov.info,backend/coverage/lcov.info

Codacy Integration

Purpose: Additional code review automation

Metrics:


Pull Request Workflow

PR Creation

Developer creates PR to master
        ↓
GitHub triggers AppVeyor build
        ↓
AppVeyor runs complete pipeline
        ↓
Results posted as PR comments

Quality Gates for Merge

Before merging to master, ensure:

Branch Protection Rules

Recommended rules for master branch:

Artifact Storage

Uploaded Artifacts:

artifacts:
  - Frontend Coverage: frontend/coverage/index.html
  - Backend Coverage: backend/coverage/lcov-report/index.html
  - Frontend Linting: frontend/eslint.json
  - Backend Linting: backend/eslint.json

Available for:

Environment Variables for CI

Required for successful builds:

Monitoring & Notifications

Build Status Badge

[![Build status](https://ci.appveyor.com/api/projects/status/x9dtpjle2v6afiwf?svg=true)](https://ci.appveyor.com/project/tuanicom/incap)

Quality Badges

Notifications

Configured via:


Local Development CI Simulation

Run Tests Locally

# Backend
cd backend
npm install
npm run lint
npm run test
npm run coverage

# Frontend
cd frontend
npm install
npm run lint
npm run test:unit
npm run coverage

Pre-commit Hook Recommendation

# In .git/hooks/pre-commit
#!/bin/bash
npm run lint || exit 1
npm run test || exit 1

For deployment information, see Deployment Guide.