abolotnov
abolotnov

Reputation: 4332

python - traverse a graph (find all issues linked)

I'm bit stuck trying to solve a simple task of getting all linked issues. This is basically a graph task I guess - I take a jira issue, find all its links and then go to linked issues for their links until I've processed all issues.

The layout of jira isues I'm testing this with is as on the picture below: enter image description here

But the result is this:

PMO-100 -> SA-300
SA-100 -> SA-300
SA-100 -> SA-200

It is missing one link but it would miss a whole lot more because it only processes the first link from all found ones:

__init__       6996   Starting...
_new_conn      6996   Starting new HTTP connection (1): 10.48.34.174
collect_links  6996   Looking for links for issue PMO-100
collect_links  6996   Found 2 links: 27846, 27843
collect_links  6996   processing link 27846
put_link       6996   Appending link 27846 to link register
collect_links  6996   Looking for links for issue SA-300
collect_links  6996   Found 2 links: 27845, 27846
collect_links  6996   processing link 27845
put_link       6996   Appending link 27845 to link register
collect_links  6996   Looking for links for issue SA-100
collect_links  6996   Found 3 links: 27844, 27845, 27843
collect_links  6996   processing link 27844
put_link       6996   Appending link 27844 to link register
collect_links  6996   Looking for links for issue SA-200
collect_links  6996   Found 1 links: 27844
collect_links  6996   processing link 27844
put_link       6996   Link 27844 already exists in link register
collect_links  6996   issue SA-100 is already in tracked issues

This is happening because of the for ... each loop inside the collect_links method - whenever it's called it will override the for ... each collection:

def collect_links(self, key):
        logging.info('Looking for links for issue %s' % key)
        self.tracked.append(key)
        links = self.jac.issue(key).fields.issuelinks
        logging.info('Found %s links: %s' % (len(links), ', '.join(i.id for i in links)))
        for link in links:
            logging.info('processing link %s' % link.id)
            self.put_link(link)
            rel = None
            if hasattr(link, 'outwardIssue'):
                rel = link.outwardIssue.key
            else:
                rel = link.inwardIssue.key
            linked_issue = self.jac.issue(rel)
            if linked_issue.key not in self.tracked:
                return self.collect_links(linked_issue.key)
            else:
                logging.info('issue %s is already in tracked issues' % linked_issue.key)

It looks like when you call self.method from within the method itself, it will not create a new chunk of data for it but rather override the data you've already created inside the method - how do I overcome that?

What happens is:

for link in links: #links contains the links linked to current issue
    if linked_issue.key not in self.tracked:
        return self.collect_links(linked_issue.key) #links changes

on the last line I would expect it keeps my links collection untouched but it changes it to be a links collection for linked_issue.key

I've pasted the whole code on pastebin.

Upvotes: 1

Views: 551

Answers (1)

Armin Rigo
Armin Rigo

Reputation: 12955

Uh, unsure I understand your problem, but in case I do:

for link in links: #links contains the links linked to current issue
    if linked_issue.key not in self.tracked:
        return self.collect_links(linked_issue.key) #links changes

This will of course stop the for loop at the first untracked link. If you want to continue iterating through the remaining elements of links, you must not use a return statement here.

Upvotes: 1

Related Questions