Merge ~chad.smith/cloud-init:tools/migrate-script into cloud-init:master

Proposed by Chad Smith
Status: Merged
Approved by: Chad Smith
Approved revision: 54cece7e182681987ee739849f5eb9aea7e5e35c
Merge reported by: Server Team CI bot
Merged at revision: not available
Proposed branch: ~chad.smith/cloud-init:tools/migrate-script
Merge into: cloud-init:master
Diff against target: 242 lines (+230/-0)
2 files modified
tools/.lp-to-git-user (+1/-0)
tools/migrate-lp-user-to-github (+229/-0)
Reviewer Review Type Date Requested Status
Server Team CI bot continuous-integration Approve
Ryan Harper Needs Fixing
Review via email: mp+375163@code.launchpad.net

Commit message

tools: add migrate-lp-user-to-github script to link LP to github

To link a launchpad account name to your github account for licensing
accountability each LP user should publish a merge proposal in launchpad
with their LP account and a matching merge proposal in github using
their github user.

Cloud-init will track these usename maps in ./tools/.lp-to-git-user as
JSON.

Run ./tools/migrate-lp-user-to-github <LP_USERNAME> <GITHUB_USERNAME>
to automatically create merge proposals in launchpad and your github
account.

To post a comment you must log in.
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

FAILED: Continuous integration, rev:505ff34c3f0d23249b2298b75caf760e61792701
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1250/
Executed test runs:
    SUCCESS: Checkout
    FAILED: Unit & Style Tests

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1250//rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

FAILED: Continuous integration, rev:8b499f40bdc9d134d379dda5cc0c4fa29b6968e1
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1252/
Executed test runs:
    SUCCESS: Checkout
    FAILED: Unit & Style Tests

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1252//rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

PASSED: Continuous integration, rev:752e4d74a96bd340d913f74a1d36b38af4cd8921
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1253/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Unit & Style Tests
    SUCCESS: Ubuntu LTS: Build
    SUCCESS: Ubuntu LTS: Integration
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1253//rebuild

review: Approve (continuous-integration)
Revision history for this message
Ryan Harper (raharper) wrote :

This works quite well.

Can we add a check that the local master/upstream is in sync with github cloud-init master? I've not fetched from master, so the github pull request I got included my two usernames *and* the 19.3 release bump since my master local branch was behind remote master.

review: Needs Fixing
Revision history for this message
Ryan Harper (raharper) wrote :

I re-ran, and the error message isn't clear about which remote (github or launchpad) has the existing branches.

So we should prefix each error with the host.

Also, it appears to be changing into a new branch under the covers, the migrate-lp-to-github; so we should emit that we're creating a local branch and the name when we do it, and pushing to github, etc.

And I think we should emit the git commands used to reset things:

git push <remote> --delete migrate-lp-to-github

or have the script do this for users.

Revision history for this message
Ryan Harper (raharper) wrote :

Also, I wish we'd store the Launchpad oath token so repeated invocations don't force a new browser open.

Revision history for this message
Ryan Harper (raharper) wrote :

I can't get this to work after removing both branches.

Creating a migration branch: migrate-lp-to-github adding your users
The authorization page:
 (https://launchpad.net/+authorize-token?oauth_token=Tn4qDRnf4r4NvPBTKBQ3&allow_permission=DESKTOP_INTEGRATION)
should be opening in your browser. Use your browser to authorize
this program to access Launchpad on your behalf.
Waiting to hear from Launchpad about your decision...
[30816:30816:1105/175558.038112:ERROR:buffer_manager.cc(488)] [.DisplayCompositor]GL ERROR :GL_INVALID_OPERATION : glBufferData: <- error from previous GL command
[30777:30777:1105/175558.055909:ERROR:account_tracker.cc(241)] AccessTokenFetched error: Invalid credentials (credentials rejected by client).
Fontconfig error: Cannot load default config file
Traceback (most recent call last):
  File "./tools/migrate-lp-user-to-github", line 203, in <module>
  File "./tools/migrate-lp-user-to-github", line 193, in main
  File "/usr/lib/python3/dist-packages/lazr/restfulclient/resource.py", line 609, in __call__
    extra_headers=extra_headers)
  File "/usr/lib/python3/dist-packages/lazr/restfulclient/_browser.py", line 426, in _request
    raise error
