| OLD | NEW |
| 1 # Copyright 2014 The Chromium Authors. All rights reserved. | 1 # Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 from datetime import datetime | 5 from datetime import datetime |
| 6 import logging | 6 import logging |
| 7 | 7 |
| 8 from google.appengine.ext import ndb | 8 from google.appengine.ext import ndb |
| 9 | 9 |
| 10 from common import appengine_util | 10 from common import appengine_util |
| 11 from common import constants | 11 from common import constants |
| 12 from model import analysis_status |
| 12 from model.wf_analysis import WfAnalysis | 13 from model.wf_analysis import WfAnalysis |
| 13 from model import analysis_status | |
| 14 from waterfall import analyze_build_failure_pipeline | 14 from waterfall import analyze_build_failure_pipeline |
| 15 | 15 |
| 16 |
| 16 @ndb.transactional | 17 @ndb.transactional |
| 17 def NeedANewAnalysis( | 18 def NeedANewAnalysis( |
| 18 master_name, builder_name, build_number, failed_steps, | 19 master_name, builder_name, build_number, failed_steps, |
| 19 build_completed, force): | 20 build_completed, force): |
| 20 """Checks status of analysis for the build and decides if a new one is needed. | 21 """Checks status of analysis for the build and decides if a new one is needed. |
| 21 | 22 |
| 22 A WfAnalysis entity for the given build will be created if none exists. | 23 A WfAnalysis entity for the given build will be created if none exists. |
| 23 When a new analysis is needed, this function will create and save a WfAnalysis | 24 When a new analysis is needed, this function will create and save a WfAnalysis |
| 24 entity to the datastore, or it will reset the existing one but still keep the | 25 entity to the datastore, or it will reset the existing one but still keep the |
| 25 result of last analysis. | 26 result of last analysis. |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 68 # TODO: support following cases | 69 # TODO: support following cases |
| 69 # * Automatically retry if last analysis failed with errors. | 70 # * Automatically retry if last analysis failed with errors. |
| 70 # * Analysis is not complete and no update in the last 5 minutes. | 71 # * Analysis is not complete and no update in the last 5 minutes. |
| 71 return False | 72 return False |
| 72 | 73 |
| 73 | 74 |
| 74 def ScheduleAnalysisIfNeeded(master_name, builder_name, build_number, | 75 def ScheduleAnalysisIfNeeded(master_name, builder_name, build_number, |
| 75 failed_steps=None, | 76 failed_steps=None, |
| 76 build_completed=False, | 77 build_completed=False, |
| 77 force=False, | 78 force=False, |
| 79 force_try_job=False, |
| 78 queue_name=constants.DEFAULT_QUEUE): | 80 queue_name=constants.DEFAULT_QUEUE): |
| 79 """Schedules an analysis if needed and returns the build analysis. | 81 """Schedules an analysis if needed and returns the build analysis. |
| 80 | 82 |
| 81 When the build failure was already analyzed and a new analysis is scheduled, | 83 When the build failure was already analyzed and a new analysis is scheduled, |
| 82 the returned WfAnalysis will still have the result of last completed analysis. | 84 the returned WfAnalysis will still have the result of last completed analysis. |
| 83 | 85 |
| 84 Args: | 86 Args: |
| 85 master_name (str): The master name of the failed build. | 87 master_name (str): The master name of the failed build. |
| 86 builder_name (str): The builder name of the failed build. | 88 builder_name (str): The builder name of the failed build. |
| 87 build_number (int): The build number of the failed build. | 89 build_number (int): The build number of the failed build. |
| 88 failed_steps (list): The names of all failed steps reported for the build. | 90 failed_steps (list): The names of all failed steps reported for the build. |
| 89 build_completed (bool): Indicate whether the build is completed. | 91 build_completed (bool): Indicate whether the build is completed. |
| 90 force (bool): If True, a fresh new analysis will be triggered even when an | 92 force (bool): If True, a fresh new analysis will be triggered even when an |
| 91 old one was completed already; otherwise bail out. | 93 old one was completed already; otherwise bail out. |
| 94 force_try_job (bool): Indicate whether or not a try job should be run or |
| 95 rerun as long as a corresponding try bot is configured. |
| 92 queue_name (str): The task queue to be used for pipeline tasks. | 96 queue_name (str): The task queue to be used for pipeline tasks. |
| 93 | 97 |
| 94 Returns: | 98 Returns: |
| 95 A WfAnalysis instance. | 99 A WfAnalysis instance. |
| 96 """ | 100 """ |
| 97 if NeedANewAnalysis( | 101 if NeedANewAnalysis( |
| 98 master_name, builder_name, build_number, failed_steps, | 102 master_name, builder_name, build_number, failed_steps, |
| 99 build_completed, force): | 103 build_completed, force): |
| 100 pipeline_job = analyze_build_failure_pipeline.AnalyzeBuildFailurePipeline( | 104 pipeline_job = analyze_build_failure_pipeline.AnalyzeBuildFailurePipeline( |
| 101 master_name, builder_name, build_number, build_completed) | 105 master_name, builder_name, build_number, build_completed, |
| 106 force_try_job) |
| 102 # Explicitly run analysis in the backend module "waterfall-backend". | 107 # Explicitly run analysis in the backend module "waterfall-backend". |
| 103 # Note: Just setting the target in queue.yaml does NOT work for pipeline | 108 # Note: Just setting the target in queue.yaml does NOT work for pipeline |
| 104 # when deployed to App Engine, but it does work in dev-server locally. | 109 # when deployed to App Engine, but it does work in dev-server locally. |
| 105 # A possible reason is that pipeline will pick a default target if none is | 110 # A possible reason is that pipeline will pick a default target if none is |
| 106 # specified explicitly, and the default target is used rather than the one | 111 # specified explicitly, and the default target is used rather than the one |
| 107 # in the queue.yaml file, but this contradicts the documentation in | 112 # in the queue.yaml file, but this contradicts the documentation in |
| 108 # https://cloud.google.com/appengine/docs/python/taskqueue/tasks#Task. | 113 # https://cloud.google.com/appengine/docs/python/taskqueue/tasks#Task. |
| 109 pipeline_job.target = appengine_util.GetTargetNameForModule( | 114 pipeline_job.target = appengine_util.GetTargetNameForModule( |
| 110 constants.WATERFALL_BACKEND) | 115 constants.WATERFALL_BACKEND) |
| 111 pipeline_job.start(queue_name=queue_name) | 116 pipeline_job.start(queue_name=queue_name) |
| 112 | 117 |
| 113 logging.info('An analysis was scheduled for build %s, %s, %s: %s', | 118 logging.info('An analysis was scheduled for build %s, %s, %s: %s', |
| 114 master_name, builder_name, build_number, | 119 master_name, builder_name, build_number, |
| 115 pipeline_job.pipeline_status_path()) | 120 pipeline_job.pipeline_status_path()) |
| 116 | 121 |
| 117 return WfAnalysis.Get(master_name, builder_name, build_number) | 122 return WfAnalysis.Get(master_name, builder_name, build_number) |
| OLD | NEW |