All files / plugins members.js

26.04% Statements 25/96
100% Branches 1/1
0% Functions 0/2
26.04% Lines 25/96

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 971x 1x 1x 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 { assign, get, isEmpty, isNil, transform, upperFirst } from 'lodash-es';
import async from 'async';
import * as utils from '../src/utils.js';
import { AccessLevel } from '../src/Consts.js';
 
const service = 'members';
 
/**
 * @param  {GitConfig.Env} env
 * @param  {GitConfig.$ProjectSchema} project
 * @param  {GitConfig.Settings} settings
 */
export async function update(env /*: Env */, project /*: $ProjectDesc */, settings /*: $Settings */) {
  if (utils.isIgnored(env, project, settings, upperFirst(service))) {
    return;
  }

  env.spin.start(`Fetching ${service} config: ${project.name}`);
  var current = /** @type {GitConfig.$MemberSchema[]} */ (
    await env.gitlab.ProjectMembers.all(project.id, { includeInherited: true }));

  const isStrict = get(settings, 'config.strict');
  var perms = transform(AccessLevel, (ret, level, levelName) => {
    transform(get(settings, [ 'config', levelName ]), (ret, user) => {
      ret[user] = level;
    }, ret);
  }, /** @type {{ [user:string]: GitConfig.$AccessLevel }} */ ({}));

  var updated = false;
  await async.eachSeries(current, async function(member) {
    const perm = perms[member.username];
    delete perms[member.username];
    return updatePerm(env, project, member, perm, isStrict)
    .then((up) => (updated = (updated || up)));
  });

  await async.eachOfSeries(perms, async function(perm, username) {
    const ret = /** @type {GitConfig.$UserSchema[]} */ (
      await env.gitlab.Users.all({ username: /** @type {string} */ (username) }));
    if (!ret || isEmpty(ret)) { throw 'user not found: ' + username; }
    const user = assign(ret[0], { access_level: 0 });

    if (await updatePerm(env, project, user, perm, isStrict)) {
      updated = true;
    }
  });
  if (updated) {
    env.spin.succeed(`${upperFirst(service)} updated: ${project.name}`);
  }
}
 
/**
 * @param {GitConfig.Env} env
 * @param {GitConfig.$ProjectSchema} project
 * @param {GitConfig.$MemberSchema} member
 * @param {GitConfig.$AccessLevel|undefined|null} perm
 * @param {boolean} [isStrict]
 */
async function updatePerm(env, project, member, perm, isStrict) {
  var updated = false;

  if (isNil(perm)) {
    if (isStrict) {
      if (env.opts.dryRun) {
        env.spin.warn(`${upperFirst(service)} ${member.username} should be removed from: ${project.name}`);
      }
      else {
        /* ldap users are hard to remove */
        await env.gitlab.ProjectMembers.remove(project.id, member.id)
        .catch(() => env.gitlab.ProjectMembers.edit(project.id, member.id, AccessLevel.guest))
        .catch(() => env.gitlab.ProjectMembers.add(project.id, member.id, AccessLevel.guest));
        updated = true;
      }
    }
  }
  else if (member.access_level === AccessLevel.owner) {
    /* can't modify owner */
  }
  else if (member.access_level !== perm) {
    if (env.opts.dryRun) {
      const type = (perm > member.access_level) ? "promoted" : "demoted";
      env.spin.warn(`${upperFirst(service)} ${member.username} should be ${type} on: ${project.name}`);
    }
    else {
      await env.gitlab.ProjectMembers.edit(project.id, member.id, perm)
      // @ts-ignore
      .catch(() => env.gitlab.ProjectMembers.add(project.id, member.id, perm));
      updated = true;
    }
  }
  return updated;
}
 
export default update;