lazr.restfulclient.errors.BadRequest: HTTP Error 400: Bad Request
Response headers:
---
-content-encoding: gzip
connection: close
content-length: 155
content-security-policy: frame-ancestors 'self';
content-type: text/plain
date: Tue, 05 Nov 2019 23:56:18 GMT
server: zope.server.http (HTTP)
status: 400
strict-transport-security: max-age=15552000
vary: Accept,Accept-Encoding
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-launchpad-revision: 469f241f4e73cc0bdffa4e30654052a2af068e06
x-lazr-notifications: []
x-powered-by: Zope (www.zope.org), Python (www.python.org)
x-xss-protection: 1; mode=block
---
Response body:
---
b'There is already a branch merge proposal registered for branch ~raharper/cloud-init:migrate-lp-to-github to land on cloud-init:master that is still active.'
---

Revision history for this message
Server Team CI bot (server-team-bot) wrote :

PASSED: Continuous integration, rev:bc9fa0fe5fb5859a4e10ff92dcb0726d89ad898c
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1261/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Unit & Style Tests
    SUCCESS: Ubuntu LTS: Build
    SUCCESS: Ubuntu LTS: Integration
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1261//rebuild

review: Approve (continuous-integration)
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

PASSED: Continuous integration, rev:7f6b69529fb9c2942f7084d7ffa444af57204488
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1263/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Unit & Style Tests
    SUCCESS: Ubuntu LTS: Build
    SUCCESS: Ubuntu LTS: Integration
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1263//rebuild

review: Approve (continuous-integration)
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

PASSED: Continuous integration, rev:54cece7e182681987ee739849f5eb9aea7e5e35c
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1273/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Unit & Style Tests
    SUCCESS: Ubuntu LTS: Build
    SUCCESS: Ubuntu LTS: Integration
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1273//rebuild

