gbp-posttag-push 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. #!/usr/bin/python
  2. # vim: set fileencoding=utf-8 :
  3. #
  4. # (C) 2009,2012,2015 Guido Guenther <agx@sigxcpu.org>
  5. #
  6. # gbp-posttag-push: post tag hook to be called by git-buildpackage to push out
  7. # the newly created tag and to forward the remote branch to that position
  8. #
  9. # it checks for explicit push destinations, if none are found it pushes back to
  10. # where the branch got merged from. Before pushing it checks if the tag is
  11. # signed.
  12. #
  13. # use:
  14. # [git-buildpackage]
  15. # posttag = gbp-posttag-push
  16. #
  17. # Options:
  18. # -d: dry-run
  19. # -u: push upstream branch too, if not on remote already
  20. # --verbose: verbose command output
  21. from __future__ import print_function
  22. from six.moves import configparser
  23. import os
  24. import subprocess
  25. import sys
  26. import gbp.log
  27. from gbp.config import GbpOptionParser
  28. from gbp.deb.git import DebianGitRepository
  29. class Env(object):
  30. pass
  31. def get_push_targets(env):
  32. """get a list of push targets"""
  33. dests = {}
  34. cmd = "git config --get-regexp 'remote\..*\.push' '^%s(:.*)?$'" % env.branch
  35. for remote in subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True).communicate()[0].split("\n"):
  36. if not len(remote):
  37. continue
  38. repo, refspec = remote.split()
  39. repo = ".".join(repo.split('.')[1:-1]) # remote.<repo>.push
  40. try:
  41. remote = refspec.split(':')[1] # src:dest
  42. except IndexError:
  43. remote = refspec
  44. dests[repo] = remote
  45. return dests
  46. def get_pull(env):
  47. """where did we pull from?"""
  48. cmd = 'git config --get branch."%s".remote' % env.branch
  49. remote = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True).communicate()[0].strip()
  50. if not remote:
  51. remote = 'origin'
  52. return { remote: env.branch }
  53. def git_push_sim(*args):
  54. print("git push %s" % " ".join(args))
  55. def get_upstream_tag(repo, tag, tag_format):
  56. # FIXME: This assumes the debian version is the last part after the slash:
  57. version = tag.split('/')[-1]
  58. no_epoch = version.split(':')[-1]
  59. upstream = version.rsplit('-')[0]
  60. tag = tag_format % dict(version=upstream)
  61. if repo.has_tag(tag):
  62. return tag
  63. return None
  64. def main(argv):
  65. env = Env()
  66. upstream_sha1 = None
  67. try:
  68. parser = GbpOptionParser(command=os.path.basename(argv[0]), prefix='',
  69. usage='%prog [options] paths')
  70. except configparser.ParsingError as err:
  71. gbp.log.error(err)
  72. return 1
  73. parser.add_option("-d", "--dry-run", dest="dryrun", default=False,
  74. action="store_true", help="dry run, don't push.")
  75. parser.add_option("-u", "--push-upstream", dest="push_upstream",
  76. default=False,
  77. action="store_true",
  78. help="also push upstream branch changes")
  79. parser.add_config_file_option(option_name="upstream-branch",
  80. dest="upstream_branch")
  81. parser.add_config_file_option(option_name="upstream-tag",
  82. dest="upstream_tag")
  83. parser.add_option("--verbose", action="store_true", dest="verbose",
  84. default=False, help="verbose command execution")
  85. (options, args) = parser.parse_args()
  86. gbp.log.setup(False, options.verbose)
  87. repo = DebianGitRepository('.')
  88. if options.dryrun:
  89. print("Dry run mode. Not pushing.")
  90. repo.push = git_push_sim
  91. repo.push_tag = git_push_sim
  92. for envvar in [ "GBP_TAG", "GBP_BRANCH", "GBP_SHA1" ]:
  93. var = os.getenv(envvar)
  94. if var:
  95. env.__dict__.setdefault( "%s" % envvar.split("_")[1].lower(), var)
  96. else:
  97. print("%s not set." % envvar, file=sys.stderr)
  98. return 1
  99. dests = get_push_targets(env)
  100. if not dests:
  101. dests = get_pull(env)
  102. upstream_tag = get_upstream_tag(repo, env.tag, options.upstream_tag)
  103. if upstream_tag:
  104. upstream_sha1 = repo.rev_parse("%s^{}" % upstream_tag)
  105. if not repo.verify_tag(env.tag):
  106. print("Not pushing nonexistent or unsigned tag '%s'." % env.tag, file=sys.stderr)
  107. return 0
  108. for dest in dests:
  109. print("Pushing %s to %s" % (env.tag, dest))
  110. repo.push_tag(dest, env.tag)
  111. print("Pushing %s to %s" % (env.sha1, dest))
  112. repo.push(dest, env.sha1, dests[dest])
  113. if options.push_upstream and upstream_tag:
  114. print("Pushing %s to %s" % (upstream_tag, dest))
  115. repo.push_tag(dest, upstream_tag)
  116. if not repo.branch_contains("%s/%s" % (dest, options.upstream_branch),
  117. upstream_sha1, remote=True):
  118. print("Pushing %s to %s" % (upstream_sha1, dest))
  119. repo.push(dest, upstream_sha1, options.upstream_branch)
  120. print("done.")
  121. if __name__ == '__main__':
  122. sys.exit(main(sys.argv))
  123. # vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·: