Subversion Repositories DevTools

Rev

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