{"action":"created","comment":{"url":"https://api.github.com/repos/spinnaker/orca/pulls/comments/134348234","pull_request_review_id":57629100,"id":134348234,"diff_hunk":"@@ -0,0 +1,342 @@\n+/*\n+ * Copyright 2017 Netflix, Inc.\n+ *\n+ * Licensed under the Apache License, Version 2.0 (the \"License\")\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ *   http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+package com.netflix.spinnaker.orca.pipeline.expressions;\n+\n+import com.fasterxml.jackson.databind.ObjectMapper;\n+import com.netflix.spinnaker.orca.pipeline.expressions.whitelisting.FilteredMethodResolver;\n+import com.netflix.spinnaker.orca.pipeline.expressions.whitelisting.FilteredPropertyAccessor;\n+import com.netflix.spinnaker.orca.pipeline.expressions.whitelisting.MapPropertyAccessor;\n+import com.netflix.spinnaker.orca.pipeline.expressions.whitelisting.WhitelistTypeLocator;\n+import com.netflix.spinnaker.orca.pipeline.model.Execution;\n+import com.netflix.spinnaker.orca.pipeline.model.Stage;\n+import com.netflix.spinnaker.orca.pipeline.util.ContextFunctionConfiguration;\n+import com.netflix.spinnaker.orca.pipeline.util.HttpClientUtils;\n+import org.slf4j.Logger;\n+import org.slf4j.LoggerFactory;\n+import org.springframework.expression.*;\n+import org.springframework.expression.common.TemplateParserContext;\n+import org.springframework.expression.spel.support.StandardEvaluationContext;\n+\n+import java.io.ByteArrayInputStream;\n+import java.io.IOException;\n+import java.io.UnsupportedEncodingException;\n+import java.net.URL;\n+import java.util.*;\n+import java.util.concurrent.atomic.AtomicReference;\n+import java.util.function.Predicate;\n+\n+/**\n+ * Provides utility support for SPEL integration\n+ * Supports registering SPEL functions, ACLs to classes (via whitelisting)\n+ */\n+\n+public class ExpressionsSupport {\n+  final static ParserContext parserContext = new TemplateParserContext(\"${\", \"}\");\n+  private static final Logger LOGGER = LoggerFactory.getLogger(ExpressionsSupport.class);\n+  private static final ObjectMapper mapper = new ObjectMapper();\n+  private static AtomicReference<ContextFunctionConfiguration> helperFunctionConfigurationAtomicReference = new AtomicReference<>();\n+  private static Map<String, List<Class<?>>> registeredHelperFunctions = new HashMap<>();\n+\n+  ExpressionsSupport(ContextFunctionConfiguration contextFunctionConfiguration) {\n+    helperFunctionConfigurationAtomicReference.set(contextFunctionConfiguration);\n+  }\n+\n+  static {\n+    registeredHelperFunctions.put(\"alphanumerical\", Collections.singletonList(String.class));\n+    registeredHelperFunctions.put(\"toJson\", Collections.singletonList(Object.class));\n+    registeredHelperFunctions.put(\"readJson\", Collections.singletonList(String.class));\n+    registeredHelperFunctions.put(\"toInt\", Collections.singletonList(String.class));\n+    registeredHelperFunctions.put(\"toFloat\", Collections.singletonList(String.class));\n+    registeredHelperFunctions.put(\"toBoolean\", Collections.singletonList(String.class));\n+    registeredHelperFunctions.put(\"toBase64\", Collections.singletonList(String.class));\n+    registeredHelperFunctions.put(\"fromBase64\", Collections.singletonList(String.class));\n+  }\n+\n+  /**\n+   * Internally registers a Spel method to an evaluation context\n+   * @throws NoSuchMethodException\n+   */\n+\n+  private static void registerFunction(StandardEvaluationContext context, String name, Class<?> ...types) throws NoSuchMethodException {\n+    context.registerFunction(name, ExpressionsSupport.class.getDeclaredMethod(name, types));\n+  }\n+\n+  /**\n+   * Creates a configured Spel evaluation context\n+   * @param rootObject the root object to transform\n+   * @param allowUnknownKeys flag to control what helper functions are available\n+   * @return an evaluation context hooked with helper functions and correct ACL via whitelisting\n+   */\n+\n+  static StandardEvaluationContext newEvaluationContext(Object rootObject, boolean allowUnknownKeys) {\n+    StandardEvaluationContext evaluationContext = new StandardEvaluationContext(rootObject);\n+    evaluationContext.setTypeLocator(new WhitelistTypeLocator());\n+    evaluationContext.setMethodResolvers(Collections.singletonList(new FilteredMethodResolver()));\n+    evaluationContext.setPropertyAccessors(Arrays.asList(new MapPropertyAccessor(allowUnknownKeys), new FilteredPropertyAccessor()));\n+\n+    try {\n+      for (Map.Entry<String, List<Class<?>>> m : registeredHelperFunctions.entrySet()) {\n+        registerFunction(evaluationContext, m.getKey(), m.getValue().toArray(new Class<?>[m.getValue().size()]));\n+      }\n+\n+      if (allowUnknownKeys) {\n+        // lazily function registering\n+        registerFunction(evaluationContext, \"fromUrl\", String.class);\n+        registerFunction(evaluationContext, \"jsonFromUrl\", String.class);\n+        registerFunction(evaluationContext, \"propertiesFromUrl\", String.class);\n+        registerFunction(evaluationContext, \"stage\", Object.class, String.class);\n+        registerFunction(evaluationContext, \"judgment\", Object.class, String.class);\n+        registerFunction(evaluationContext, \"judgement\", Object.class, String.class);\n+      }\n+    } catch (NoSuchMethodException e) {\n+      // Indicates a function was not properly registered. This should not happen. Please fix the faulty function\n+      LOGGER.error(\"Failed to register helper functions for rootObject {}\", rootObject, e);\n+    }\n+\n+    return evaluationContext;\n+  }\n+\n+  /*\n+    HELPER FUNCTIONS: These functions are explicitly registered with each invocation\n+    To add a new helper function, append the function below and update ExpressionHelperFunctions and registeredHelperFunctions\n+   */\n+\n+  /**\n+   * Parses a string to an integer\n+   * @param str represents an int\n+   * @return an integer\n+   */\n+\n+  public static Integer toInt(String str) {\n+    return Integer.valueOf(str);\n+  }\n+\n+  /**\n+   * Parses a string to a float\n+   * @param str represents an float\n+   * @return an float\n+   */\n+\n+  public static Float toFloat(String str) {\n+    return Float.valueOf(str);\n+  }\n+\n+  /**\n+   * Parses a string to a boolean\n+   * @param str represents an boolean\n+   * @return a boolean\n+   */\n+\n+  public static Boolean toBoolean(String str) {\n+    return Boolean.valueOf(str);\n+  }\n+\n+  /**\n+   * Encodes a string to base64\n+   * @param text plain string\n+   * @return converted string\n+   */\n+","path":"orca-core/src/main/groovy/com/netflix/spinnaker/orca/pipeline/expressions/ExpressionsSupport.java","position":153,"original_position":153,"commit_id":"d38bf7cbc6e33ab65c1d282e3e0fe0b854719625","original_commit_id":"d38bf7cbc6e33ab65c1d282e3e0fe0b854719625","user":{"login":"robzienert","id":108741,"avatar_url":"https://avatars0.githubusercontent.com/u/108741?v=4","gravatar_id":"","url":"https://api.github.com/users/robzienert","html_url":"https://github.com/robzienert","followers_url":"https://api.github.com/users/robzienert/followers","following_url":"https://api.github.com/users/robzienert/following{/other_user}","gists_url":"https://api.github.com/users/robzienert/gists{/gist_id}","starred_url":"https://api.github.com/users/robzienert/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/robzienert/subscriptions","organizations_url":"https://api.github.com/users/robzienert/orgs","repos_url":"https://api.github.com/users/robzienert/repos","events_url":"https://api.github.com/users/robzienert/events{/privacy}","received_events_url":"https://api.github.com/users/robzienert/received_events","type":"User","site_admin":false},"body":"Primarily from a consistency perspective: It's very atypical; certainly not something we do anywhere else in our projects.","created_at":"2017-08-21T22:42:47Z","updated_at":"2017-08-21T22:42:48Z","html_url":"https://github.com/spinnaker/orca/pull/1560#discussion_r134348234","pull_request_url":"https://api.github.com/repos/spinnaker/orca/pulls/1560","_links":{"self":{"href":"https://api.github.com/repos/spinnaker/orca/pulls/comments/134348234"},"html":{"href":"https://github.com/spinnaker/orca/pull/1560#discussion_r134348234"},"pull_request":{"href":"https://api.github.com/repos/spinnaker/orca/pulls/1560"}}},"pull_request":{"url":"https://api.github.com/repos/spinnaker/orca/pulls/1560","id":136821523,"html_url":"https://github.com/spinnaker/orca/pull/1560","diff_url":"https://github.com/spinnaker/orca/pull/1560.diff","patch_url":"https://github.com/spinnaker/orca/pull/1560.patch","issue_url":"https://api.github.com/repos/spinnaker/orca/issues/1560","number":1560,"state":"open","locked":false,"title":"feat(pipelineexpressions): Adding a v2 expressions evaluator","user":{"login":"jeyrschabu","id":1572759,"avatar_url":"https://avatars3.githubusercontent.com/u/1572759?v=4","gravatar_id":"","url":"https://api.github.com/users/jeyrschabu","html_url":"https://github.com/jeyrschabu","followers_url":"https://api.github.com/users/jeyrschabu/followers","following_url":"https://api.github.com/users/jeyrschabu/following{/other_user}","gists_url":"https://api.github.com/users/jeyrschabu/gists{/gist_id}","starred_url":"https://api.github.com/users/jeyrschabu/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jeyrschabu/subscriptions","organizations_url":"https://api.github.com/users/jeyrschabu/orgs","repos_url":"https://api.github.com/users/jeyrschabu/repos","events_url":"https://api.github.com/users/jeyrschabu/events{/privacy}","received_events_url":"https://api.github.com/users/jeyrschabu/received_events","type":"User","site_admin":false},"body":"- Extracted expressions evaluation to new package\r\n- Exposing expression failures via a detailed summary\r\n- Added support for flagging a pipeline to be processed with v2\r\n","created_at":"2017-08-21T18:59:36Z","updated_at":"2017-08-21T22:42:48Z","closed_at":null,"merged_at":null,"merge_commit_sha":"f5a7fae6b6e4fd8e4c22aa620fba9de928875d46","assignee":null,"assignees":[],"requested_reviewers":[],"milestone":null,"commits_url":"https://api.github.com/repos/spinnaker/orca/pulls/1560/commits","review_comments_url":"https://api.github.com/repos/spinnaker/orca/pulls/1560/comments","review_comment_url":"https://api.github.com/repos/spinnaker/orca/pulls/comments{/number}","comments_url":"https://api.github.com/repos/spinnaker/orca/issues/1560/comments","statuses_url":"https://api.github.com/repos/spinnaker/orca/statuses/d38bf7cbc6e33ab65c1d282e3e0fe0b854719625","head":{"label":"jeyrschabu:orca_expressions","ref":"orca_expressions","sha":"d38bf7cbc6e33ab65c1d282e3e0fe0b854719625","user":{"login":"jeyrschabu","id":1572759,"avatar_url":"https://avatars3.githubusercontent.com/u/1572759?v=4","gravatar_id":"","url":"https://api.github.com/users/jeyrschabu","html_url":"https://github.com/jeyrschabu","followers_url":"https://api.github.com/users/jeyrschabu/followers","following_url":"https://api.github.com/users/jeyrschabu/following{/other_user}","gists_url":"https://api.github.com/users/jeyrschabu/gists{/gist_id}","starred_url":"https://api.github.com/users/jeyrschabu/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jeyrschabu/subscriptions","organizations_url":"https://api.github.com/users/jeyrschabu/orgs","repos_url":"https://api.github.com/users/jeyrschabu/repos","events_url":"https://api.github.com/users/jeyrschabu/events{/privacy}","received_events_url":"https://api.github.com/users/jeyrschabu/received_events","type":"User","site_admin":false},"repo":{"id":68213502,"name":"orca","full_name":"jeyrschabu/orca","owner":{"login":"jeyrschabu","id":1572759,"avatar_url":"https://avatars3.githubusercontent.com/u/1572759?v=4","gravatar_id":"","url":"https://api.github.com/users/jeyrschabu","html_url":"https://github.com/jeyrschabu","followers_url":"https://api.github.com/users/jeyrschabu/followers","following_url":"https://api.github.com/users/jeyrschabu/following{/other_user}","gists_url":"https://api.github.com/users/jeyrschabu/gists{/gist_id}","starred_url":"https://api.github.com/users/jeyrschabu/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jeyrschabu/subscriptions","organizations_url":"https://api.github.com/users/jeyrschabu/orgs","repos_url":"https://api.github.com/users/jeyrschabu/repos","events_url":"https://api.github.com/users/jeyrschabu/events{/privacy}","received_events_url":"https://api.github.com/users/jeyrschabu/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/jeyrschabu/orca","description":"orchestration engine","fork":true,"url":"https://api.github.com/repos/jeyrschabu/orca","forks_url":"https://api.github.com/repos/jeyrschabu/orca/forks","keys_url":"https://api.github.com/repos/jeyrschabu/orca/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jeyrschabu/orca/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jeyrschabu/orca/teams","hooks_url":"https://api.github.com/repos/jeyrschabu/orca/hooks","issue_events_url":"https://api.github.com/repos/jeyrschabu/orca/issues/events{/number}","events_url":"https://api.github.com/repos/jeyrschabu/orca/events","assignees_url":"https://api.github.com/repos/jeyrschabu/orca/assignees{/user}","branches_url":"https://api.github.com/repos/jeyrschabu/orca/branches{/branch}","tags_url":"https://api.github.com/repos/jeyrschabu/orca/tags","blobs_url":"https://api.github.com/repos/jeyrschabu/orca/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jeyrschabu/orca/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jeyrschabu/orca/git/refs{/sha}","trees_url":"https://api.github.com/repos/jeyrschabu/orca/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jeyrschabu/orca/statuses/{sha}","languages_url":"https://api.github.com/repos/jeyrschabu/orca/languages","stargazers_url":"https://api.github.com/repos/jeyrschabu/orca/stargazers","contributors_url":"https://api.github.com/repos/jeyrschabu/orca/contributors","subscribers_url":"https://api.github.com/repos/jeyrschabu/orca/subscribers","subscription_url":"https://api.github.com/repos/jeyrschabu/orca/subscription","commits_url":"https://api.github.com/repos/jeyrschabu/orca/commits{/sha}","git_commits_url":"https://api.github.com/repos/jeyrschabu/orca/git/commits{/sha}","comments_url":"https://api.github.com/repos/jeyrschabu/orca/comments{/number}","issue_comment_url":"https://api.github.com/repos/jeyrschabu/orca/issues/comments{/number}","contents_url":"https://api.github.com/repos/jeyrschabu/orca/contents/{+path}","compare_url":"https://api.github.com/repos/jeyrschabu/orca/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jeyrschabu/orca/merges","archive_url":"https://api.github.com/repos/jeyrschabu/orca/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jeyrschabu/orca/downloads","issues_url":"https://api.github.com/repos/jeyrschabu/orca/issues{/number}","pulls_url":"https://api.github.com/repos/jeyrschabu/orca/pulls{/number}","milestones_url":"https://api.github.com/repos/jeyrschabu/orca/milestones{/number}","notifications_url":"https://api.github.com/repos/jeyrschabu/orca/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jeyrschabu/orca/labels{/name}","releases_url":"https://api.github.com/repos/jeyrschabu/orca/releases{/id}","deployments_url":"https://api.github.com/repos/jeyrschabu/orca/deployments","created_at":"2016-09-14T14:30:22Z","updated_at":"2016-09-14T14:30:29Z","pushed_at":"2017-08-21T18:48:02Z","git_url":"git://github.com/jeyrschabu/orca.git","ssh_url":"git@github.com:jeyrschabu/orca.git","clone_url":"https://github.com/jeyrschabu/orca.git","svn_url":"https://github.com/jeyrschabu/orca","homepage":"","size":9196,"stargazers_count":0,"watchers_count":0,"language":"Groovy","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"spinnaker:master","ref":"master","sha":"59b5942c28ac4611ad9942f8a292e33aea9cf703","user":{"login":"spinnaker","id":7634182,"avatar_url":"https://avatars1.githubusercontent.com/u/7634182?v=4","gravatar_id":"","url":"https://api.github.com/users/spinnaker","html_url":"https://github.com/spinnaker","followers_url":"https://api.github.com/users/spinnaker/followers","following_url":"https://api.github.com/users/spinnaker/following{/other_user}","gists_url":"https://api.github.com/users/spinnaker/gists{/gist_id}","starred_url":"https://api.github.com/users/spinnaker/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/spinnaker/subscriptions","organizations_url":"https://api.github.com/users/spinnaker/orgs","repos_url":"https://api.github.com/users/spinnaker/repos","events_url":"https://api.github.com/users/spinnaker/events{/privacy}","received_events_url":"https://api.github.com/users/spinnaker/received_events","type":"Organization","site_admin":false},"repo":{"id":19834314,"name":"orca","full_name":"spinnaker/orca","owner":{"login":"spinnaker","id":7634182,"avatar_url":"https://avatars1.githubusercontent.com/u/7634182?v=4","gravatar_id":"","url":"https://api.github.com/users/spinnaker","html_url":"https://github.com/spinnaker","followers_url":"https://api.github.com/users/spinnaker/followers","following_url":"https://api.github.com/users/spinnaker/following{/other_user}","gists_url":"https://api.github.com/users/spinnaker/gists{/gist_id}","starred_url":"https://api.github.com/users/spinnaker/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/spinnaker/subscriptions","organizations_url":"https://api.github.com/users/spinnaker/orgs","repos_url":"https://api.github.com/users/spinnaker/repos","events_url":"https://api.github.com/users/spinnaker/events{/privacy}","received_events_url":"https://api.github.com/users/spinnaker/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/spinnaker/orca","description":"orchestration engine","fork":false,"url":"https://api.github.com/repos/spinnaker/orca","forks_url":"https://api.github.com/repos/spinnaker/orca/forks","keys_url":"https://api.github.com/repos/spinnaker/orca/keys{/key_id}","collaborators_url":"https://api.github.com/repos/spinnaker/orca/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/spinnaker/orca/teams","hooks_url":"https://api.github.com/repos/spinnaker/orca/hooks","issue_events_url":"https://api.github.com/repos/spinnaker/orca/issues/events{/number}","events_url":"https://api.github.com/repos/spinnaker/orca/events","assignees_url":"https://api.github.com/repos/spinnaker/orca/assignees{/user}","branches_url":"https://api.github.com/repos/spinnaker/orca/branches{/branch}","tags_url":"https://api.github.com/repos/spinnaker/orca/tags","blobs_url":"https://api.github.com/repos/spinnaker/orca/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/spinnaker/orca/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/spinnaker/orca/git/refs{/sha}","trees_url":"https://api.github.com/repos/spinnaker/orca/git/trees{/sha}","statuses_url":"https://api.github.com/repos/spinnaker/orca/statuses/{sha}","languages_url":"https://api.github.com/repos/spinnaker/orca/languages","stargazers_url":"https://api.github.com/repos/spinnaker/orca/stargazers","contributors_url":"https://api.github.com/repos/spinnaker/orca/contributors","subscribers_url":"https://api.github.com/repos/spinnaker/orca/subscribers","subscription_url":"https://api.github.com/repos/spinnaker/orca/subscription","commits_url":"https://api.github.com/repos/spinnaker/orca/commits{/sha}","git_commits_url":"https://api.github.com/repos/spinnaker/orca/git/commits{/sha}","comments_url":"https://api.github.com/repos/spinnaker/orca/comments{/number}","issue_comment_url":"https://api.github.com/repos/spinnaker/orca/issues/comments{/number}","contents_url":"https://api.github.com/repos/spinnaker/orca/contents/{+path}","compare_url":"https://api.github.com/repos/spinnaker/orca/compare/{base}...{head}","merges_url":"https://api.github.com/repos/spinnaker/orca/merges","archive_url":"https://api.github.com/repos/spinnaker/orca/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/spinnaker/orca/downloads","issues_url":"https://api.github.com/repos/spinnaker/orca/issues{/number}","pulls_url":"https://api.github.com/repos/spinnaker/orca/pulls{/number}","milestones_url":"https://api.github.com/repos/spinnaker/orca/milestones{/number}","notifications_url":"https://api.github.com/repos/spinnaker/orca/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/spinnaker/orca/labels{/name}","releases_url":"https://api.github.com/repos/spinnaker/orca/releases{/id}","deployments_url":"https://api.github.com/repos/spinnaker/orca/deployments","created_at":"2014-05-15T20:33:00Z","updated_at":"2017-08-03T06:29:49Z","pushed_at":"2017-08-21T22:32:20Z","git_url":"git://github.com/spinnaker/orca.git","ssh_url":"git@github.com:spinnaker/orca.git","clone_url":"https://github.com/spinnaker/orca.git","svn_url":"https://github.com/spinnaker/orca","homepage":"","size":9031,"stargazers_count":60,"watchers_count":60,"language":"Groovy","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":110,"mirror_url":null,"open_issues_count":55,"forks":110,"open_issues":55,"watchers":60,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/spinnaker/orca/pulls/1560"},"html":{"href":"https://github.com/spinnaker/orca/pull/1560"},"issue":{"href":"https://api.github.com/repos/spinnaker/orca/issues/1560"},"comments":{"href":"https://api.github.com/repos/spinnaker/orca/issues/1560/comments"},"review_comments":{"href":"https://api.github.com/repos/spinnaker/orca/pulls/1560/comments"},"review_comment":{"href":"https://api.github.com/repos/spinnaker/orca/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/spinnaker/orca/pulls/1560/commits"},"statuses":{"href":"https://api.github.com/repos/spinnaker/orca/statuses/d38bf7cbc6e33ab65c1d282e3e0fe0b854719625"}}}}
{"actor":{"display_login":"robzienert"}}