def send_upstream(self, downstream, upstream): """ Sends the change indicated by the comment upstream. @param downstream - gerrit.Remote downstream object @param upstream - gerrit.Remote upstream object """ # Check if upstream project before doing anything. if not self.is_upstream_project(): return ssh = downstream.SSH() # Check to see if comment indicates a change is upstream ready if not self.is_upstream_indicated(): logger.debug("Change %s: Upstream not indicated" % self.change_id) return # Grab all of the approvals approvals = self.get_approvals(downstream.SSH()) # Check to see if comment has necessary approvals. if self.is_forced(): if not self.is_release_approved(approvals): msg = "Could not send to upstream: Release not approved." logger.debug("Change %s: %s" % (self.change_id, msg)) ssh.exec_once('gerrit review -m %s %s' % (pipes.quote(msg), self.revision)) return msg = ("***WARNING***\n%s (%s) has requested a forced upstream " "push. Bypassing all votes except for Release...\n\n" "Current votes are:\n\n%s" % (self._data['author']['name'], self._data['author']['email'], self.stringify_approvals(approvals))) logger.debug("Change %s: %s" % (self.change_id, msg)) ssh.exec_once('gerrit review -m %s %s' % (pipes.quote(msg), self.revision)) else: if not self.is_upstream_approved(approvals): msg = ("Could not send to upstream: One or more labels" " not approved.") logger.debug("Change %s: %s" % (self.change_id, msg)) ssh.exec_once('gerrit review -m %s %s' % (pipes.quote(msg), self.revision)) return # Do some git stuffs to push upstream logger.debug("Change %s: Sending to upstream" % self.change_id) repo_dir = '~/tmp' repo_dir = os.path.expanduser(repo_dir) repo_dir = os.path.abspath(repo_dir) # Add uuid, want a unique directory here uuid_dir = str(uuid4()) repo_dir = os.path.join(repo_dir, uuid_dir) # Make Empty directory - We want this to stop and fail on OSError if not os.path.isdir(repo_dir): os.makedirs(repo_dir) logger.debug( "Change %s: Created directory %s" % (self.change_id, repo_dir) ) # Save the current working directory old_cwd = os.getcwd() try: # Change to newly created directory. os.chdir(repo_dir) # Init the cwd git.init() # Add the remotes for upstream and downstream remote_url = "ssh://%s@%s:%s/%s" git.add_remote('downstream', remote_url % (downstream.username, downstream.host, downstream.port, self.project)) # Figure out what user we will pose as # This every upstream user sharing the same key is kinda shady. # Default back to the configured user if username doesnt exist. # should fail in this case username = self.patchset_uploader_username name = self.patchSet_uploader_name email = self.patchset_uploader_email if not username: logger.debug("Change %s: Unable to use author credentials." " Defaulting to configured credentials." % self.change_id) username = upstream.username name = self._conf['git-config']['name'] email = self._conf['git-config']['email'] git.add_remote('upstream', remote_url % (username, upstream.host, upstream.port, self.project)) logger.debug('Change %s: Sending upstream as ' 'username %s, email %s, name %s' % (self.change_id, username, email, name)) try: env = get_review_env() # Set committer info git.set_config('user.email', email) git.set_config('user.name', name) # Download specific change to local args = ['git-review', '-r', 'downstream', '-d', '%s,%s' % (self.change_id, self.patchset_id)] logger.debug('Change %s: running: %s' % (self.change_id, ' '.join(args))) out = subprocess.check_output(args, stderr=subprocess.STDOUT, env=env) logger.debug("Change %s: %s" % (self.change_id, out)) # Send downloaded change to upstream args = ['git-review', '-R', '-y', '-r', 'upstream', self.branch, '-t', self.topic] logger.debug('Change %s: running: %s' % (self.change_id, ' '.join(args))) out = subprocess.check_output(args, stderr=subprocess.STDOUT, env=env) logger.debug("Change %s: %s" % (self.change_id, out)) upstream_url = self.get_upstream_url(upstream) msg = 'Sent to upstream: %s' % (upstream_url) # Send comment to downstream gerrit with link to change in # upstream gerrit ssh.exec_once('gerrit review -m %s %s' % (pipes.quote(msg), self.revision)) except subprocess.CalledProcessError as e: msg = "Could not send to upstream:\n%s" % e.output ssh.exec_once('gerrit review -m %s %s' % (pipes.quote(msg), self.revision)) logger.error("Change %s: Unable to send to upstream" % self.change_id) logger.error("Change %s: %s" % (self.change_id, out)) except Exception: msg = 'Could not send to upstream: Error running git-review' ssh.exec_once('gerrit review -m %s %s' % (pipes.quote(msg), self.revision)) logger.exception("Change %s: Unable to send to upstream" % self.change_id) finally: # Change to old current working directory os.chdir(old_cwd) # Attempt to clean up created directory shutil.rmtree(repo_dir)
def _sync(self, remote): """ Pushes all normal branches from a source repo to gerrit. @param remote - gerrit.Remote object """ # Only sync if source repo is provided. if not self.source: return # Only sync if heads and/or tags are specified if not self.heads and not self.tags: return msg = "Project %s: syncing with repo %s." % (self.name, self.source) logger.info(msg) print msg repo_dir = '~/tmp' repo_dir = os.path.expanduser(repo_dir) repo_dir = os.path.abspath(repo_dir) # Make Empty directory - We want this to stop and fail on OSError if not os.path.isdir(repo_dir): os.makedirs(repo_dir) logger.debug( "Project %s: Created directory %s" % (self.name, repo_dir) ) # Save the current working directory old_cwd = os.getcwd() try: # Change cwd to that repo os.chdir(repo_dir) uuid_dir = str(uuid4()) repo_dir = os.path.join(repo_dir, uuid_dir) # Do a git clone --bare <source_repo> git.clone(self.source, name=uuid_dir, bare=True) # Change to bare cloned directory os.chdir(uuid_dir) # Add remote named gerrit ssh_url = 'ssh://%s@%s:%s/%s' % ( remote.username, remote.host, remote.port, self.name ) git.add_remote('gerrit', ssh_url) # Push heads if self.heads: kwargs = {'all_': True} if self.force: kwargs['force'] = True git.push('gerrit', **kwargs) # Push tags if self.tags: kwargs = {'tags': True} if self.force: kwargs['force'] = True git.push('gerrit', **kwargs) ref_kwargs = self.ref_kwargs() # Grab origin refs origin_refset = git.remote_refs('origin', **ref_kwargs) # Grab gerrit refs gerrit_refset = git.remote_refs('gerrit', **ref_kwargs) # Find refs that should be removed. prune_refset = gerrit_refset - origin_refset if self.preserve_prefix == PRESERVE_ALL_BRANCHES: msg = "Project %s: Preserving all refs" % self.name logger.debug(msg) print msg prune_refset = set([]) elif not self.preserve_prefix is None: msg = "Project %s: Preserving refs with prefixes of %s" \ % (self.name, self.preserve_prefix) logger.debug(msg) print msg heads_prefix = "refs/heads/%s" % self.preserve_prefix tags_prefix = "refs/tags/%s" % self.preserve_prefix keep = lambda ref: not ref.startswith(heads_prefix) and \ not ref.startswith(tags_prefix) prune_refset = filter(keep, prune_refset) # Prefix each ref in refset with ':' to delete colonize = lambda ref: ':%s' % ref prune_refset = map(colonize, prune_refset) # Remove branches no longer needed if prune_refset: git.push('gerrit', refspecs=prune_refset) finally: # Change to old current working directory os.chdir(old_cwd) # Attempt to clean up created directory shutil.rmtree(repo_dir)
def _config(self, remote, conf, groups): """ Builds the groups file and project.config file for a project. @param remote - gerrit.Remote object @param conf - Dict containing git config information @param groups - List of groups """ if not self.config: return msg = "Project %s: Configuring." % self.name logger.info(msg) print msg repo_dir = '~/tmp' repo_dir = os.path.expanduser(repo_dir) repo_dir = os.path.abspath(repo_dir) uuid_dir = str(uuid4()) repo_dir = os.path.join(repo_dir, uuid_dir) # Make Empty directory - We want this to stop and fail on OSError logger.debug( "Project %s: Creating directory %s" % (self.name, repo_dir) ) os.makedirs(repo_dir) # Save the current working directory old_cwd = os.getcwd() origin = 'origin' try: # Change cwd to that repo os.chdir(repo_dir) # Git init empty directory git.init() # Add remote origin ssh_url = 'ssh://%s@%s:%s/%s' % ( remote.username, remote.host, remote.port, self.name ) git.add_remote(origin, ssh_url) # Fetch refs/meta/config for project refspec = 'refs/meta/config:refs/remotes/origin/meta/config' git.fetch(origin, refspec) # Checkout refs/meta/config git.checkout_branch('meta/config') # Get md5 of existing config _file = os.path.join(repo_dir, 'project.config') contents = '' try: with open(_file, 'r') as f: contents = f.read() except IOError: pass existing_md5 = hashlib.md5(contents).hexdigest() # Get md5 of new config with open(self.config, 'r') as f: contents = f.read() new_md5 = hashlib.md5(contents).hexdigest() msg = "Project %s: Md5 comparision\n%s\n%s" msg = msg % (self.name, existing_md5, new_md5) logger.debug(msg) print msg # Only alter if checksums do not match if existing_md5 != new_md5: logger.debug( "Project %s: config md5's are different." % self.name ) # Update project.config file _file = os.path.join(repo_dir, 'project.config') with open(_file, 'w') as f: f.write(contents) # Update groups file group_contents = groups_file_contents(groups) _file = os.path.join(repo_dir, 'groups') with open(_file, 'w') as f: f.write(group_contents) # Git config user.email git.set_config('user.email', conf['git-config']['email']) # Git config user.name git.set_config('user.name', conf['git-config']['name']) # Add groups and project.config git.add(['groups', 'project.config']) # Git commit git.commit(message='Setting up %s' % self.name) # Git push git.push(origin, refspecs='meta/config:refs/meta/config') logger.info("Project %s: pushed configuration." % self.name) else: msg = "Project %s: config unchanged." % self.name logger.info(msg) print msg finally: # Change to old current working directory os.chdir(old_cwd) # Attempt to clean up created directory shutil.rmtree(repo_dir)
def send_upstream(self, downstream, upstream): """ Sends the change indicated by the comment upstream. @param downstream - gerrit.Remote downstream object @param upstream - gerrit.Remote upstream object """ # Check if upstream project before doing anything. if not self.is_upstream_project(): return ssh = downstream.SSH() # Check to see if comment indicates a change is upstream ready if not self.is_upstream_indicated(): logger.debug("Change %s: Upstream not indicated" % self.change_id) return # Grab all of the approvals approvals = self.get_approvals(downstream.SSH()) # Check to see if comment has necessary approvals. if not self.is_upstream_approved(approvals): msg = ("Could not send to upstream: One or more labels" " not approved.") logger.debug("Change %s: %s" % (self.change_id, msg)) ssh.exec_once('gerrit review -m %s %s' % (pipes.quote(msg), self.revision)) return # Do some git stuffs to push upstream logger.debug("Change %s: Sending to upstream" % self.change_id) repo_dir = '~/tmp' repo_dir = os.path.expanduser(repo_dir) repo_dir = os.path.abspath(repo_dir) # Add uuid, want a unique directory here uuid_dir = str(uuid4()) repo_dir = os.path.join(repo_dir, uuid_dir) # Make Empty directory - We want this to stop and fail on OSError if not os.path.isdir(repo_dir): os.makedirs(repo_dir) logger.debug("Change %s: Created directory %s" % (self.change_id, repo_dir)) # Save the current working directory old_cwd = os.getcwd() try: # Change to newly created directory. os.chdir(repo_dir) # Init the cwd git.init() # Add the remotes for upstream and downstream remote_url = "ssh://%s@%s:%s/%s" git.add_remote( 'downstream', remote_url % (downstream.username, downstream.host, downstream.port, self.project)) # Figure out what user we will pose as # This every upstream user sharing the same key is kinda shady. # Default back to the configured user if username doesnt exist. # should fail in this case username = self.change_owner_username name = self.change_owner_name email = self.change_owner_email if not username: logger.debug("Change %s: Unable to use author credentials." " Defaulting to configured credentials." % self.change_id) username = upstream.username name = self._conf['git-config']['name'] email = self._conf['git-config']['email'] git.add_remote( 'upstream', remote_url % (username, upstream.host, upstream.port, self.project)) logger.debug('Change %s: Sending upstream as ' 'username %s, email %s, name %s' % (self.change_id, username, email, name)) try: env = get_review_env() # Set committer info git.set_config('user.email', email) git.set_config('user.name', name) # Download specific change to local args = [ 'git-review', '-r', 'downstream', '-d', '%s,%s' % (self.change_id, self.patchset_id) ] logger.debug('Change %s: running: %s' % (self.change_id, ' '.join(args))) out = subprocess.check_output(args, stderr=subprocess.STDOUT, env=env) logger.debug("Change %s: %s" % (self.change_id, out)) # Send downloaded change to upstream args = [ 'git-review', '-y', '-r', 'upstream', self.branch, '-t', self.topic ] logger.debug('Change %s: running: %s' % (self.change_id, ' '.join(args))) out = subprocess.check_output(args, stderr=subprocess.STDOUT, env=env) logger.debug("Change %s: %s" % (self.change_id, out)) upstream_url = self.get_upstream_url(upstream) msg = 'Sent to upstream: %s' % (upstream_url) # Send comment to downstream gerrit with link to change in # upstream gerrit ssh.exec_once('gerrit review -m %s %s' % (pipes.quote(msg), self.revision)) except subprocess.CalledProcessError as e: msg = "Could not send to upstream:\n%s" % e.output ssh.exec_once('gerrit review -m %s %s' % (pipes.quote(msg), self.revision)) logger.error("Change %s: Unable to send to upstream" % self.change_id) logger.error("Change %s: %s" % (self.change_id, out)) except Exception: msg = 'Could not send to upstream: Error running git-review' ssh.exec_once('gerrit review -m %s %s' % (pipes.quote(msg), self.revision)) logger.exception("Change %s: Unable to send to upstream" % self.change_id) finally: # Change to old current working directory os.chdir(old_cwd) # Attempt to clean up created directory shutil.rmtree(repo_dir)
def _sync(self, remote): """ Pushes all normal branches from a source repo to gerrit. @param remote - gerrit.Remote object """ # Only sync if source repo is provided. if not self.source: return # Only sync if heads and/or tags are specified if not self.heads and not self.tags: return msg = "Project %s: syncing with repo %s." % (self.name, self.source) logger.info(msg) print msg repo_dir = '~/tmp' repo_dir = os.path.expanduser(repo_dir) repo_dir = os.path.abspath(repo_dir) # Make Empty directory - We want this to stop and fail on OSError if not os.path.isdir(repo_dir): os.makedirs(repo_dir) logger.debug("Project %s: Created directory %s" % (self.name, repo_dir)) # Save the current working directory old_cwd = os.getcwd() try: # Change cwd to that repo os.chdir(repo_dir) uuid_dir = str(uuid4()) repo_dir = os.path.join(repo_dir, uuid_dir) # Do a git clone --bare <source_repo> git.clone(self.source, name=uuid_dir, bare=True) # Change to bare cloned directory os.chdir(uuid_dir) # Add remote named gerrit ssh_url = 'ssh://%s@%s:%s/%s' % (remote.username, remote.host, remote.port, self.name) git.add_remote('gerrit', ssh_url) # Push heads if self.heads: kwargs = {'all_': True} if self.force: kwargs['force'] = True git.push('gerrit', **kwargs) # Push tags if self.tags: kwargs = {'tags': True} if self.force: kwargs['force'] = True git.push('gerrit', **kwargs) ref_kwargs = self.ref_kwargs() # Grab origin refs origin_refset = git.remote_refs('origin', **ref_kwargs) # Grab gerrit refs gerrit_refset = git.remote_refs('gerrit', **ref_kwargs) # Find refs that should be removed. prune_refset = gerrit_refset - origin_refset if self.preserve_prefix: msg = "Project %s: Preserving refs with prefixes of %s" \ % (self.name, self.preserve_prefix) logger.debug(msg) print msg heads_prefix = "refs/heads/%s" % self.preserve_prefix tags_prefix = "refs/tags/%s" % self.preserve_prefix keep = lambda ref: not ref.startswith(heads_prefix) and \ not ref.startswith(tags_prefix) prune_refset = filter(keep, prune_refset) # Prefix each ref in refset with ':' to delete colonize = lambda ref: ':%s' % ref prune_refset = map(colonize, prune_refset) # Remove branches no longer needed if prune_refset: git.push('gerrit', refspecs=prune_refset) finally: # Change to old current working directory os.chdir(old_cwd) # Attempt to clean up created directory shutil.rmtree(repo_dir)
def _config(self, remote, conf, groups): """ Builds the groups file and project.config file for a project. @param remote - gerrit.Remote object @param conf - Dict containing git config information @param groups - List of groups """ if not self.config: return msg = "Project %s: Configuring." % self.name logger.info(msg) print msg repo_dir = '~/tmp' repo_dir = os.path.expanduser(repo_dir) repo_dir = os.path.abspath(repo_dir) uuid_dir = str(uuid4()) repo_dir = os.path.join(repo_dir, uuid_dir) # Make Empty directory - We want this to stop and fail on OSError logger.debug("Project %s: Creating directory %s" % (self.name, repo_dir)) os.makedirs(repo_dir) # Save the current working directory old_cwd = os.getcwd() origin = 'origin' try: # Change cwd to that repo os.chdir(repo_dir) # Git init empty directory git.init() # Add remote origin ssh_url = 'ssh://%s@%s:%s/%s' % (remote.username, remote.host, remote.port, self.name) git.add_remote(origin, ssh_url) # Fetch refs/meta/config for project refspec = 'refs/meta/config:refs/remotes/origin/meta/config' git.fetch(origin, refspec) # Checkout refs/meta/config git.checkout_branch('meta/config') # Get md5 of existing config _file = os.path.join(repo_dir, 'project.config') contents = '' try: with open(_file, 'r') as f: contents = f.read() except IOError: pass existing_md5 = hashlib.md5(contents).hexdigest() # Get md5 of new config with open(self.config, 'r') as f: contents = f.read() new_md5 = hashlib.md5(contents).hexdigest() msg = "Project %s: Md5 comparision\n%s\n%s" msg = msg % (self.name, existing_md5, new_md5) logger.debug(msg) print msg # Only alter if checksums do not match if existing_md5 != new_md5: logger.debug("Project %s: config md5's are different." % self.name) # Update project.config file _file = os.path.join(repo_dir, 'project.config') with open(_file, 'w') as f: f.write(contents) # Update groups file group_contents = groups_file_contents(groups) _file = os.path.join(repo_dir, 'groups') with open(_file, 'w') as f: f.write(group_contents) # Git config user.email git.set_config('user.email', conf['git-config']['email']) # Git config user.name git.set_config('user.name', conf['git-config']['name']) # Add groups and project.config git.add(['groups', 'project.config']) # Git commit git.commit(message='Setting up %s' % self.name) # Git push git.push(origin, refspecs='meta/config:refs/meta/config') logger.info("Project %s: pushed configuration." % self.name) else: msg = "Project %s: config unchanged." % self.name logger.info(msg) print msg finally: # Change to old current working directory os.chdir(old_cwd) # Attempt to clean up created directory shutil.rmtree(repo_dir)