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
|
#!/usr/bin/python3
# Given a merge proposal URL (eg.
# https://code.launchpad.net/~paelzer/ubuntu/+source/open-vm-tools/+git/open-vm-tools/+merge/352237)
# this script clones the proposer's branch, upload tags it, and pushes the
# upload tag to the official repository. This can be used by members of
# ~git-ubuntu-import to easily push an upload tag for contributors, until we
# have a mechanism to do this better.
#
# This does minimal checking. The target repository must be correct; otherwise
# the upload tag will be pushed to the wrong place. There are races (for
# example if the proposer pushes a new commit after you reviewed but before
# this script completes). However this script only pushes upload tags, so is
# generally safe since the importer always verifies before incorporating an
# upload tag. We intend to allow uploaders to push upload tags (or their
# equivalent) directly anyway; this is a stop-gap because using the current tag
# mechanism is awkward because Launchpad doesn't currently have per-ref ACLs.
#
# Prerequisites:
# python3-launchpadlib installed
# You have a Launchpad login that # belongs to ~git-ubuntu-import
import os
import subprocess
import sys
import tempfile
import launchpadlib.launchpad
def split_merge_url(url):
"""Given an LP merge proposal URL, extract its essential components
This is a hack. Given something like
https://code.launchpad.net/~paelzer/ubuntu/+source/open-vm-tools/+git/open-vm-tools/+merge/352237,
this works out the lp username, package name and "merge id" of the
corresponding MP, for use in further hacky API calls.
Returns a tuple of (lpuser, pkgname, mergeid) (all strings).
"""
assert url.startswith('https://code.launchpad.net/')
trail = url[len('https://code.launchpad.net/'):]
lpuser, ubuntu, source, pkgname1, plusgit, pkgname2, plusmerge, mergeid = trail.split('/')
assert ubuntu == 'ubuntu'
assert source == '+source'
assert pkgname1 == pkgname2
assert plusgit == '+git'
assert plusmerge == '+merge'
return lpuser, pkgname1, mergeid
def insert_username_into_git_ssh_url(lp, url):
"""Given a Launchpad object and a git_ssh repository URL, insert the user
to authenticate with
input url example: 'git+ssh://git.launchpad.net/ubuntu/+source/open-vm-tools'
return value example: 'git+ssh://racb@git.launchpad.net/ubuntu/+source/open-vm-tools'
"""
assert url.startswith('git+ssh://git.launchpad.net')
trail = url[len('git+ssh://git.launchpad.net'):]
return 'git+ssh://' + lp.me.name + '@git.launchpad.net' + trail
def get_merge_proposal(lp, url):
"""Given a Launchpad object and a web interface MP URL, return the
corresponding Launchpad API branch_merge_proposal object
"""
user, pkgname1, mergeid = split_merge_url(url)
return lp.load('https://api.launchpad.net/devel/{user}/ubuntu/+source/{pkgname}/+git/{pkgname}/+merge/{mergeid}'.format(user=user, pkgname=pkgname1, mergeid=mergeid))
def clone_tag_and_push(url):
# Log in and get our lp object
lp = launchpadlib.launchpad.Launchpad.login_with(
'git-ubuntu-auto-upload-tag', 'production', version='devel'
)
# Get the merge proposal lp object
mp = get_merge_proposal(lp, url)
# Figure out the proposal's git repository URL and branch name and clone it
git_url = mp.source_git_repository.git_https_url
git_ref = mp.source_git_path
assert git_ref.startswith('refs/heads/')
git_branch = git_ref[len('refs/heads/'):]
subprocess.check_call(['git', 'clone', '-b', git_branch, git_url, 'git'])
# Figure out the upload tag name and tag it
tag = subprocess.check_output(['git', 'ubuntu', 'tag', '--print-name-only', '--upload'], cwd='git').strip().decode()
subprocess.check_call(['git', 'tag', tag, 'HEAD'], cwd='git')
# Figure out the target repository for the upload tag push
lpuser, pkgname, mergeid = split_merge_url(url)
target_git_repo = mp.target_git_repository
target = target_git_repo.target
# Check the target repository we've worked out is sane
assert target.resource_type_link == 'https://api.launchpad.net/devel/#distribution_source_package'
assert target.name == pkgname
# Push the upload tag
subprocess.check_call(['echo', 'git', 'push', insert_username_into_git_ssh_url(lp, target_git_repo.git_ssh_url), tag], cwd='git')
def main(url):
with tempfile.TemporaryDirectory() as d:
os.chdir(d)
clone_tag_and_push(url)
if __name__ == '__main__':
main(sys.argv[1])
|