# All files / lib/analyzers devops-analyzer.js

100% Statements 37/37
95% Branches 19/20
100% Functions 1/1
100% Lines 37/37

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75

    7x

    7x
    7x
    1x
    1x
    1x

    7x
    7x
    1x
    1x

    7x
    7x
    7x
    1x
    1x

    7x
    7x
    1x
    1x

    7x
    7x
    1x
    1x

    7x
    1x
    1x

    7x
    7x
    1x
    1x
    1x
    1x

    7x
    7x
    7x
    7x

    7x

     import fs from 'fs-extra';
    import path from 'path';
    import { recursiveGlob } from './utils.js';

    export async function analyzeDevOps(projectPath) {
      const detected = {
        ciSystems: [],
        tools: [],
        buildTools: [],
        configFiles: []
      };

      // GitHub Actions
      const ghaDir = path.join(projectPath, '.github', 'workflows');
      if (await fs.pathExists(ghaDir)) {
        detected.ciSystems.push('github-actions');
        detected.tools.push('github-actions');
        detected.configFiles.push('.github/workflows/');
      }

      // GitLab CI
      const gitlabCiPath = path.join(projectPath, '.gitlab-ci.yml');
      if (await fs.pathExists(gitlabCiPath)) {
        detected.ciSystems.push('gitlab-ci');
        detected.configFiles.push('.gitlab-ci.yml');
      }

      // CircleCI
      const circleDir = path.join(projectPath, '.circleci');
      const circleConfig = path.join(circleDir, 'config.yml');
      if (await fs.pathExists(circleDir) && await fs.pathExists(circleConfig)) {
        detected.ciSystems.push('circleci');
        detected.configFiles.push('.circleci/config.yml');
      }

      // Jenkins
      const jenkinsfile = path.join(projectPath, 'Jenkinsfile');
      if (await fs.pathExists(jenkinsfile)) {
        detected.ciSystems.push('jenkins');
        detected.configFiles.push('Jenkinsfile');
      }

      // Terraform (re-use pattern from cloud analyzer but we track here as tool)
      const tfFiles = await recursiveGlob(projectPath, '**/*.tf');
      if (tfFiles.length > 0) {
        detected.tools.push('terraform');
        detected.configFiles.push(...tfFiles.slice(0, 3));
      }

      // Makefile
      if (await fs.pathExists(path.join(projectPath, 'Makefile'))) {
        detected.buildTools.push('make');
        detected.configFiles.push('Makefile');
      }

      // NPM/Yarn/PNPM scripts from package.json
      const pkgPath = path.join(projectPath, 'package.json');
      if (await fs.pathExists(pkgPath)) {
        try {
          const pkg = await fs.readJson(pkgPath);
          Eif (pkg.scripts && Object.keys(pkg.scripts).length > 0) {
            detected.buildTools.push('npm-scripts');
          }
        } catch (e) {}
      }

      // Deduplicate
      detected.ciSystems = [...new Set(detected.ciSystems)];
      detected.tools = [...new Set(detected.tools)];
      detected.buildTools = [...new Set(detected.buildTools)];
      detected.configFiles = [...new Set(detected.configFiles)];

      return detected;
    }