Skip to content

Commit

Permalink
Merge pull request #49305 from terminalmage/issue48299
Browse files Browse the repository at this point in the history
Allow git.latest to remove local tags which have been removed remotely
  • Loading branch information
gtmanfred committed Aug 24, 2018
2 parents 459354a + 4a093d9 commit b65890c
Show file tree
Hide file tree
Showing 3 changed files with 341 additions and 77 deletions.
110 changes: 110 additions & 0 deletions salt/modules/git.py
Original file line number Diff line number Diff line change
Expand Up @@ -4845,6 +4845,116 @@ def symbolic_ref(cwd,
output_encoding=output_encoding)['stdout']


def tag(cwd,
name,
ref='HEAD',
message=None,
opts='',
git_opts='',
user=None,
password=None,
ignore_retcode=False,
output_encoding=None):
'''
.. versionadded:: 2018.3.4
Interface to `git-tag(1)`_, adds and removes tags.
cwd
The path to the main git checkout or a linked worktree
name
Name of the tag
ref : HEAD
Which ref to tag (defaults to local clone's HEAD)
.. note::
This argument is ignored when either ``-d`` or ``--delete`` is
present in the ``opts`` passed to this function.
message
Optional message to include with the tag. If provided, an annotated tag
will be created.
opts
Any additional options to add to the command line, in a single string
.. note::
Additionally, on the Salt CLI, if the opts are preceded with a
dash, it is necessary to precede them with ``opts=`` (as in the CLI
examples below) to avoid causing errors with Salt's own argument
parsing.
git_opts
Any additional options to add to git command itself (not the
``worktree`` subcommand), in a single string. This is useful for
passing ``-c`` to run git with temporary changes to the git
configuration.
.. note::
This is only supported in git 1.7.2 and newer.
user
User under which to run the git command. By default, the command is 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.
ignore_retcode : False
If ``True``, do not log an error to the minion log if the git command
returns a nonzero exit status.
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.
.. _`git-tag(1)`: http://git-scm.com/docs/git-tag
CLI Example:
.. code-block:: bash
# Create an non-annotated tag
salt myminion git.tag /path/to/repo v1.2
# Create an annotated tag
salt myminion git.tag /path/to/repo v1.2 message='Version 1.2'
# Delete the tag
salt myminion git.tag /path/to/repo v1.2 opts='-d'
'''
cwd = _expand_path(cwd, user)
command = ['git'] + _format_git_opts(git_opts)
command.append('tag')
# Don't add options for annotated commits, since we'll automatically add
# them if a message was passed. This keeps us from blocking on input, since
# passing an annotated command
formatted_opts = [x for x in _format_opts(opts) if x not in ('-a', '--annotate')]
# Make sure that the message was not passed in the opts
if any(x == '-m' or '--message' in x for x in formatted_opts):
raise SaltInvocationError(
'Tag messages must be passed in the "message" argument'
)
command.extend(formatted_opts)
command.append(name)
if '-d' not in formatted_opts and '--delete' not in formatted_opts:
command.append(ref)
return _git_run(command,
cwd=cwd,
user=user,
password=password,
ignore_retcode=ignore_retcode,
redirect_stderr=True,
output_encoding=output_encoding)['stdout']


def version(versioninfo=False):
'''
.. versionadded:: 2015.8.0
Expand Down
78 changes: 64 additions & 14 deletions salt/states/git.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,12 @@ def _uptodate(ret, target, comments=None, local_changes=False):
# Shouldn't be making any changes if the repo was up to date, but
# report on them so we are alerted to potential problems with our
# logic.
ret['comment'] += '\n\nChanges made: ' + comments
ret['comment'] += (
'\n\nChanges {0}made: {1}'.format(
'that would be ' if __opts__['test'] else '',
_format_comments(comments)
)
)
return ret


Expand All @@ -171,8 +176,7 @@ def _neutral_test(ret, comment):
def _fail(ret, msg, comments=None):
ret['result'] = False
if comments:
msg += '\n\nChanges already made: '
msg += _format_comments(comments)
msg += '\n\nChanges already made: ' + _format_comments(comments)
ret['comment'] = msg
return ret

Expand All @@ -184,8 +188,12 @@ def _already_cloned(ret, target, branch=None, comments=None):
' and is checked out to branch \'{0}\''.format(branch) if branch else ''
)
if comments:
ret['comment'] += '\n\nChanges already made: '
ret['comment'] += _format_comments(comments)
ret['comment'] += (
'\n\nChanges {0}made: {1}'.format(
'that would be ' if __opts__['test'] else '',
_format_comments(comments)
)
)
return ret


Expand Down Expand Up @@ -268,6 +276,7 @@ def latest(name,
mirror=False,
remote='origin',
fetch_tags=True,
sync_tags=True,
depth=None,
identity=None,
https_user=None,
Expand Down Expand Up @@ -460,6 +469,12 @@ def latest(name,
If ``True``, then when a fetch is performed all tags will be fetched,
even those which are not reachable by any branch on the remote.
sync_tags : True
If ``True``, then Salt will delete tags which exist in the local clone
but are not found on the remote repository.
.. versionadded:: 2018.3.4
depth
Defines depth in history when git a clone is needed in order to ensure
latest. E.g. ``depth: 1`` is useful when deploying from a repository
Expand Down Expand Up @@ -851,11 +866,14 @@ def latest(name,
user=user,
password=password,
output_encoding=output_encoding)
all_local_tags = __salt__['git.list_tags'](
target,
user=user,
password=password,
output_encoding=output_encoding)
all_local_tags = set(
__salt__['git.list_tags'](
target,
user=user,
password=password,
output_encoding=output_encoding
)
)
local_rev, local_branch = _get_local_rev_and_branch(
target,
user,
Expand Down Expand Up @@ -1370,11 +1388,43 @@ def latest(name,
ignore_retcode=True,
output_encoding=output_encoding) if '^{}' not in x
])
if set(all_local_tags) != remote_tags:
if all_local_tags != remote_tags:
has_remote_rev = False
ret['changes']['new_tags'] = list(remote_tags.symmetric_difference(
all_local_tags
))
new_tags = remote_tags - all_local_tags
deleted_tags = all_local_tags - remote_tags
if new_tags:
ret['changes']['new_tags'] = new_tags
if sync_tags and deleted_tags:
# Delete the local copy of the tags to keep up with the
# remote repository.
for tag_name in deleted_tags:
try:
if not __opts__['test']:
__salt__['git.tag'](
target,
tag_name,
opts='-d',
user=user,
password=password,
output_encoding=output_encoding)
except CommandExecutionError as exc:
ret.setdefault('warnings', []).append(
'Failed to remove local tag \'{0}\':\n\n'
'{1}\n\n'.format(tag_name, exc)
)
else:
ret['changes'].setdefault(
'deleted_tags', []).append(tag_name)

if ret['changes'].get('deleted_tags'):
comments.append(
'The following tags {0} removed from the local '
'checkout: {1}'.format(
'would be' if __opts__['test']
else 'were',
', '.join(ret['changes']['deleted_tags'])
)
)

if not has_remote_rev:
try:
Expand Down
Loading

0 comments on commit b65890c

Please sign in to comment.