.. versionadded:: 2014.7.0
    .. versionchanged:: 2015.8.0
        Renamed from ``git.config`` to ``git.config_set``. For earlier
        versions, use ``git.config``.

    Ensure that a config value is set to the desired value(s)

    name
        Name of the git config value to set

    value
        Set a single value for the config item

    multivar
        Set multiple values for the config item

        .. note::
            The order matters here, if the same parameters are set but in a
            different order, they will be removed and replaced in the order
            specified.

        .. versionadded:: 2015.8.0

    repo
        Location of the git repository for which the config value should be
        set. Required unless ``global`` is set to ``True``.

    user
        User under which to run git commands. By default, the commands are run
        by the user under which the minion is running.

    password
        Windows only. Required when specifying ``user``. This parameter will be
        ignored on non-Windows platforms.

      .. versionadded:: 2016.3.4

    global : False
        If ``True``, this will set a global git config option

    output_encoding
        Use this option to specify which encoding to use to decode the output
        from any git commands which are run. This should not be needed in most
        cases.

        .. note::
            This should only be needed if the files in the repository were
            created with filenames using an encoding other than UTF-8 to handle
            Unicode characters.

        .. versionadded:: 2018.3.1

    **Local Config Example:**

    .. code-block:: yaml

        # Single value
        mylocalrepo:
          git.config_set:
            - name: user.email
            - value: foo@bar.net
            - repo: /path/to/repo

        # Multiple values
        mylocalrepo:
          git.config_set:
            - name: mysection.myattribute
            - multivar:
              - foo
              - bar
              - baz
            - repo: /path/to/repo

    **Global Config Example (User ``foo``):**

    .. code-block:: yaml

        mylocalrepo:
          git.config_set:
            - name: user.name
            - value: Foo Bar
            - user: foo
            - global: True

def config_set(name,
               value=None,
               multivar=None,
               repo=None,
               user=None,
               password=None,
               output_encoding=None,
               **kwargs):
    '''
    .. versionadded:: 2014.7.0
    .. versionchanged:: 2015.8.0
        Renamed from ``git.config`` to ``git.config_set``. For earlier
        versions, use ``git.config``.

    Ensure that a config value is set to the desired value(s)

    name
        Name of the git config value to set

    value
        Set a single value for the config item

    multivar
        Set multiple values for the config item

        .. note::
            The order matters here, if the same parameters are set but in a
            different order, they will be removed and replaced in the order
            specified.

        .. versionadded:: 2015.8.0

    repo
        Location of the git repository for which the config value should be
        set. Required unless ``global`` is set to ``True``.

    user
        User under which to run git commands. By default, the commands are run
        by the user under which the minion is running.

    password
        Windows only. Required when specifying ``user``. This parameter will be
        ignored on non-Windows platforms.

      .. versionadded:: 2016.3.4

    global : False
        If ``True``, this will set a global git config option

    output_encoding
        Use this option to specify which encoding to use to decode the output
        from any git commands which are run. This should not be needed in most
        cases.

        .. note::
            This should only be needed if the files in the repository were
            created with filenames using an encoding other than UTF-8 to handle
            Unicode characters.

        .. versionadded:: 2018.3.1

    **Local Config Example:**

    .. code-block:: yaml

        # Single value
        mylocalrepo:
          git.config_set:
            - name: user.email
            - value: foo@bar.net
            - repo: /path/to/repo

        # Multiple values
        mylocalrepo:
          git.config_set:
            - name: mysection.myattribute
            - multivar:
              - foo
              - bar
              - baz
            - repo: /path/to/repo

    **Global Config Example (User ``foo``):**

    .. code-block:: yaml

        mylocalrepo:
          git.config_set:
            - name: user.name
            - value: Foo Bar
            - user: foo
            - global: True
    '''
    ret = {'name': name,
           'changes': {},
           'result': True,
           'comment': ''}

    if value is not None and multivar is not None:
        return _fail(
            ret,
            'Only one of \'value\' and \'multivar\' is permitted'
        )

    # Sanitize kwargs and make sure that no invalid ones were passed. This
    # allows us to accept 'global' as an argument to this function without
    # shadowing global(), while also not allowing unwanted arguments to be
    # passed.
    kwargs = salt.utils.args.clean_kwargs(**kwargs)
    global_ = kwargs.pop('global', False)
    if kwargs:
        return _fail(
            ret,
            salt.utils.args.invalid_kwargs(kwargs, raise_exc=False)
        )

    if not global_ and not repo:
        return _fail(
            ret,
            'Non-global config options require the \'repo\' argument to be '
            'set'
        )

    if not isinstance(name, six.string_types):
        name = six.text_type(name)
    if value is not None:
        if not isinstance(value, six.string_types):
            value = six.text_type(value)
        value_comment = '\'' + value + '\''
        desired = [value]
    if multivar is not None:
        if not isinstance(multivar, list):
            try:
                multivar = multivar.split(',')
            except AttributeError:
                multivar = six.text_type(multivar).split(',')
        else:
            new_multivar = []
            for item in multivar:
                if isinstance(item, six.string_types):
                    new_multivar.append(item)
                else:
                    new_multivar.append(six.text_type(item))
            multivar = new_multivar
        value_comment = multivar
        desired = multivar

    # Get current value
    pre = __salt__['git.config_get'](
        cwd=repo,
        key=name,
        user=user,
        password=password,
        ignore_retcode=True,
        output_encoding=output_encoding,
        **{'all': True, 'global': global_}
    )

    if desired == pre:
        ret['comment'] = '{0}\'{1}\' is already set to {2}'.format(
            'Global key ' if global_ else '',
            name,
            value_comment
        )
        return ret

    if __opts__['test']:
        ret['changes'] = {'old': pre, 'new': desired}
        msg = '{0}\'{1}\' would be {2} {3}'.format(
            'Global key ' if global_ else '',
            name,
            'added as' if pre is None else 'set to',
            value_comment
        )
        return _neutral_test(ret, msg)

    try:
        # Set/update config value
        post = __salt__['git.config_set'](
            cwd=repo,
            key=name,
            value=value,
            multivar=multivar,
            user=user,
            password=password,
            output_encoding=output_encoding,
            **{'global': global_}
        )
    except CommandExecutionError as exc:
        return _fail(
            ret,
            'Failed to set {0}\'{1}\' to {2}: {3}'.format(
                'global key ' if global_ else '',
                name,
                value_comment,
                _strip_exc(exc)
            )
        )

    if pre != post:
        ret['changes'][name] = {'old': pre, 'new': post}

    if post != desired:
        return _fail(
            ret,
            'Failed to set {0}\'{1}\' to {2}'.format(
                'global key ' if global_ else '',
                name,
                value_comment
            )
        )

    ret['comment'] = '{0}\'{1}\' was {2} {3}'.format(
        'Global key ' if global_ else '',
        name,
        'added as' if pre is None else 'set to',
        value_comment
    )
    return ret