All files / plugins deploy-keys.js

24.21% Statements 23/95
100% Branches 1/1
0% Functions 0/2
24.21% Lines 23/95

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 961x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x                                                           1x 1x 1x 1x 1x 1x                                                                                       1x 1x  
//@ts-check
import { cloneDeep, filter, forEach, get, isEmpty,
  upperFirst } from 'lodash-es';
import async from 'async';
import path from 'node:path';
import * as utils from '../src/utils.js';
import { fileURLToPath } from 'node:url';
 
const service = path.parse(fileURLToPath(import.meta.url)).name;
 
/**
 * @param  {GitConfig.Env} env
 * @param  {GitConfig.$DeployKeySchema[]} projectKeys
 * @param  {Plugins.DeployKeyConfig[]} confKeys
 */
function diffDeployKeys(env, projectKeys, confKeys) {
  /** @type {{
    new: Plugins.DeployKeyConfig[],
    old: GitConfig.$DeployKeySchema[],
    update: Array<{ ck: Plugins.DeployKeyConfig, pk: GitConfig.$DeployKeySchema }> }} */
  const ret /*: DeployKeysMod */ = { new: [], old: [], update: [] };
  confKeys = cloneDeep(confKeys);

  forEach(projectKeys, (pk) => {
    /** @type {Plugins.DeployKeyConfig|undefined} */
    let ck;
    confKeys = filter(confKeys, (k) => {
      if (k.key === pk.key) {
        ck = k;
        return false;
      }
      return true;
    });
    if (!ck) {
      ret.old.push(pk);
    }
    else if ((ck.title !== pk.title) || (Boolean(ck.can_push) !== pk.can_push)) {
      ret.update.push({ pk, ck });
    }
  });

  ret.new = confKeys;
  return ret;
}
 
/**
 * @param  {GitConfig.Env} env
 * @param  {GitConfig.$ProjectSchema} project
 * @param  {GitConfig.Settings} settings
 */
async function update(env, project, settings) {
  if (utils.isIgnored(env, project, settings, upperFirst(service))) {
    return;
  }

  env.spin.start(`Fetching ${service} configuration: ${project.name}`);
  const projectKeys = /** @type {GitConfig.$DeployKeySchema[]} */
    (await env.gitlab.DeployKeys.all({ projectId: project.id }));
  const mods = diffDeployKeys(env, projectKeys,
    get(settings, [ 'config', 'keys' ], []));

  env.spin.debug(`${upperFirst(service)} modifications: %o`, mods);
  if (env.opts.dryRun) {
    if (!isEmpty(mods.new)) {
      env.spin.warn(`${upperFirst(service)} addition required: ${project.name}`);
    }
    if (!isEmpty(mods.update)) {
      env.spin.warn(`${upperFirst(service)} update required: ${project.name}`);
    }
    if (!isEmpty(mods.old)) {
      env.spin.warn(`${upperFirst(service)} removal required: ${project.name}`);
    }
  }
  else {
    var updated = false;
    await async.eachSeries(mods.old, async function(pk) {
      await env.gitlab.DeployKeys.remove(project.id, pk.id);
      updated = true;
    });
    await async.eachSeries(mods.new, async function(ck) {
      // @ts-ignore correct parameters
      await env.gitlab.DeployKeys.create(project.id, ck.title, ck.key, { can_push: ck.can_push ?? false });
      updated = true;
    });
    await async.eachSeries(mods.update, async function({ ck, pk }) {
      await env.gitlab.DeployKeys.edit(project.id, pk.id, ck);
      updated = true;
    });
    if (updated) {
      env.spin.succeed(`${upperFirst(service)} updated: ${project.name}`);
    }
  }
}
 
export default update;