review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/tools/.lp-to-git-user b/tools/.lp-to-git-user
0new file mode 1006440new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/tools/.lp-to-git-user
@@ -0,0 +1 @@
1{}
diff --git a/tools/migrate-lp-user-to-github b/tools/migrate-lp-user-to-github
0new file mode 1007552new file mode 100755
index 0000000..6b095a1
--- /dev/null
+++ b/tools/migrate-lp-user-to-github
@@ -0,0 +1,229 @@
1#!/usr/bin/python3
2"""Link your Launchpad user to github, proposing branches to LP and Github"""
3
4from argparse import ArgumentParser
5from subprocess import Popen, PIPE
6import os
7import sys
8
9try:
10 from launchpadlib.launchpad import Launchpad
11except ImportError:
12 print("Missing python launchpadlib dependency to create branches for you."
13 "Install with: sudo apt-get install python3-launchpadlib" )
14 sys.exit(1)
15
16if "avoid-pep8-E402-import-not-top-of-file":
17 _tdir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
18 sys.path.insert(0, _tdir)
19 from cloudinit import util
20
21
22DRYRUN = False
23LP_TO_GIT_USER_FILE='.lp-to-git-user'
24MIGRATE_BRANCH_NAME='migrate-lp-to-github'
25GITHUB_PULL_URL='https://github.com/canonical/cloud-init/compare/master...{github_user}:{branch}'
26GH_UPSTREAM_URL='https://github.com/canonical/cloud-init'
27
28
29def error(message):
30 if isinstance(message, bytes):
31 message = message.decode('utf-8')
32 log('ERROR: {error}'.format(error=message))
33 sys.exit(1)
34
35
36def log(message):
37 print(message)
38
39
40def subp(cmd, skip=False):
41 prefix = 'SKIPPED: ' if skip else '$ '
42 log('{prefix}{command}'.format(prefix=prefix, command=' '.join(cmd)))
43 if skip:
44 return
45 proc = Popen(cmd, stdout=PIPE, stderr=PIPE)
46 out, err = proc.communicate()
47 if proc.returncode:
48 error(err if err else out)
49 return out.decode('utf-8')
50
51
52LP_GIT_PATH_TMPL = 'git+ssh://{launchpad_user}@git.launchpad.net/'
53LP_UPSTREAM_PATH_TMPL = LP_GIT_PATH_TMPL + 'cloud-init'
54LP_REMOTE_PATH_TMPL = LP_GIT_PATH_TMPL + '~{launchpad_user}/cloud-init'
55GITHUB_REMOTE_PATH_TMPL = 'git@github.com:{github_user}/cloud-init.git'
56
57
58# Comment templates
59COMMIT_MSG_TMPL = '''
60lp-to-git-users: adding {gh_username}
61
62Mapped from {lp_username}
63'''
64PUBLISH_DIR='/tmp/cloud-init-lp-to-github-migration'
65
66def get_parser():
67 parser = ArgumentParser(description=__doc__)
68 parser.add_argument(
69 '--dryrun', required=False, default=False, action='store_true',
70 help=('Run commands and review operation in dryrun mode, '
71 'making not changes.'))
72 parser.add_argument('launchpad_user', help='Your launchpad username.')
73 parser.add_argument('github_user', help='Your github username.')
74 parser.add_argument(
75 '--local-repo-dir', required=False, dest='repo_dir',
76 help=('The name of the local directory into which we clone.'
77 ' Default: {}'.format(PUBLISH_DIR)))
78 parser.add_argument(
79 '--upstream-branch', required=False, dest='upstream',
80 default='origin/master',
81 help=('The name of remote branch target into which we will merge.'
82 ' Default: origin/master'))
83 parser.add_argument(
84 '-v', '--verbose', required=False, default=False, action='store_true',
85 help=('Print all actions.'))
86 parser.add_argument(
87 '--push-remote', required=False, dest='pushremote',
88 help=('QA-only provide remote name into which you want to push'))
89 return parser
90
91
92def create_publish_branch(upstream, publish_branch):
93 '''Create clean publish branch target in the current git repo.'''
94 branches = subp(['git', 'branch'])
95 upstream_remote, upstream_branch = upstream.split('/', 1)
96 subp(['git', 'checkout', upstream_branch])
97 subp(['git', 'pull'])
98 if publish_branch in branches:
99 subp(['git', 'branch', '-D', publish_branch])
100 subp(['git', 'checkout', upstream, '-b', publish_branch])
101
102
103def add_lp_and_github_remotes(lp_user, gh_user):
104 """Add lp and github remotes if not present.
105
106 @return Tuple with (lp_remote_name, gh_remote_name)
107 """
108 lp_remote = LP_REMOTE_PATH_TMPL.format(launchpad_user=lp_user)
109 gh_remote = GITHUB_REMOTE_PATH_TMPL.format(github_user=gh_user)
110 remotes = subp(['git', 'remote', '-v'])
111 lp_remote_name = gh_remote_name = None
112 for remote in remotes.splitlines():
113 if not remote:
114 continue
115 remote_name, remote_url, _operation = remote.split()
116 if lp_remote == remote_url:
117 lp_remote_name = remote_name
118 elif gh_remote == remote_url:
119 gh_remote_name = remote_name
120 if not lp_remote_name:
121 log("launchpad: Creating git remote launchpad-{} to point at your"
122 " LP repo".format(lp_user))
123 lp_remote_name = 'launchpad-{}'.format(lp_user)
124 subp(['git', 'remote', 'add', lp_remote_name, lp_remote])
125 subp(['git', 'fetch', lp_remote_name])
126 if not gh_remote_name:
127 log("github: Creating git remote github-{} to point at your"
128 " GH repo".format(gh_user))
129 gh_remote_name = 'github-{}'.format(gh_user)
130 subp(['git', 'remote', 'add', gh_remote_name, gh_remote])
131 try:
132 subp(['git', 'fetch', gh_remote_name])
133 except:
134 log("ERROR: [github] Could not fetch remote '{remote}'."
135 "Please create a fork for your github user by clicking 'Fork'"
136 " from {gh_upstream}".format(
137 remote=gh_remote, gh_upstream=GH_UPSTREAM_URL))
138 sys.exit(1)
139 return (lp_remote_name, gh_remote_name)
140
141
142def create_migration_branch(
143 branch_name, upstream, lp_user, gh_user, commit_msg):
144 """Create an LP to Github migration branch and add lp_user->gh_user."""
145 log("Creating a migration branch: {} adding your users".format(
146 MIGRATE_BRANCH_NAME))
147 create_publish_branch(upstream, MIGRATE_BRANCH_NAME)
148 lp_to_git_map = {}
149 lp_to_git_file = os.path.join(os.getcwd(), LP_TO_GIT_USER_FILE)
150 if os.path.exists(lp_to_git_file):
151 with open(lp_to_git_file) as stream:
152 lp_to_git_map = util.load_json(stream.read())
153 if gh_user in lp_to_git_map.values():
154 raise RuntimeError(
155 "github user '{}' already in {}".format(gh_user, lp_to_git_file))
156 if lp_user in lp_to_git_map:
157 raise RuntimeError(
158 "launchpad user '{}' already in {}".format(
159 lp_user, lp_to_git_file))
160 lp_to_git_map[lp_user] = gh_user
161 with open(lp_to_git_file, 'w') as stream:
162 stream.write(util.json_dumps(lp_to_git_map))
163 subp(['git', 'add', lp_to_git_file])
164 commit_file = os.path.join(os.path.dirname(os.getcwd()), 'commit.msg')
165 with open(commit_file, 'wb') as stream:
166 stream.write(commit_msg.encode('utf-8'))
167 subp(['git', 'commit', '--all', '-F', commit_file])
168
169
170def main():
171 global DRYRUN
172 global VERBOSITY
173 parser = get_parser()
174 args = parser.parse_args()
175 DRYRUN = args.dryrun
176 VERBOSITY = 1 if args.verbose else 0
177 repo_dir = args.repo_dir or PUBLISH_DIR
178 if not os.path.exists(repo_dir):
179 subp(['git', 'clone',
180 LP_UPSTREAM_PATH_TMPL.format(launchpad_user=args.launchpad_user),
181 repo_dir])
182 os.chdir(repo_dir)
183 log("Sycing master branch with upstream")
184 subp(['git', 'checkout', 'master'])
185 subp(['git', 'pull'])
186 lp_remote_name, gh_remote_name = add_lp_and_github_remotes(
187 args.launchpad_user, args.github_user)
188 commit_msg = COMMIT_MSG_TMPL.format(
189 gh_username=args.github_user, lp_username=args.launchpad_user)
190 create_migration_branch(
191 MIGRATE_BRANCH_NAME, args.upstream, args.launchpad_user,
192 args.github_user, commit_msg)
193
194 for push_remote in (lp_remote_name, gh_remote_name):
195 subp(['git', 'push', push_remote, MIGRATE_BRANCH_NAME, '--force'])
196
197 # Make merge request on LP
198 log("[launchpad] Automatically creating merge proposal using launchpadlib")
199 lp = Launchpad.login_with(
200 "server-team github-migration tool", 'production', version='devel')
201 master = lp.git_repositories.getByPath(
202 path='cloud-init').getRefByPath(path='master')
203 LP_BRANCH_PATH='~{launchpad_user}/cloud-init/+git/cloud-init'
204 lp_git_repo = lp.git_repositories.getByPath(
205 path=LP_BRANCH_PATH.format(launchpad_user=args.launchpad_user))
206 lp_user_migrate_branch = lp_git_repo.getRefByPath(
207 path='refs/heads/migrate-lp-to-github')
208 lp_merge_url = (
209 'https://code.launchpad.net/' +
210 LP_BRANCH_PATH.format(launchpad_user=args.launchpad_user) +
211 '/+ref/' + MIGRATE_BRANCH_NAME)
212 try:
213 lp_user_migrate_branch.createMergeProposal(
214 commit_message=commit_msg, merge_target=master, needs_review=True)
215 except Exception as e:
216 log('[launchpad] active merge proposal already exists at:\n'
217 '{url}\n'.format(url=lp_merge_url))
218 else:
219 log("[launchpad] Merge proposal created at:\n{url}.\n".format(
220 url=lp_merge_url))
221 log("To link your account to github open your browser and"
222 " click 'Create pull request' at the following URL:\n"
223 "{url}".format(url=GITHUB_PULL_URL.format(
224 github_user=args.github_user, branch=MIGRATE_BRANCH_NAME)))
225 return 0
226
227
228if __name__ == '__main__':
229 sys.exit(main())

Subscribers

People subscribed via source and target branches