{"action":"created","comment":{"url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/pulls/comments/63368755","id":63368755,"diff_hunk":"@@ -0,0 +1,176 @@\n+/*\n+ * The MIT License\n+ *\n+ * Copyright (c) 2016, CloudBees, Inc.\n+ *\n+ * Permission is hereby granted, free of charge, to any person obtaining a copy\n+ * of this software and associated documentation files (the \"Software\"), to deal\n+ * in the Software without restriction, including without limitation the rights\n+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n+ * copies of the Software, and to permit persons to whom the Software is\n+ * furnished to do so, subject to the following conditions:\n+ *\n+ * The above copyright notice and this permission notice shall be included in\n+ * all copies or substantial portions of the Software.\n+ *\n+ * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n+ * THE SOFTWARE.\n+ */\n+\n+package org.jenkinsci.plugins.workflow.graphanalysis;\n+\n+import org.jenkinsci.plugins.workflow.graph.BlockEndNode;\n+import org.jenkinsci.plugins.workflow.graph.BlockStartNode;\n+import org.jenkinsci.plugins.workflow.graph.FlowNode;\n+\n+import javax.annotation.Nonnull;\n+import java.util.ArrayDeque;\n+import java.util.Collection;\n+import java.util.List;\n+\n+/**\n+ * Scanner that will scan down forks when we hit parallel blocks.\n+ * Think of it as the opposite of {@link DepthFirstScanner}:\n+ *   - We visit every node exactly once, but walk through all parallel forks before resuming the main flow\n+ *\n+ * This is near-optimal in many cases, since it keeps minimal state information and explores parallel blocks first\n+ * It is also very easy to make it branch/block-aware, since we have all the fork information at all times.\n+ * @author <samvanoort@gmail.com>Sam Van Oort</samvanoort@gmail.com>\n+ */\n+public class ForkScanner extends AbstractFlowScanner {\n+\n+    /** These are the BlockStartNodes that begin parallel blocks\n+     *  There will be one entry for every executing parallel branch in current flow\n+     */\n+    ArrayDeque<FlowNode> forkStarts = new ArrayDeque<FlowNode>();\n+\n+    /** FlowNode that will terminate the current parallel block */\n+    FlowNode currentParallelStart = null;\n+\n+    /** How deep are we in parallel branches, if 0 we are linear */\n+    protected int parallelDepth = 0;\n+\n+    @Override\n+    protected void reset() {\n+        if (_queue == null) {\n+            _queue = new ArrayDeque<FlowNode>();\n+        } else {\n+            _queue.clear();\n+        }\n+        forkStarts.clear();\n+        parallelDepth =0;\n+        currentParallelStart = null;\n+        _current = null;\n+        _next = null;\n+    }\n+\n+    @Override\n+    protected void setHeads(@Nonnull Collection<FlowNode> heads) {\n+        if (heads.size() > 1) {\n+            throw new IllegalArgumentException(\"ForkedFlowScanner can't handle multiple head nodes yet\");","path":"src/main/java/org/jenkinsci/plugins/workflow/graphanalysis/ForkScanner.java","position":75,"original_position":75,"commit_id":"b90e87869ab5fee5be3ebc13f09274c02a803696","original_commit_id":"b90e87869ab5fee5be3ebc13f09274c02a803696","user":{"login":"svanoort","id":5400948,"avatar_url":"https://avatars.githubusercontent.com/u/5400948?v=3","gravatar_id":"","url":"https://api.github.com/users/svanoort","html_url":"https://github.com/svanoort","followers_url":"https://api.github.com/users/svanoort/followers","following_url":"https://api.github.com/users/svanoort/following{/other_user}","gists_url":"https://api.github.com/users/svanoort/gists{/gist_id}","starred_url":"https://api.github.com/users/svanoort/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/svanoort/subscriptions","organizations_url":"https://api.github.com/users/svanoort/orgs","repos_url":"https://api.github.com/users/svanoort/repos","events_url":"https://api.github.com/users/svanoort/events{/privacy}","received_events_url":"https://api.github.com/users/svanoort/received_events","type":"User","site_admin":false},"body":"This is the final use case to handle.  I'm aware that it can't handle multiple heads yet: this should be the only remaining WIP component, but but it is quite complex to work with. ","created_at":"2016-05-16T15:08:03Z","updated_at":"2016-05-16T15:08:03Z","html_url":"https://github.com/jenkinsci/workflow-api-plugin/pull/2#discussion_r63368755","pull_request_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/pulls/2","_links":{"self":{"href":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/pulls/comments/63368755"},"html":{"href":"https://github.com/jenkinsci/workflow-api-plugin/pull/2#discussion_r63368755"},"pull_request":{"href":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/pulls/2"}}},"pull_request":{"url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/pulls/2","id":66425394,"html_url":"https://github.com/jenkinsci/workflow-api-plugin/pull/2","diff_url":"https://github.com/jenkinsci/workflow-api-plugin/pull/2.diff","patch_url":"https://github.com/jenkinsci/workflow-api-plugin/pull/2.patch","issue_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/issues/2","number":2,"state":"open","locked":false,"title":"Generified Flow Search Algorithms","user":{"login":"svanoort","id":5400948,"avatar_url":"https://avatars.githubusercontent.com/u/5400948?v=3","gravatar_id":"","url":"https://api.github.com/users/svanoort","html_url":"https://github.com/svanoort","followers_url":"https://api.github.com/users/svanoort/followers","following_url":"https://api.github.com/users/svanoort/following{/other_user}","gists_url":"https://api.github.com/users/svanoort/gists{/gist_id}","starred_url":"https://api.github.com/users/svanoort/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/svanoort/subscriptions","organizations_url":"https://api.github.com/users/svanoort/orgs","repos_url":"https://api.github.com/users/svanoort/repos","events_url":"https://api.github.com/users/svanoort/events{/privacy}","received_events_url":"https://api.github.com/users/svanoort/received_events","type":"User","site_admin":false},"body":"Provides a package of search/operation APIs for searching/analyzing flow graphs.\r\n\r\nThese are intended to be extensible for custom use cases, but provide a general API that covers what is needed. \r\n\r\nTODOs:\r\n- [x] findAllNodes: rename to 'filter'\r\n- [x] helper method to find next enclosing block. \r\n- [x] ForkScanner: handle blacklist nodes within forked blocks\r\n- [ ] Forkscanner: handle starting within parallel blocks (potentially nested)\r\n\r\nNotes:\r\n\r\n* Parallel blocks have their own LabelAction for each branch, a ParallelLabelAction on the StepStartNode beginning each branch, with displayname branch + displayname, and getThreadName that returns the label given to the branch, StepEndNode gives the timing too (and final state)\r\n\r\nGeneral use cases:\r\n* ErrorInfo - https://github.com/jenkinsci/workflow-basic-steps-plugin/pull/2 = https://issues.jenkins-ci.org/browse/JENKINS-28119\r\n   - Searching back for node emitting failure (ErrorAction), skips block end node because the blockendnode gets the final error action.\r\n  - Then does the walk back via blockjumping to get the nearest log action, and the nearest label too\r\n* [`WorkflowRun.getLogPrefix`](https://github.com/jenkinsci/workflow-job-plugin/blob/master/src/main/java/org/jenkinsci/plugins/workflow/job/WorkflowRun.java#L402-L426).\r\n* [Milestone step - JENKINS-27039](https://github.com/jenkinsci/pipeline-milestone-step-plugin/pull/1)\r\n  - Needs something like FlowGraphWalker but that bombs out on parallel -> optimal case for recursive breadth-first algorithm (planned but not implemented yet).  Caching not allowable probably.\r\n* Durable task step: search label/stage which uses a executor node.\r\n   - Good use case for caching or incremental caching. \r\n* Log search: nearest enclose start node with label for parallel\r\n\r\nPipeline Stage View:\r\n * Stage/node labels - the BlockJumpingScanner allows us to solve [JENKINS-33290](https://issues.jenkins-ci.org/browse/JENKINS-33290)\r\n*","created_at":"2016-04-14T03:47:14Z","updated_at":"2016-05-16T15:08:03Z","closed_at":null,"merged_at":null,"merge_commit_sha":"35006ec79f1dcedef154b9858b4f1b1182b9e43f","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/pulls/2/commits","review_comments_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/pulls/2/comments","review_comment_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/pulls/comments{/number}","comments_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/issues/2/comments","statuses_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/statuses/b90e87869ab5fee5be3ebc13f09274c02a803696","head":{"label":"jenkinsci:generic-flow-analyzer","ref":"generic-flow-analyzer","sha":"b90e87869ab5fee5be3ebc13f09274c02a803696","user":{"login":"jenkinsci","id":107424,"avatar_url":"https://avatars.githubusercontent.com/u/107424?v=3","gravatar_id":"","url":"https://api.github.com/users/jenkinsci","html_url":"https://github.com/jenkinsci","followers_url":"https://api.github.com/users/jenkinsci/followers","following_url":"https://api.github.com/users/jenkinsci/following{/other_user}","gists_url":"https://api.github.com/users/jenkinsci/gists{/gist_id}","starred_url":"https://api.github.com/users/jenkinsci/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jenkinsci/subscriptions","organizations_url":"https://api.github.com/users/jenkinsci/orgs","repos_url":"https://api.github.com/users/jenkinsci/repos","events_url":"https://api.github.com/users/jenkinsci/events{/privacy}","received_events_url":"https://api.github.com/users/jenkinsci/received_events","type":"Organization","site_admin":false},"repo":{"id":55527408,"name":"workflow-api-plugin","full_name":"jenkinsci/workflow-api-plugin","owner":{"login":"jenkinsci","id":107424,"avatar_url":"https://avatars.githubusercontent.com/u/107424?v=3","gravatar_id":"","url":"https://api.github.com/users/jenkinsci","html_url":"https://github.com/jenkinsci","followers_url":"https://api.github.com/users/jenkinsci/followers","following_url":"https://api.github.com/users/jenkinsci/following{/other_user}","gists_url":"https://api.github.com/users/jenkinsci/gists{/gist_id}","starred_url":"https://api.github.com/users/jenkinsci/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jenkinsci/subscriptions","organizations_url":"https://api.github.com/users/jenkinsci/orgs","repos_url":"https://api.github.com/users/jenkinsci/repos","events_url":"https://api.github.com/users/jenkinsci/events{/privacy}","received_events_url":"https://api.github.com/users/jenkinsci/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/jenkinsci/workflow-api-plugin","description":"","fork":false,"url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin","forks_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/forks","keys_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/teams","hooks_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/hooks","issue_events_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/issues/events{/number}","events_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/events","assignees_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/assignees{/user}","branches_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/branches{/branch}","tags_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/tags","blobs_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/git/refs{/sha}","trees_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/statuses/{sha}","languages_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/languages","stargazers_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/stargazers","contributors_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/contributors","subscribers_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/subscribers","subscription_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/subscription","commits_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/commits{/sha}","git_commits_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/git/commits{/sha}","comments_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/comments{/number}","issue_comment_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/issues/comments{/number}","contents_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/contents/{+path}","compare_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/merges","archive_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/downloads","issues_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/issues{/number}","pulls_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/pulls{/number}","milestones_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/milestones{/number}","notifications_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/labels{/name}","releases_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/releases{/id}","deployments_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/deployments","created_at":"2016-04-05T17:18:43Z","updated_at":"2016-05-05T09:51:45Z","pushed_at":"2016-05-03T21:10:25Z","git_url":"git://github.com/jenkinsci/workflow-api-plugin.git","ssh_url":"git@github.com:jenkinsci/workflow-api-plugin.git","clone_url":"https://github.com/jenkinsci/workflow-api-plugin.git","svn_url":"https://github.com/jenkinsci/workflow-api-plugin","homepage":"","size":277,"stargazers_count":1,"watchers_count":1,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":3,"mirror_url":null,"open_issues_count":3,"forks":3,"open_issues":3,"watchers":1,"default_branch":"master"}},"base":{"label":"jenkinsci:master","ref":"master","sha":"ac98823111bef74073501a3656ce0dfe6c199655","user":{"login":"jenkinsci","id":107424,"avatar_url":"https://avatars.githubusercontent.com/u/107424?v=3","gravatar_id":"","url":"https://api.github.com/users/jenkinsci","html_url":"https://github.com/jenkinsci","followers_url":"https://api.github.com/users/jenkinsci/followers","following_url":"https://api.github.com/users/jenkinsci/following{/other_user}","gists_url":"https://api.github.com/users/jenkinsci/gists{/gist_id}","starred_url":"https://api.github.com/users/jenkinsci/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jenkinsci/subscriptions","organizations_url":"https://api.github.com/users/jenkinsci/orgs","repos_url":"https://api.github.com/users/jenkinsci/repos","events_url":"https://api.github.com/users/jenkinsci/events{/privacy}","received_events_url":"https://api.github.com/users/jenkinsci/received_events","type":"Organization","site_admin":false},"repo":{"id":55527408,"name":"workflow-api-plugin","full_name":"jenkinsci/workflow-api-plugin","owner":{"login":"jenkinsci","id":107424,"avatar_url":"https://avatars.githubusercontent.com/u/107424?v=3","gravatar_id":"","url":"https://api.github.com/users/jenkinsci","html_url":"https://github.com/jenkinsci","followers_url":"https://api.github.com/users/jenkinsci/followers","following_url":"https://api.github.com/users/jenkinsci/following{/other_user}","gists_url":"https://api.github.com/users/jenkinsci/gists{/gist_id}","starred_url":"https://api.github.com/users/jenkinsci/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jenkinsci/subscriptions","organizations_url":"https://api.github.com/users/jenkinsci/orgs","repos_url":"https://api.github.com/users/jenkinsci/repos","events_url":"https://api.github.com/users/jenkinsci/events{/privacy}","received_events_url":"https://api.github.com/users/jenkinsci/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/jenkinsci/workflow-api-plugin","description":"","fork":false,"url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin","forks_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/forks","keys_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/teams","hooks_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/hooks","issue_events_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/issues/events{/number}","events_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/events","assignees_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/assignees{/user}","branches_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/branches{/branch}","tags_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/tags","blobs_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/git/refs{/sha}","trees_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/statuses/{sha}","languages_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/languages","stargazers_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/stargazers","contributors_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/contributors","subscribers_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/subscribers","subscription_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/subscription","commits_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/commits{/sha}","git_commits_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/git/commits{/sha}","comments_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/comments{/number}","issue_comment_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/issues/comments{/number}","contents_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/contents/{+path}","compare_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/merges","archive_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/downloads","issues_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/issues{/number}","pulls_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/pulls{/number}","milestones_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/milestones{/number}","notifications_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/labels{/name}","releases_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/releases{/id}","deployments_url":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/deployments","created_at":"2016-04-05T17:18:43Z","updated_at":"2016-05-05T09:51:45Z","pushed_at":"2016-05-03T21:10:25Z","git_url":"git://github.com/jenkinsci/workflow-api-plugin.git","ssh_url":"git@github.com:jenkinsci/workflow-api-plugin.git","clone_url":"https://github.com/jenkinsci/workflow-api-plugin.git","svn_url":"https://github.com/jenkinsci/workflow-api-plugin","homepage":"","size":277,"stargazers_count":1,"watchers_count":1,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":3,"mirror_url":null,"open_issues_count":3,"forks":3,"open_issues":3,"watchers":1,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/pulls/2"},"html":{"href":"https://github.com/jenkinsci/workflow-api-plugin/pull/2"},"issue":{"href":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/issues/2"},"comments":{"href":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/issues/2/comments"},"review_comments":{"href":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/pulls/2/comments"},"review_comment":{"href":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/pulls/2/commits"},"statuses":{"href":"https://api.github.com/repos/jenkinsci/workflow-api-plugin/statuses/b90e87869ab5fee5be3ebc13f09274c02a803696"}}}}