All files / src index.js

0% Statements 0/119
0% Branches 0/1
0% Functions 0/1
0% Lines 0/119

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 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120                                                                                                                                                                                                                                               
//@ts-check
import { concat, filter, forEach, get, map } from 'lodash-es';
import { Command, InvalidOptionArgumentError } from 'commander';
import process from 'node:process';
import path from 'node:path';
import Env from './env.js';
import { isIgnored } from  '../src/utils.js';

/**
 * @typedef {import('@gitbeaker/core').GroupSchema} GroupSchema
 */

const cmd = new Command();

/**
 * @param  {any} val
 * @param  {any[]} memo
 */
function collect(val, memo) {
  memo.push(val);
  return memo;
}

/**
 * @param  {string} val
 * @param  {any} memo
 */
function jsonCollect(val, memo) {
  try {
    memo.push(JSON.parse(val));
    return memo;
  }
  catch (e) {
    throw new InvalidOptionArgumentError('Failed to parse JSon argument.');
  }
}

cmd
.option('-u, --url <GitLab url>', 'GitLab url', 'https://gitlab.cern.ch')
.option('-p, --path <path>', 'Projects path in GitLab', collect, [ ])
.option('--plugin <plugin>', 'Filter plugins to execute', collect, [ ])
.option('--no-recurse', 'Do not recurse paths')
.option('-t, --token', 'Access token (or use ACCESS_TOKEN in env)')
.option('-d, --debug', 'Enable debug')
.option('-c, --config <file>', 'Configuration file', path.join(process.cwd(), 'config'))
.option('--dry-run', 'Do not make any modifications')
.option('--exclude-all', 'Exclude all projects by default', false)
.option('--exclude <rules>', 'Exclude rule (json)', jsonCollect, [])
.option('--include <rules>', 'Include rule (json)', jsonCollect, [])
.option('--dump-projects', 'dump project configuration (and do nothing else)', false);

cmd.parse(process.argv);
const opts = /** @type {GitConfig.EnvOpts} */ (cmd.opts());

const env = new Env();

Promise.resolve()
// eslint-disable-next-line complexity
.then(async () => {
  await env.load(opts.config, opts);

  const paths = env.config.path;

  /** @type {GitConfig.$ProjectSchema[]} */
  let projects = [];
  if (env.opts.recurse) {
    for (let i = 0; i < paths.length; ++i) {
      const path = paths[i];
      env.spin.start('Listing groups in ' + path);
      const subgroups = /** @type {GroupSchema[]} */ (await env.gitlab.Groups.allSubgroups(path));
      forEach(subgroups, (desc) => paths.push(get(desc, [ 'full_path' ]))); // jshint ignore:line

      env.spin.start('Listing projects in ' + path);
      const newProjects = /** @type {GitConfig.$ProjectSchema[]} */(
        /** @type {unknown} */ (await env.gitlab.Groups.allProjects(path)));
      projects = concat(projects, filter(newProjects,
        (p) => !isIgnored(env, p, opts, 'global config'))); // jshint ignore:line
    }
  }
  env.spin.debug('Projects:', map(projects, 'name'));

  for (const project of projects) {
    if (opts.dumpProjects) {
      env.spin.info(JSON.stringify(project, undefined, 2));
    }
    else {
      for (const settings of env.config.settings) {
        const plugin = env.plugins[settings?.plugin];
        if (!plugin) {
          throw new Error(`unknown plugin: ${settings?.plugin}`);
        }
        else if ((env.opts.plugin?.length ?? 0) !== 0 &&
                 !env.opts.plugin.includes(settings?.plugin)) {
          /* plugin filter from cmdline */
          continue;
        }
        await plugin(env, project, settings, get(settings, 'service'));
      }
    }
  }
})
.then(
  () => env.spin.succeed('done'),
  (err) => {
    env.spin.fail("Error: " + err);
    if (err?.cause?.request) {
      /** @type {Request} */
      const request = err.cause.request;
      env.spin.fail("  Request: %s %s",
        request.method?.toString?.() ?? "?",
        request.url?.toString?.() ?? "?");
    }
    env.spin.debug(err?.stack);
  }
)
.finally(() => {
  // waiting for this merge: https://github.com/sindresorhus/ky/pull/145
  process.exit(0); // eslint-disable-line
});