Subversion Repositories DevTools

Rev

Rev 7082 | Rev 7164 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
6914 dpurdie 1
package com.erggroup.buildtool.ripple;
2
 
7033 dpurdie 3
import org.slf4j.Logger;
4
import org.slf4j.LoggerFactory;
6914 dpurdie 5
 
6
import com.erggroup.buildtool.smtp.CreateUrls;
7
import com.erggroup.buildtool.smtp.Smtpsend;
8
 
9
import java.sql.SQLException;
10
import java.util.ArrayList;
11
import java.util.Iterator;
12
 
13
/**entity class holding build exclusion data
7082 dpurdie 14
 * 
15
 * There are three types of exclusion
16
 * Package Errors. Errors detected during planing. They may go away on the next plan
17
 *      These are 'hard' errors
18
 *          Have a rootCase string
19
 *          Have a null rootId
20
 *          
21
 * Build Errors
22
 *      These are persistent errors
23
 *          Have a null rootCause
24
 *          Have a null rootId
25
 *          Have a non-null root_file
26
 *          
27
 *  Indirect errors
28
 *      These are packages that depend on excluded packages
29
 *          Will have a non-null rootId          
30
 * 
6914 dpurdie 31
 */
32
public class BuildExclusion
33
{
34
  /**Logger
35
   * @attribute
36
   */
7033 dpurdie 37
  private static final Logger mLogger = LoggerFactory.getLogger(BuildExclusion.class);
6914 dpurdie 38
 
39
  /**The pvid of the package being excluded
40
   */
7082 dpurdie 41
  public int mId;
6914 dpurdie 42
 
43
  /**root identifier is the PVID of the package that is causing the exclusion
7082 dpurdie 44
   * A NULL (-1) value indicates that this entry(package) is the root cause of the of an exclusion
45
   * A Value of -2 indicates that cause is a RippleStop
6914 dpurdie 46
   */
47
  private int mRootId;
48
 
49
  /**root cause
50
   * If not NULL, then this is the reason this package is being excluded
51
   */
52
  private String mRootCause;
53
 
54
  /**test build instruction
7082 dpurdie 55
   * Associated package is a test build
6914 dpurdie 56
   */
57
  private int mTestBuildInstruction;
58
 
7082 dpurdie 59
  /** Indicates that the error associated with this package has been seen again
60
   *  Set if we discover 'Package Error'
61
   *  
62
   *  Used to determine if a 'Package Error' should be removed
63
   *    
6914 dpurdie 64
   */
65
  private boolean mProcessed = false;
7032 dpurdie 66
 
67
  /** Indicates that the entry was imported from the database
68
   *  Used to determine entries that are no-longer needed and can be removed from the database
69
   *  Really only applied to indirect exclusions where the reason for the exclusion no longer exists
70
   *  
71
   */
72
  private boolean mImported = false;
6914 dpurdie 73
 
74
  /**constructor
7032 dpurdie 75
   *    @param  identifier - pvid of the package being excluded
76
   *    @param  rootIdentifier  - pvid of the root package causing the exclusion. May be null
77
   *    @param  rootCause - Short (< 50 Char) string explaining the cause
78
   *    @param  testBuildInstruction - Indicates a text build instruction
6914 dpurdie 79
   */
80
  public BuildExclusion(int identifier, int rootIdentifier, String rootCause, int testBuildInstruction )
81
  {
82
    mLogger.debug("BuildExclusion");
83
    mId = identifier;
84
    mRootId = dealWithNullRootPvId(identifier, rootIdentifier);
85
    mRootCause = rootCause;
86
    mTestBuildInstruction = testBuildInstruction;
87
  }
88
 
89
  /**sets mProcessed true
90
   */
7032 dpurdie 91
  void setProcessed()
6914 dpurdie 92
  {
7033 dpurdie 93
    mLogger.debug("process {}", mId);
6914 dpurdie 94
    mProcessed = true;
95
  }
96
 
97
  /** @returns true if the item has been marked as processed. 
7032 dpurdie 98
   * Appears to be an indication that the entry has been superseded.
6914 dpurdie 99
   */
100
  boolean isProcessed()
101
  {
7082 dpurdie 102
    mLogger.debug("isProcessed returned {}", mProcessed);
6914 dpurdie 103
    return mProcessed;
104
  }
7032 dpurdie 105
 
106
  /** Flag as an imported entry
107
   *  Used to detect indirect exclusions that are no longer valid
108
   */
109
  void setImported()
110
  {
111
      mImported = true;
112
  }
6914 dpurdie 113
 
7032 dpurdie 114
  /** Test the state of the imported flag
115
   * 
116
   */
117
  boolean isImported()
118
  {
119
      return mImported;
120
  }
121
 
6914 dpurdie 122
  /**
7082 dpurdie 123
   * Determine the entry type
124
   * Have three types - see class comments above
125
   */
126
  boolean isAPackageError()
127
  {
128
      return (mRootCause != null && mRootId < 0);
129
  }
130
 
131
  boolean isABuildError()
132
  {
133
      return (mRootCause == null && mRootId < 0);
134
  }
135
 
136
  boolean isAIndirectError()
137
  {
138
      return (mRootId >= 0);
139
  }
140
 
141
  /**
142
   * @return true if this item is the root case, and is not simply a by product of some other cause.
143
   * This is the same as !isAIndirectError() 
144
   */
145
  boolean isARootCause()
146
  {
147
    boolean retVal = false;
148
 
149
    if ( mRootId == -1 )
150
    {
151
      retVal = true;
152
    }
153
 
154
    mLogger.info("isARootCause {} returned {}",mId, retVal);
155
    return retVal;
156
  }
157
 
158
  /**
6914 dpurdie 159
   * Compare this item with parameters
160
   * @param identifier          - Related Package identifier
161
   * @param rootIdentifier      - Package identifier of root cause
162
   * @param  rootCause          - Root cause string. May be null
163
   * @return true if all attributes match
164
   */
165
  boolean compare( int identifier, int rootIdentifier, String rootCause)
166
  {
7033 dpurdie 167
    mLogger.debug("compare {}, {}, {}, {}", mId, identifier, rootIdentifier,  rootCause);
6914 dpurdie 168
    boolean retVal = false;
169
    rootIdentifier = dealWithNullRootPvId(identifier, rootIdentifier);
170
 
171
    if ( mRootCause == null )
172
    {
173
      if ( mId == identifier && mRootId == rootIdentifier && rootCause == null )
174
      {
175
        retVal = true;
176
      }
177
    }
178
    else
179
    {
180
      if ( mId == identifier && mRootId == rootIdentifier && mRootCause.compareTo(rootCause) == 0 )
181
      {
182
        retVal = true;
183
      }
184
    }
185
 
7033 dpurdie 186
    mLogger.info("compare returned {}", retVal);
6914 dpurdie 187
    return retVal;
188
  }
189
 
7082 dpurdie 190
  /**   Does this entry relate to the package with a specified mId
191
   * 
192
   * @param identifier  - Package Identifier (mId) to match
6914 dpurdie 193
   * @return true if mId attribute matches
194
   */
195
  boolean compare( int identifier )
196
  {
7033 dpurdie 197
    mLogger.debug("compare {},{}", mId,  identifier);
6914 dpurdie 198
    boolean retVal = false;
199
 
200
    if ( mId == identifier )
201
    {
202
      retVal = true;
203
    }
204
 
7033 dpurdie 205
    mLogger.info("compare returned {}", retVal);
6914 dpurdie 206
    return retVal;
207
  }
208
 
209
  /**runs exclude from build
210
   * Assumes that a connection to RM has been established
211
   * 
212
   * @param rm          Release Manager instance
7033 dpurdie 213
   * @param rtagId      Rtag Id we are working against
6914 dpurdie 214
   */
7033 dpurdie 215
  void excludeFromBuild( ReleaseManager rm, int rtagId ) throws SQLException, Exception
6914 dpurdie 216
  {
7033 dpurdie 217
    mLogger.debug("excludeFromBuild {}", mId);
6914 dpurdie 218
 
219
    // a null version and log file is passed to oracle
220
    // the planned version is only needed to remove a planned version from the planned version table
221
    // the ripple engine does not get this far ie it excludes pvs before claiming a version
222
    // this is the one instance where an existing build failure must be superseded in the database
223
    rm.excludeFromBuild(true, 
224
                        mId, 
225
                        null, 
7033 dpurdie 226
                        rtagId, 
6914 dpurdie 227
    		            mRootId == -1 ? null : String.valueOf(mRootId), 
228
    		            mRootCause, 
229
    		            null, 
230
    		            true, (mTestBuildInstruction > 0) );
231
  }
232
 
233
  /**runs include to build
234
   * Include a previously excluded package-version back into the build set
235
   * 
236
   * @param rm          Release Manager instance
7033 dpurdie 237
   * @param rtagId      Rtag Id we are working against
6914 dpurdie 238
   */
7033 dpurdie 239
  void includeToBuild( ReleaseManager rm, int rtagId ) throws SQLException, Exception
6914 dpurdie 240
  {
7033 dpurdie 241
    mLogger.debug("includeToBuild {}", mId);
242
    rm.includeToBuild(mId, rtagId);
6914 dpurdie 243
  }
244
 
245
  /**
246
   * Match this items mRootId against the id's provided in a collection
247
   * ie: Determine if any items in the collection are the root cause of this items
248
   * ie: Used to determine if an entry is for an indirectly excluded package where
249
   *     the root cause of the exclusion has been removed.
250
   *     
251
   * @param buildExclusionCollection - Collection to be processed
252
   * @return false: Indirectly excluded package whose root cause no longer exists
253
   */
254
  boolean isRelevant(ArrayList<BuildExclusion> buildExclusionCollection)
255
  {
7033 dpurdie 256
    mLogger.debug("isRelevant {}", mId);
6914 dpurdie 257
    boolean retVal = false;
258
 
259
    if ( mRootId == -1 )     {
7082 dpurdie 260
        // This is a Build or Package Error
261
        retVal = true;
6914 dpurdie 262
 
263
    } else if(mRootId == -2 ) {
264
        // Excluded due to Ripple Stop
265
        // Will be recalculated so its not relevant
266
        retVal = false;
267
 
268
    } else {
7032 dpurdie 269
 
7082 dpurdie 270
        //
271
        //  Must be an indirect exclusion
272
        //  Scan to see if the rootCause is still present. It may have been removed by the user
273
 
7032 dpurdie 274
      retVal = false;
6914 dpurdie 275
      for (Iterator<BuildExclusion> it = buildExclusionCollection.iterator(); it.hasNext(); )
276
      {
277
        BuildExclusion buildExclusion = it.next();
278
 
7082 dpurdie 279
        if ( buildExclusion.mRootId == mRootId )
6914 dpurdie 280
        {
281
          retVal = true;
282
          break;
283
        }
284
      }
285
    }
286
 
7033 dpurdie 287
    mLogger.info("isRelevant {} returned {}", mId, retVal);
6914 dpurdie 288
    return retVal;
289
  }
290
 
7082 dpurdie 291
 
6914 dpurdie 292
 
293
  /**
294
   * Send an email notifying users about a build excluded package
295
   * It is user friendly, in that it does not trigger a storm of emails because a low level package 
296
   * has a build issue. It limits the emails to the low level package
297
   * 
298
   * i.e. only send email if the build exclusion has a null root pv id
299
   * and a non null root cause
300
   * 
301
   * @param    rippleEngine        - Ripple Engine Instance
302
   * @param    packageCollection   - Collection to process
303
   */
304
    public void email(RippleEngine rippleEngine, ArrayList<Package> packageCollection) throws SQLException, Exception
305
    {
7033 dpurdie 306
      mLogger.debug("email {}", mId);
6914 dpurdie 307
 
308
      //
309
      //    Only process entries that are direct failures of ripple engine detected failure
310
      //    Do not process entries that are indirectly excluded as this will cause an email storm
311
      //    Direct build failure: 
312
      //        Have no RootId and have a rootCause
313
      //
7082 dpurdie 314
      if ( isAPackageError() )
6914 dpurdie 315
      {
316
        //  Locate the associated package entry
317
        Package pkg= rippleEngine.mReleaseManager.findPackage(mId, packageCollection);
318
 
319
        if ( pkg != ReleaseManager.NULL_PACKAGE )
320
        {
7155 dpurdie 321
            // Generate a nice subject line
322
            String subject;
323
            if (pkg.mTestBuildInstruction > 0) {
324
                subject = "TEST BUILD FAILED on package " + pkg.mAlias;
325
            } else {
326
                subject = "BUILD FAILURE on package " + pkg.mAlias;
327
            }
328
 
6914 dpurdie 329
          // Is there anyone to send an email to
330
          String owners = pkg.emailInfoNonAntTask(rippleEngine);
331
 
332
          if ( owners != null )
333
          {
334
 
335
            String body =
336
            "Release: " + rippleEngine.mBaselineName + "<p>" +
337
            "Package: " + pkg.mName + "<p>" + 
338
            "Cause: "   + mRootCause + "<p>"+
339
            "RmRef: "   + CreateUrls.generateRmUrl(rippleEngine.getRtagId(), pkg.mId) +"<p>";
340
 
341
            try
342
            {
343
              Smtpsend.send(
7032 dpurdie 344
              rippleEngine.getMailServer(),             // mailServer
345
              rippleEngine.getMailSender(),             // source
6914 dpurdie 346
              owners,                                   // target
347
              null,                                     // cc
348
              null,                                     // bcc
7155 dpurdie 349
              subject,                                  // subject
6914 dpurdie 350
              body,                                     // body
351
              null                                      // attachment
352
              );
353
            }
354
            catch( Exception e )
355
            {
7033 dpurdie 356
                mLogger.info("email send exception. {}", e);
6914 dpurdie 357
            }
358
          }
359
 
7155 dpurdie 360
          //    Handle test builds here
361
          if (pkg.mTestBuildInstruction > 0 )
362
          {
363
 
6914 dpurdie 364
          // Having sent the build failure email, complete a test build if applicable.
365
          // This ensures the test build instruction is not processed indefinitely
366
          // as there is no notion of excluding test builds
7155 dpurdie 367
 
368
          // Update the Release Manager Database
369
          rippleEngine.mReleaseManager.markDaemonInstCompleted(pkg.mTestBuildInstruction);
370
 
371
          }
6914 dpurdie 372
        }
373
      }
374
    }
375
 
376
    /**
377
     * Hides how a rootPvId is treated
378
     * Only use rootPvId if not equal to the pvid
379
     * 
380
     * If the provided rootPvId matches the pvId, then the rootPvId will be set to null (-1)
381
     * This is to drive a direct build exclusion in the release manager
382
     * 
383
     * @param   pvid        - id
384
     * @param   rootPvId    - rootPvid
385
     * 
386
     * @returns rootPvId unless pvId matches= rootPvId, when it returns a null (-1)
387
    */
388
    private int dealWithNullRootPvId( int pvId, int rootPvId )
389
    {
390
      int retVal = rootPvId;
391
 
392
      if ( pvId == rootPvId )
393
      {
394
        retVal = -1;    // -1 == null entry
395
      }
396
 
397
      return retVal;
398
    }
399
 
400
    /**
401
     * Generate a single text line of info
7082 dpurdie 402
     * Used within the UTF to display diagnostic info
6914 dpurdie 403
     * @return String form of the state of the entry
404
     */
7082 dpurdie 405
    public String toString()
6914 dpurdie 406
    {
407
        String rv = "";
408
        rv += "pvid=" + mId + ",RootId=" + mRootId + ",Processed=" + mProcessed + ",TestBuild=" + mTestBuildInstruction + ",RootCause=" + mRootCause;
7032 dpurdie 409
        if ( mImported ) {
410
            rv += ",Imported=" + mImported;
411
        }
6914 dpurdie 412
        return rv;
413
    }
414
}