Subversion Repositories DevTools

Rev

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