All files / ee/app/assets/javascripts/approvals mappers.js

73.33% Statements 22/30
54.55% Branches 6/11
62.5% Functions 10/16
73.91% Lines 17/23

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 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143                      21x     4x 2x     2x                                   16x       16x     21x           21x       21x           21x                       21x                           21x                               21x   21x   3x                       1x                 21x                                
import {
  convertObjectPropsToCamelCase,
  convertObjectPropsToSnakeCase,
} from '~/lib/utils/common_utils';
import {
  RULE_TYPE_REGULAR,
  RULE_TYPE_ANY_APPROVER,
  APPROVAL_RULE_CONFIGS,
  RULE_TYPE_REPORT_APPROVER,
} from './constants';
 
const visibleTypes = new Set([RULE_TYPE_ANY_APPROVER, RULE_TYPE_REGULAR]);
 
function withDefaultEmptyRule(rules = []) {
  if (rules && rules.length > 0) {
    return rules;
  }
 
  return [
    {
      id: null,
      name: '',
      approvalsRequired: 0,
      minApprovalsRequired: 0,
      approvers: [],
      containsHiddenGroups: false,
      users: [],
      groups: [],
      ruleType: RULE_TYPE_ANY_APPROVER,
      protectedBranches: [],
      overridden: false,
    },
  ];
}
 
function ruleTypeFromName(ruleName) {
  return ruleName in APPROVAL_RULE_CONFIGS ? RULE_TYPE_REPORT_APPROVER : undefined;
}
 
function reportTypeFromName(ruleName) {
  return APPROVAL_RULE_CONFIGS[ruleName]?.reportType;
}
 
export const mapApprovalRuleRequest = (req) => ({
  ...convertObjectPropsToSnakeCase(req),
  report_type: reportTypeFromName(req.name),
  rule_type: ruleTypeFromName(req.name),
});
 
export const mapApprovalFallbackRuleRequest = (req) => ({
  fallback_approvals_required: req.approvalsRequired,
});
 
export const mapApprovalRuleResponse = (res) => ({
  ...convertObjectPropsToCamelCase(res),
  hasSource: Boolean(res.source_rule),
  minApprovalsRequired: 0,
});
 
export const mapApprovalSettingsResponse = (res) => ({
  rules: withDefaultEmptyRule(res.rules.map(mapApprovalRuleResponse)),
  fallbackApprovalsRequired: res.fallback_approvals_required,
});
 
/**
 * Map the sourced approval rule response for the MR view
 *
 * This rule is sourced from project settings, which implies:
 * - Not a real MR rule, so no "id".
 * - The approvals required are the minimum.
 */
export const mapMRSourceRule = ({ id, ...rule }) => ({
  ...rule,
  hasSource: true,
  sourceId: id,
  minApprovalsRequired: 0,
});
 
/**
 * Map the approval settings response for the MR view
 *
 * - Only show regular rules.
 * - If needed, extract the fallback approvals required
 *   from the fallback rule.
 */
export const mapMRApprovalSettingsResponse = (res) => {
  const rules = res.rules.filter(({ rule_type }) => visibleTypes.has(rule_type));
 
  const fallbackApprovalsRequired = res.fallback_approvals_required || 0;
 
  return {
    rules: withDefaultEmptyRule(
      rules
        .map(mapApprovalRuleResponse)
        .map(res.approval_rules_overwritten ? (x) => x : mapMRSourceRule),
    ),
    fallbackApprovalsRequired,
    minFallbackApprovalsRequired: 0,
  };
};
 
const invertApprovalSetting = ({ value, ...rest }) => ({ value: !value, ...rest });
 
export const mergeRequestApprovalSettingsMappers = {
  mapDataToState: (data) =>
    convertObjectPropsToCamelCase(
      {
        preventAuthorApproval: invertApprovalSetting(data.allow_author_approval),
        preventMrApprovalRuleEdit: invertApprovalSetting(
          data.allow_overrides_to_approver_list_per_merge_request,
        ),
        requireUserPassword: data.require_password_to_approve,
        removeApprovalsOnPush: invertApprovalSetting(data.retain_approvals_on_push),
        preventCommittersApproval: invertApprovalSetting(data.allow_committer_approval),
      },
      { deep: true },
    ),
  mapStateToPayload: ({ settings }) => ({
    allow_author_approval: !settings.preventAuthorApproval.value,
    allow_overrides_to_approver_list_per_merge_request: !settings.preventMrApprovalRuleEdit.value,
    require_password_to_approve: settings.requireUserPassword.value,
    retain_approvals_on_push: !settings.removeApprovalsOnPush.value,
    allow_committer_approval: !settings.preventCommittersApproval.value,
  }),
};
 
export const projectApprovalsMappers = {
  mapDataToState: (data) => ({
    preventAuthorApproval: { value: !data.merge_requests_author_approval },
    preventMrApprovalRuleEdit: { value: data.disable_overriding_approvers_per_merge_request },
    requireUserPassword: { value: data.require_password_to_approve },
    removeApprovalsOnPush: { value: data.reset_approvals_on_push },
    preventCommittersApproval: { value: data.merge_requests_disable_committers_approval },
  }),
  mapStateToPayload: ({ settings }) => ({
    merge_requests_author_approval: !settings.preventAuthorApproval.value,
    disable_overriding_approvers_per_merge_request: settings.preventMrApprovalRuleEdit.value,
    require_password_to_approve: settings.requireUserPassword.value,
    reset_approvals_on_push: settings.removeApprovalsOnPush.value,
    merge_requests_disable_committers_approval: settings.preventCommittersApproval.value,
  }),
};