def updateFromSSH(self, data, connection): if self.patchset is None: self.patchset = str(data['currentPatchSet']['number']) if 'project' not in data: raise exceptions.ChangeNotFound(self.number, self.patchset) self.project = connection.source.getProject(data['project']) self.commit_id = str(data['currentPatchSet']['revision']) self.branch = data['branch'] self.url = data['url'] urlparse = urllib.parse.urlparse(connection.baseurl) baseurl = "%s://%s%s" % (urlparse.scheme, urlparse.netloc, urlparse.path) baseurl = baseurl.rstrip('/') self.uris = [ '%s/%s' % (baseurl, self.number), '%s/#/c/%s' % (baseurl, self.number), '%s/c/%s/+/%s' % (baseurl, self.project.name, self.number), ] max_ps = 0 files = [] for ps in data['patchSets']: if str(ps['number']) == self.patchset: self.ref = ps['ref'] self.commit = ps['revision'] for f in ps.get('files', []): files.append(f['file']) if int(ps['number']) > int(max_ps): max_ps = str(ps['number']) if max_ps == self.patchset: self.is_current_patchset = True else: self.is_current_patchset = False self.files = files self.id = data['id'] self.is_merged = data.get('status', '') == 'MERGED' self.approvals = data['currentPatchSet'].get('approvals', []) self.open = data['open'] self.status = data['status'] self.wip = data.get('wip', False) self.owner = data['owner'].get('username') self.message = data['commitMessage'] self.missing_labels = set() for sr in data.get('submitRecords', []): if sr['status'] == 'NOT_READY': for label in sr['labels']: if label['status'] in ['OK', 'MAY']: continue elif label['status'] in ['NEED', 'REJECT']: self.missing_labels.add(label['label'])
def _updateChange(self, change, history=None): # In case this change is already in the history we have a # cyclic dependency and don't need to update ourselves again # as this gets done in a previous frame of the call stack. # NOTE(jeblair): The only case where this can still be hit is # when we get an event for a change with no associated # patchset; for instance, when the gerrit topic is changed. # In that case, we will update change 1234,None, which will be # inserted into the cache as its own entry, but then we will # resolve the patchset before adding it to the history list, # then if there are dependencies, we can walk down and then # back up to the version of this change with a patchset which # will match the history list but will have bypassed the # change cache because the previous object had a patchset of # None. All paths hit the change cache first. To be able to # drop history, we need to resolve the patchset on events with # no patchsets before adding the entry to the change cache. if (history and change.number and change.patchset and (change.number, change.patchset) in history): self.log.debug("Change %s is in history" % (change,)) return change self.log.info("Updating %s" % (change,)) data = self.query(change.number) change._data = data if change.patchset is None: change.patchset = str(data['currentPatchSet']['number']) if 'project' not in data: raise exceptions.ChangeNotFound(change.number, change.patchset) change.project = self.source.getProject(data['project']) change.id = data['id'] change.branch = data['branch'] change.url = data['url'] urlparse = urllib.parse.urlparse(self.baseurl) baseurl = "%s%s" % (urlparse.netloc, urlparse.path) baseurl = baseurl.rstrip('/') change.uris = [ '%s/%s' % (baseurl, change.number), '%s/#/c/%s' % (baseurl, change.number), ] max_ps = 0 files = [] for ps in data['patchSets']: if str(ps['number']) == change.patchset: change.ref = ps['ref'] change.commit = ps['revision'] for f in ps.get('files', []): files.append(f['file']) if int(ps['number']) > int(max_ps): max_ps = str(ps['number']) if max_ps == change.patchset: change.is_current_patchset = True else: change.is_current_patchset = False change.files = files change.is_merged = self._isMerged(change) change.approvals = data['currentPatchSet'].get('approvals', []) change.open = data['open'] change.status = data['status'] change.owner = data['owner'] change.message = data['commitMessage'] if change.is_merged: # This change is merged, so we don't need to look any further # for dependencies. self.log.debug("Updating %s: change is merged" % (change,)) return change if history is None: history = [] else: history = history[:] history.append((change.number, change.patchset)) needs_changes = set() git_needs_changes = [] if 'dependsOn' in data: parts = data['dependsOn'][0]['ref'].split('/') dep_num, dep_ps = parts[3], parts[4] self.log.debug("Updating %s: Getting git-dependent change %s,%s" % (change, dep_num, dep_ps)) dep = self._getChange(dep_num, dep_ps, history=history) # This is a git commit dependency. So we only ignore it if it is # already merged. So even if it is "ABANDONED", we should not # ignore it. if (not dep.is_merged) and dep not in needs_changes: git_needs_changes.append(dep) needs_changes.add(dep) change.git_needs_changes = git_needs_changes compat_needs_changes = [] for record in self._getDependsOnFromCommit(data['commitMessage'], change): dep_num = str(record['number']) dep_ps = str(record['currentPatchSet']['number']) self.log.debug("Updating %s: Getting commit-dependent " "change %s,%s" % (change, dep_num, dep_ps)) dep = self._getChange(dep_num, dep_ps, history=history) if dep.open and dep not in needs_changes: compat_needs_changes.append(dep) needs_changes.add(dep) change.compat_needs_changes = compat_needs_changes needed_by_changes = set() git_needed_by_changes = [] if 'neededBy' in data: for needed in data['neededBy']: parts = needed['ref'].split('/') dep_num, dep_ps = parts[3], parts[4] self.log.debug("Updating %s: Getting git-needed change %s,%s" % (change, dep_num, dep_ps)) dep = self._getChange(dep_num, dep_ps, history=history) if (dep.open and dep.is_current_patchset and dep not in needed_by_changes): git_needed_by_changes.append(dep) needed_by_changes.add(dep) change.git_needed_by_changes = git_needed_by_changes compat_needed_by_changes = [] for record in self._getNeededByFromCommit(data['id'], change): dep_num = str(record['number']) dep_ps = str(record['currentPatchSet']['number']) self.log.debug("Updating %s: Getting commit-needed change %s,%s" % (change, dep_num, dep_ps)) # Because a commit needed-by may be a cross-repo # dependency, cause that change to refresh so that it will # reference the latest patchset of its Depends-On (this # change). In case the dep is already in history we already # refreshed this change so refresh is not needed in this case. refresh = (dep_num, dep_ps) not in history dep = self._getChange( dep_num, dep_ps, refresh=refresh, history=history) if (dep.open and dep.is_current_patchset and dep not in needed_by_changes): compat_needed_by_changes.append(dep) needed_by_changes.add(dep) change.compat_needed_by_changes = compat_needed_by_changes self.sched.onChangeUpdated(change) return change
def _updateChange(self, change, history=None): self.log.info("Updating %s" % (change, )) data = self.connection.query(change.number) change._data = data if change.patchset is None: change.patchset = str(data['currentPatchSet']['number']) if 'project' not in data: found = False start = time.time() while time.time() - start < 75: self.log.info("Change %s not found, retrying" % (change, )) data = self.connection.query(change.number) self.log.debug("Change replication retry debug: %s" % data) if 'project' in data: found = True break time.sleep(self.replication_retry_interval) if not found: raise exceptions.ChangeNotFound(change.number, change.patchset) change._data = data change.project = self.sched.getProject(data['project']) change.branch = data['branch'] change.url = data['url'] max_ps = 0 files = [] for ps in data['patchSets']: if int(ps['number']) == int(change.patchset): change.refspec = ps['ref'] for f in ps.get('files', []): files.append(f['file']) if int(ps['number']) > int(max_ps): max_ps = ps['number'] if int(max_ps) == int(change.patchset): change.is_current_patchset = True else: change.is_current_patchset = False change.files = files change.is_merged = self._isMerged(change) change.approvals = data['currentPatchSet'].get('approvals', []) change.open = data['open'] change.status = data['status'] change.owner = data['owner'] change.wip = data.get('wip', False) change.private = data.get('private', False) if change.is_merged: # This change is merged, so we don't need to look any further # for dependencies. self.log.debug("Updating %s: change is merged" % (change, )) return change if history is None: history = [] else: history = history[:] history.append(change.number) needs_changes = [] if 'dependsOn' in data: parts = data['dependsOn'][0]['ref'].split('/') dep_num, dep_ps = parts[3], parts[4] if dep_num in history: raise Exception("Dependency cycle detected: %s in %s" % (dep_num, history)) self.log.debug("Updating %s: Getting git-dependent change %s,%s" % (change, dep_num, dep_ps)) dep = self._getChange(dep_num, dep_ps, history=history) # Because we are not forcing a refresh in _getChange, it # may return without executing this code, so if we are # updating our change to add ourselves to a dependency # cycle, we won't detect it. By explicitly performing a # walk of the dependency tree, we will. detect_cycle(dep, history) # This is a git commit dependency. So we only ignore it if it is # already merged. So even if it is "ABANDONED", we should not # ignore it. if (not dep.is_merged) and dep not in needs_changes: needs_changes.append(dep) for record in self._getDependsOnFromCommit(data['commitMessage'], change): dep_num = record['number'] dep_ps = record['currentPatchSet']['number'] if dep_num in history: raise Exception("Dependency cycle detected: %s in %s" % (dep_num, history)) self.log.debug("Updating %s: Getting commit-dependent " "change %s,%s" % (change, dep_num, dep_ps)) dep = self._getChange(dep_num, dep_ps, history=history) # Because we are not forcing a refresh in _getChange, it # may return without executing this code, so if we are # updating our change to add ourselves to a dependency # cycle, we won't detect it. By explicitly performing a # walk of the dependency tree, we will. detect_cycle(dep, history) if dep.open and dep not in needs_changes: needs_changes.append(dep) change.needs_changes = needs_changes needed_by_changes = [] if 'neededBy' in data: for needed in data['neededBy']: parts = needed['ref'].split('/') dep_num, dep_ps = parts[3], parts[4] self.log.debug("Updating %s: Getting git-needed change %s,%s" % (change, dep_num, dep_ps)) dep = self._getChange(dep_num, dep_ps) if dep.open and dep.is_current_patchset: needed_by_changes.append(dep) for record in self._getNeededByFromCommit(data['id'], change): dep_num = record['number'] dep_ps = record['currentPatchSet']['number'] self.log.debug("Updating %s: Getting commit-needed change %s,%s" % (change, dep_num, dep_ps)) # Because a commit needed-by may be a cross-repo # dependency, cause that change to refresh so that it will # reference the latest patchset of its Depends-On (this # change). dep = self._getChange(dep_num, dep_ps, refresh=True) if dep.open and dep.is_current_patchset: needed_by_changes.append(dep) change.needed_by_changes = needed_by_changes return change
def _updateChange(self, change, history=None): self.log.info("Updating information for %s,%s" % (change.number, change.patchset)) data = self.connection.query(change.number) change._data = data if change.patchset is None: change.patchset = data['currentPatchSet']['number'] if 'project' not in data: raise exceptions.ChangeNotFound(change.number, change.patchset) # If updated changed came as a dependent on # and its project is not defined, # then create a 'foreign' project for it in layout change.project = self.sched.getProject(data['project'], create_foreign=bool(history)) change.branch = data['branch'] change.url = data['url'] max_ps = 0 files = [] for ps in data['patchSets']: if ps['number'] == change.patchset: change.refspec = ps['ref'] for f in ps.get('files', []): files.append(f['file']) if int(ps['number']) > int(max_ps): max_ps = ps['number'] if max_ps == change.patchset: change.is_current_patchset = True else: change.is_current_patchset = False change.files = files change.is_merged = self._isMerged(change) change.approvals = data['currentPatchSet'].get('approvals', []) change.open = data['open'] change.status = data['status'] change.owner = data['owner'] if change.is_merged: # This change is merged, so we don't need to look any further # for dependencies. return change if history is None: history = [] else: history = history[:] history.append(change.number) needs_changes = [] if 'dependsOn' in data: parts = data['dependsOn'][0]['ref'].split('/') dep_num, dep_ps = parts[3], parts[4] if dep_num in history: raise Exception("Dependency cycle detected: %s in %s" % (dep_num, history)) self.log.debug("Getting git-dependent change %s,%s" % (dep_num, dep_ps)) dep = self._getChange(dep_num, dep_ps, history=history) if (not dep.is_merged) and dep not in needs_changes: needs_changes.append(dep) for record in self._getDependsOnFromCommit(data['commitMessage']): dep_num = record['number'] dep_ps = record['currentPatchSet']['number'] if dep_num in history: raise Exception("Dependency cycle detected: %s in %s" % (dep_num, history)) self.log.debug("Getting commit-dependent change %s,%s" % (dep_num, dep_ps)) dep = self._getChange(dep_num, dep_ps, history=history) if (not dep.is_merged) and dep not in needs_changes: needs_changes.append(dep) change.needs_changes = needs_changes needed_by_changes = [] if 'neededBy' in data: for needed in data['neededBy']: parts = needed['ref'].split('/') dep_num, dep_ps = parts[3], parts[4] dep = self._getChange(dep_num, dep_ps) if (not dep.is_merged) and dep.is_current_patchset: needed_by_changes.append(dep) for record in self._getNeededByFromCommit(data['id']): dep_num = record['number'] dep_ps = record['currentPatchSet']['number'] self.log.debug("Getting commit-needed change %s,%s" % (dep_num, dep_ps)) # Because a commit needed-by may be a cross-repo # dependency, cause that change to refresh so that it will # reference the latest patchset of its Depends-On (this # change). dep = self._getChange(dep_num, dep_ps, refresh=True) if (not dep.is_merged) and dep.is_current_patchset: needed_by_changes.append(dep) change.needed_by_changes = needed_by_changes return change