Subversion Repositories DevTools

Rev

Rev 4697 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4625 dpurdie 1
########################################################################
2
# Copyright (c) VIX TECHNOLOGY (AUST) LTD
3
#
4
# Module name   : jats_get_releasenote_data.pl
5
# Module type   : Makefile system
6
# Compiler(s)   : Perl
7
# Environment(s): jats
8
#
9
# Description   : Extract Data from RM in order to generate a release note
10
#                 The data is stored in XML
11
#
12
# Improvements  : Catpure non ripple build reason for Release
13
#                 Release ReleaseName
14
#                 Project ProjectName 
15
#                 BuildFilters BuildMachines
16
#                 Build Standard
17
#                 Build Environment
18
#
19
#                 Get Jira Credentials from DataBase
20
#
21
#
22
# Usage:        See POD
23
#
24
#......................................................................#
25
 
26
require 5.008_002;
27
use strict;
28
use warnings;
29
 
30
use Pod::Usage;
31
use Getopt::Long;
32
use XML::Simple;
33
use JSON;
34
use LWP::UserAgent;
35
use MIME::Base64;
36
use POSIX qw(strftime);
37
use Encode qw(decode encode);
38
use Getopt::Long;
39
use Pod::Usage;
40
 
41
use JatsError;
42
use JatsSystem;
43
use FileUtils;
44
use JatsRmApi;
45
use ArrayHashUtils;
46
use DBI;
47
 
48
my $VERSION = "1.0.0";                                      # Update this. Inserted into meta data field
49
 
50
my $opt_verbose = 0;
51
my $opt_help = 0;
52
my $opt_pvid;
53
my $opt_prev_pvid;
54
my $opt_outfile;
55
 
56
#
57
#   Data Items
58
#
59
my $RM_DB;
60
my %pkgData;
61
my %pkgPrevData;
62
my @dependData;
63
my @dependRunData;
64
my @unitTestData;
65
my @additionalNotesData;
66
my @buildDepDiff;
67
my @JiraIssues;
68
my @JiraIssueList;
69
my %ClearQuestIssueData;
70
my @ClearQuestIssues;
71
my @FileList;                                               # Place Holder
72
 
73
#-------------------------------------------------------------------------------
74
# Function        : Main Entry
75
#
76
# Description     :
77
#
78
# Inputs          :
79
#
80
# Returns         :
81
#
82
{
83
    my $result = GetOptions (
84
                    "help+"         => \$opt_help,          # flag, multiple use allowed
85
                    "manual:3"      => \$opt_help,
86
                    "verbose:+"     => \$opt_verbose,       # flag
87
                    "pvid:n"        => \$opt_pvid,          # Number
88
                    "outfile:s"     => \$opt_outfile,       # String
89
                    );
90
 
91
    #
92
    #   Process help and manual options
93
    #
94
    pod2usage(-verbose => 0, -message => "Version: $VERSION")  if ($opt_help == 1  || ! $result);
95
    pod2usage(-verbose => 1)  if ($opt_help == 2 );
96
    pod2usage(-verbose => 2)  if ($opt_help > 2);
97
 
98
    ErrorConfig( 'name'    =>'GetRnInfo', 'verbose' => $opt_verbose );
99
 
100
    #
101
    #   Sanity Check
102
    #
103
    Error ("Must provide pvid") unless $opt_pvid;
104
    Error ("GBE_JIRA_URL is not configured") unless exists ($ENV{GBE_JIRA_URL});
105
    Error ("GBE_JIRA_USERNAME is not configured") unless exists ($ENV{GBE_JIRA_USERNAME});
106
    Error ("GBE_JIRA_PASSWORD is not configured") unless exists ($ENV{GBE_JIRA_PASSWORD});
107
 
108
    #
109
    #   Get Data Item
110
    #
111
    GetPkgInfo($opt_pvid, \%pkgData);
112
    $opt_prev_pvid = $pkgData{prev_pvid} || $pkgData{'-prev_pvid'};
113
 
114
    #
115
    #   Get Data on immediate Previous version
116
    #
117
    if ($opt_prev_pvid)
118
    {
119
        GetPkgInfo($opt_prev_pvid, \%pkgPrevData);
120
        foreach my $field ( qw(pvid name version modified_stamp pname psuffix dlocked build_type)) {
121
            $pkgData{previous}{$field} = $pkgPrevData{$field};
122
        }
123
    }
124
 
125
    GetPkgIssues();
126
    GetBuildDependencies();
127
    GetRunTimeDependencies();
128
    GetUnitTests();
129
    GetNotes();
130
    GetBuildDepDiff();
131
    GetIssues();
132
 
133
    #
134
    #   Create a single data structure
135
    #
136
    my $data;
137
 
138
    $data->{package} = \%pkgData;   
139
    $data->{build}{dependency} = \@dependData;   
140
    $data->{builddep}{dependencydiff} = \@buildDepDiff;   
141
    $data->{runtime}{dependency} = \@dependRunData;   
142
    $data->{unit_tests}{test} = \@unitTestData;   
143
    $data->{additional_notes}{note} = \@additionalNotesData;   
144
    $data->{issues}{jira} = \@JiraIssues;
145
    $data->{issues}{clearquest} = \@ClearQuestIssues;
146
    $data->{files}{file} = \@FileList;
147
 
148
    #
149
    #    Insert some metadata
150
    #        created datetime in same format as that from Release Manager
151
    #
152
    $data->{meta}{data_version} = $VERSION;
153
    $data->{meta}{datetime} = time;
154
    $data->{meta}{created} = strftime "%Y-%m-%d %H:%M:%S.0", gmtime(time);
155
 
156
    #
157
    #   Determine the name of the output file
158
    #
159
    unless ($opt_outfile) {
160
       $opt_outfile = join('_', $pkgData{name}, $pkgData{version});
161
       $opt_outfile .= '.xml';
162
    }
163
 
164
    #
165
    #   Write out sections of XML
166
    #       Want control over the output order
167
    #       Use lots of attributes and only elements for arrays
168
    #       Save as one attribute per line - for readability
169
    #
170
    Verbose("Creating: " . DisplayPath($opt_outfile));
171
    my $xs = XML::Simple->new( NoAttr =>0, AttrIndent => 1 );
172
 
173
    open (my $XML, '>', $opt_outfile) || Error ("Cannot create output file: $opt_outfile", $!);
174
    print $XML ('<?xml version="1.0" encoding="UTF-8"?>' . "\n");
175
    print $XML ("<package_data>\n");
176
    foreach my $section (qw( meta package build builddep runtime unit_tests additional_notes issues files)) {
177
        print $XML $xs->XMLout($data->{$section}, 'RootName' => $section);
178
    }
179
    print $XML ("</package_data>\n");
180
    close $XML;
181
 
182
    #
183
    #   All done
184
    #
185
    exit 0;
186
}
187
 
188
#-------------------------------------------------------------------------------
189
# Function        : populateHash 
190
#
191
# Description     : Put an array of data items into a hash
192
#                   Clean white space from the data
193
#                   Replace /r and /n sequences with a single <br>
194
#
195
# Inputs          : pHash           - ref to output hash
196
#                   pRow            - Ref to the row data 
197
#                   pItems          - Ref to an hash array of entry names
198
#
199
# Returns         : pHash
200
#
201
sub populateHash
202
{
203
    my ($pHash, $pRow, $pItems) = @_;
204
 
205
    foreach my $item ( @{$pItems} ) {
206
        my $data = shift @{$pRow};
207
 
208
        if (defined $data)
209
        {
210
            $data =~ s~^\s+~~;
211
            $data =~ s~\s+$~~;
212
 
213
            #
214
            #   Clean multiline items
215
            #
216
            if ($data =~ m~\n|\r~)
217
            {
218
                $data =~ tr~\r~\n~;
219
                $data =~ tr~\n~\n~s;
220
                $data =~ s~\n~<br>~g;
221
                $data =~ s~<br><br>~<br>~gi;
222
            }
223
 
224
            #
225
            #   Convert from iso-8859-1 into utf-8
226
            #   Release Manger appears to store data in iso-8859-1
227
            #   Note sure about ClearQuest data 
228
            #
229
            $data = decode( 'iso-8859-1', $data );
230
            $data = encode( 'utf-8', $data );
231
 
232
            #
233
            #   Some other nessessary conversions
234
            #   Appears to come from ClearQuest data, or RM fields pasted from ClearQuest
235
            #
236
            $data =~ s/\023/-/g;                    # Some form of -
237
            $data =~ s/\x1C/"/g;                    # Some Forms of ' and "
238
            $data =~ s/\x1D/"/g;
239
            $data =~ s/\x18/'/g;
240
            $data =~ s/\x19/'/g;
241
            $data =~ s/\t/&#9;/g;                   # Tab
242
            $data =~ s/[[:cntrl:]]/?/g;             # Control Chars
243
#            $data =~ s/[^[:ascii:]]/?/g;           # Non Ascii
244
 
245
            #
246
            #   Store in hash
247
            #
248
            $pHash->{$item} = $data;
249
        }
250
    }
251
    return $pHash;
252
}
253
 
254
#-------------------------------------------------------------------------------
255
# Function        : performSqlQueryCallback 
256
#
257
# Description     : Perform a general Sql query and invoke a user function for
258
#                   each row of results
259
#
260
# Inputs          : $fname                  - Name of query for error reporting
261
#                   $m_sqlstr               - Query string
262
#                   $f_process              - Function called for each row in the result
263
#                                             Use closure to have callback modify other data
264
#
265
# Returns         : Number of rows found
266
#
267
sub performSqlQueryCallback
268
{
269
    my ($fname, $m_sqlstr, $f_process ) = @_;
270
    my $found = 0;
271
 
272
    #
273
    #   Connect to the database - once
274
    #
275
    connectRM(\$RM_DB, 0) unless $RM_DB;
276
 
277
    $m_sqlstr =~ s~\s+~ ~g;
278
    Verbose3("SQL:", $m_sqlstr);
279
    my $sth = $RM_DB->prepare($m_sqlstr);
280
    if ( defined($sth) )
281
    {
282
        if ( $sth->execute( ) )
283
        {
284
            if ( $sth->rows )
285
            {
286
                while ( my @row = $sth->fetchrow_array )
287
                {
288
                    $found++;
289
                    &$f_process(\@row);
290
                }
291
            }
292
            $sth->finish();
293
        }
294
        else
295
        {
296
            Error("$fname:Execute failure: $m_sqlstr", $sth->errstr() );
297
        }
298
    }
299
    else
300
    {
301
        Error("$fname:Prepare failure" );
302
    }
303
 
304
    unless ( $found )
305
    {
306
        Verbose("$fname:No data for: $opt_pvid");
307
    }
308
    return $found;
309
}
310
 
311
#-------------------------------------------------------------------------------
312
# Function        : populateArrayFromSql 
313
#
314
# Description     : Issue an SQL query and push the results into an array of hashes
315
#                   where each row from the query is a hash and the entire result is an 
316
#                   array 
317
#
318
# Inputs          :     name                - For error reporting
319
#                       pArray              - Ref to the output array
320
#                       sql                 - Sql to process
321
#                       pItems              - Array of tems to extract
322
#                                             Must match the SQL SELECT arguments
323
#                                             Item names starting with '-' do not end up in the
324
#                                             generated XML
325
# Returns         : 
326
#
327
sub populateArrayFromSql
328
{
329
    my ($fname, $pArray, $m_sqlstr, $pItems) = @_;
330
 
331
    performSqlQueryCallback($fname, 
332
                            $m_sqlstr, 
333
                            sub { 
334
                                my ($pRow) = @_;
335
                                my %entry;
336
                                push @{$pArray}, populateHash( \%entry, $pRow, $pItems);
337
                                }
338
                            );
339
#DebugDumpData("populateArrayFromSql", $pArray);
340
}
341
 
342
#-------------------------------------------------------------------------------
343
# Function        : GetPkgInfo  
344
#
345
# Description     : Get Basic Package Information    
346
#
347
# Inputs          : pvid                - pvid of package to fetch
348
#                   pHash               - Ref to Hash to populate 
349
#
350
# Returns         : 
351
#
352
sub GetPkgInfo
353
{
354
    my ($pvid, $pHash) = @_;
355
    my $fname = 'GetPkgInfo';
356
 
357
    #
358
    #   Now extract the package infromation
359
    #
360
    my @items = qw(name version modifier modifier_email modified_stamp owner owner_email pkg_label src_path vcstag reason long_desc short_desc pvid psuffix pname deployable -prev_pvid build_type);
361
    my $m_sqlstr = 
362
          "SELECT ".
363
          "     pkg.pkg_name, ".
364
          "     pv.pkg_version, ".
365
          "     lm.full_name AS modifier,".
366
          "     lm.user_email AS modifier_email, ".
367
          "     pv.modified_stamp, ".
368
          "     own.full_name AS owner,".
369
          "     own.user_email AS owner_email, ".
370
          "     pv.PKG_LABEL,".
371
          "     pv.SRC_PATH,".
372
          "     release_manager.PK_RMAPI.return_vcs_tag(pv.PV_ID),".
373
          "     pv.comments reason, ".
374
          "     pv.pv_overview long_desc,".
375
          "     pv.pv_description short_desc,".
376
          "     pv.pv_id,".
377
          "     pv.v_ext,".
378
          "     pkg.pkg_name || pv.v_ext, ".
379
          "     pv.is_deployable,".
380
          "     pv.last_pv_id,".
381
          "     pv.build_type".
382
          " FROM RELEASE_MANAGER.PACKAGES pkg, RELEASE_MANAGER.package_versions pv, RELEASE_MANAGER.users lm, RELEASE_MANAGER.users own".
383
          " WHERE pv.pkg_id = pkg.pkg_id".
384
          " AND pv.modifier_id = lm.user_id".
385
          " AND pv.owner_id = own.user_id".
386
          " AND pv.pv_id = " . $pvid;
387
 
388
    performSqlQueryCallback($fname, 
389
                            $m_sqlstr, 
390
                            sub { populateHash( $pHash, $_[0], \@items); }
391
                            );
392
 
393
#    DebugDumpData("$fname", $pHash);
394
}
395
 
396
#-------------------------------------------------------------------------------
397
# Function        : GetPkgIssues 
398
#
399
# Description     : Get the Issues for the package 
400
#
401
# Inputs          :  
402
#
403
# Returns         : 
404
#
405
sub GetPkgIssues
406
{
407
    #
408
    #   Get associated Jira issues
409
    #   Insert Dependency issues into the Package Information
410
    #
411
    performSqlQueryCallback('GetPkgIssuesJira', 
412
                             "SELECT iss_key".
413
                             " FROM".
414
                             " RELEASE_MANAGER.JIRA_ISSUES ".
415
                             " WHERE pv_id in ($opt_pvid)".
416
                             " ORDER BY iss_key ASC",
417
                               sub 
418
                               {
419
                                   my ($pRow) = @_;
420
                                   UniquePush (\@JiraIssueList, $pRow->[0]);
421
                                   push @{$pkgData{issues}{jira}}, $pRow->[0];
422
                               }
423
                              );
424
 
425
    #
426
    #   Get associated ClearQuest Issues
427
    #       Insert Dependency issues into the Package Information
428
    #       Keep the body of the ClearQuest data for later
429
    #
430
    my @items = qw(iss_uid iss_db iss_id iss_state iss_mod_date iss_notes); 
431
    performSqlQueryCallback('GetPkgIssuesCQ',
432
                            "SELECT iss_db || '_' || iss_id as iss_uid, iss_db, iss_id, iss_state, mod_date, notes".
433
                            " FROM".
434
                            " RELEASE_MANAGER.CQ_ISSUES cq ".
435
                            " WHERE pv_id in ($opt_pvid)",
436
                            sub 
437
                            {
438
                                my ($pRow) = @_;
439
                                my $uid = $pRow->[0];
440
                                push @{$pkgData{issues}{clearquest}}, $uid;
441
 
442
                                my %entry;
443
                                populateHash(\%entry,$pRow, \@items);
444
                                $ClearQuestIssueData{$uid} = \%entry;
445
 
446
                            }
447
                           );
448
}
449
 
450
#-------------------------------------------------------------------------------
451
# Function        : GetBuildDependencies 
452
#
453
# Description     : Get the build dependencies and associated information
454
#
455
# Inputs          : 
456
#
457
# Returns         : 
458
#
459
sub GetBuildDependencies
460
{
461
    my @items = qw(pvid name version dlocked pkg_label src_path vcstag -pkgid modified_stamp reason pname psuffix build_type); 
462
    my $m_sqlstr = "SELECT ".
463
                  "        pv.PV_ID,".
464
                  "        pkg.PKG_NAME, ".
465
                  "        pv.PKG_VERSION, ".
466
                  "        pv.DLOCKED,".
467
                  "        pv.PKG_LABEL,".
468
                  "        pv.SRC_PATH,".
469
                  "        release_manager.PK_RMAPI.return_vcs_tag(pv.PV_ID),".
470
                  "        pv.PKG_ID,".
471
                  "        pv.MODIFIED_STAMP," .
472
                  "        pv.comments as reason,".
473
                  "        pkg.PKG_NAME || pv.v_ext," .
474
                  "        pv.v_ext," .
475
                  "        pv.build_type" .
476
                  " FROM  ".
477
                  "         RELEASE_MANAGER.PACKAGE_DEPENDENCIES pd, ".
478
                  "         RELEASE_MANAGER.PACKAGE_VERSIONS pv, ".
479
                  "         RELEASE_MANAGER.PACKAGES pkg" .
480
                  " WHERE ".
481
                  #"         pv.PV_ID = \'$opt_pvid\' " .
482
                  "         pd.PV_ID(+) = \'$opt_pvid\' " .
483
                  "         AND pd.DPV_ID = pv.PV_ID" .
484
                  "         AND pv.PKG_ID = pkg.PKG_ID" .
485
                  "";
486
 
487
    populateArrayFromSql( 'GetBuildDependencies', \@dependData, $m_sqlstr, \@items );
488
 
489
    #
490
    #   Get associated Jira issues
491
    #       Group issues by pvid
492
    #
493
    my %issuedByPvid;
494
    performSqlQueryCallback( 'GetBuildDependenciesIssuesJira', 
495
                              "SELECT ji.pv_id, ji.iss_key FROM".
496
                              "   RELEASE_MANAGER.PACKAGE_DEPENDENCIES pd, ".
497
                              "   RELEASE_MANAGER.PACKAGE_VERSIONS pv, ".
498
                              "   RELEASE_MANAGER.JIRA_ISSUES ji ".
499
                              " WHERE ".
500
                              "   pd.PV_ID(+) = \'$opt_pvid\' " .
501
                              "   AND pd.DPV_ID = pv.PV_ID" .
502
                              "   AND pd.DPV_ID = ji.PV_ID" .
503
                              " ORDER BY ji.iss_key ASC",
504
                              sub 
505
                              {
506
                                my ($pRow) = @_;
507
                                my $pvid = $pRow->[0];
508
                                my $issue = $pRow->[1];
509
                                push @{$issuedByPvid{$pvid}}, $issue;
510
                                UniquePush (\@JiraIssueList, $issue);
511
                              }
512
                              );
513
 
514
    #
515
    #   Insert jira issues into the dependendency array
516
    #
517
    foreach my $entry (@dependData) {
518
        my $pvid = $entry->{pvid};
519
        if (exists $issuedByPvid{$pvid})
520
        {
521
            push @{$entry->{issues}{jira}}, @{$issuedByPvid{$pvid}}; 
522
        }
523
    }
524
 
525
    #
526
    #   Get associated ClearQuest issues
527
    #       Group issues by pvid
528
    #
529
    my %CQissuedByPvid;
530
    @items = qw(-pvid iss_uid iss_db iss_id iss_state iss_mod_date iss_notes);
531
    performSqlQueryCallback( 'GetBuildDependenciesIssuesCQ', 
532
                             "SELECT cq.pv_id,iss_db || '_' || iss_id as iss_uid, cq.iss_db, cq.iss_id, cq.iss_state,mod_date, notes FROM".
533
                             "   RELEASE_MANAGER.PACKAGE_DEPENDENCIES pd, ".
534
                             "   RELEASE_MANAGER.PACKAGE_VERSIONS pv, ".
535
                             "   RELEASE_MANAGER.CQ_ISSUES cq ".
536
                             " WHERE ".
537
                             "   pd.PV_ID(+) = \'$opt_pvid\' " .
538
                             "   AND pd.DPV_ID = pv.PV_ID" .
539
                             "   AND pd.DPV_ID = cq.PV_ID",
540
                             sub 
541
                             {
542
                                my ($pRow) = @_;
543
                                my $pvid = $pRow->[0];
544
                                my $uid = $pRow->[1];
545
 
546
                                my %data;
547
                                populateHash(\%data, $pRow, \@items);
548
 
549
                                push @{$CQissuedByPvid{$pvid}}, $uid;
550
                                $ClearQuestIssueData{$uid} = \%data; 
551
 
552
                             }
553
                           );
554
 
555
    #
556
    #   Insert clearquest issues into the dependendency array
557
    #
558
    foreach my $entry (@dependData) {
559
        my $pvid = $entry->{pvid};
560
        if (exists $CQissuedByPvid{$pvid})
561
        {
562
            push @{$entry->{issues}{clearquest}}, @{$CQissuedByPvid{$pvid}}; 
563
        }
564
    }
565
 
566
#    DebugDumpData("Dependency Issues", \@dependData, \@issues, \%issues);
567
}
568
 
569
#-------------------------------------------------------------------------------
570
# Function        : GetRunTimeDependencies 
571
#
572
# Description     : Get the runtime dependencies
573
#
574
# Inputs          : 
575
#
576
# Returns         : 
577
#
578
sub GetRunTimeDependencies
579
{
580
    my $m_sqlstr = " SELECT pkg.pkg_name, ".
581
                   "        pv.pkg_version, ".
582
                   "        pv.v_ext, ".
583
                   "        pkg.pkg_name || pv.v_ext, ".
584
                   "        rtd.rtd_comments, ".
585
                   "        rtd.rtd_url,".
586
                   "        pv.pv_id".
587
                   "   FROM RELEASE_MANAGER.PACKAGES pkg, ".
588
                   "RELEASE_MANAGER.package_versions pv, ".
589
                   "RELEASE_MANAGER.runtime_dependencies rtd".
590
                   "  WHERE pv.pkg_id = pkg.pkg_id".
591
                   "    AND rtd.rtd_id = pv.pv_id".
592
                   "    AND rtd.pv_id = " . $opt_pvid .
593
                   " ORDER BY UPPER(pkg.pkg_name)";
594
    my @items = qw(name version psuffix pname comment url pvid);
595
 
596
    populateArrayFromSql( 'GetRunTimeDependencies', \@dependRunData, $m_sqlstr, \@items );
597
}
598
 
599
#-------------------------------------------------------------------------------
600
# Function        : GetUnitTests 
601
#
602
# Description     : Get the unit test information
603
#
604
# Inputs          : 
605
#
606
# Returns         : 
607
#
608
sub GetUnitTests
609
{
610
    my $m_sqlstr = << "END_SQL";
611
    SELECT  ttypes.test_type_id, 
612
        ttypes.test_type_name,
613
        ut.TEST_ID, 
614
        ut.PV_ID, 
615
        ut.TEST_SUMMARY, 
616
        ut.COMPLETION_DATE, 
617
        tusr.full_name AS TESTER,
618
        tusr.user_email AS TESTER_EMAIL, 
619
        ut.RESULTS_URL, 
620
        ut.RESULTS_ATTACHMENT_NAME, 
621
        ut.ACCEPTANCE_DATE, 
622
        ausr.FULL_NAME AS REVIEWEE,
623
        ausr.user_email AS REVIEWEE_EMAIL,
624
        ut.NUMOF_TEST, 
625
        ut.TEST_ACCEPTED, 
626
        ut.REVIEW_COMMENTS
627
    FROM RELEASE_MANAGER.UNIT_TESTS ut,
628
      (
629
         SELECT tt.*
630
            FROM RELEASE_MANAGER.TEST_TYPES tt
631
            WHERE NOT tt.DISPLAY_ORDER IS NULL     
632
      ) ttypes,
633
      RELEASE_MANAGER.USERS tusr,
634
      RELEASE_MANAGER.USERS ausr
635
 WHERE
636
   ut.TEST_TYPES_FK = ttypes.test_type_id  
637
   AND ut.pv_id (+) = $opt_pvid
638
   AND ut.COMPLETED_BY = tusr.user_id (+)
639
   AND ut.ACCEPTED_BY  = ausr.user_id (+)
640
ORDER BY ttypes.DISPLAY_ORDER  
641
END_SQL
642
 
643
    my @items = qw(
644
        -test_type
645
        name
646
        -test_id 
647
        -pv_id 
648
        test_summary 
649
        completion_date 
650
        tester
651
        tester_email 
652
        results_url 
653
        results_attachment_name 
654
        acceptance_date 
655
        reviewee
656
        reviewee_email
657
        numof_test 
658
        test_accepted 
659
        review_comments
660
        );
661
 
662
    populateArrayFromSql( 'GetUnitTests', \@unitTestData, $m_sqlstr, \@items );
663
}
664
 
665
#-------------------------------------------------------------------------------
666
# Function        : GetNotes 
667
#
668
# Description     : Get the addiotional Notes
669
#
670
# Inputs          : 
671
#
672
# Returns         : 
673
#
674
sub GetNotes
675
{
676
    my $m_sqlstr = << "END_SQL";
677
    SELECT an.note_id, an.NOTE_TITLE, an.NOTE_BODY, an.mod_date, usr.full_name, usr.user_email,
678
        an.mod_date ||' by '|| usr.full_name AS lastmod
679
    FROM RELEASE_MANAGER.ADDITIONAL_NOTES an,
680
    RELEASE_MANAGER.USERS usr
681
    WHERE an.pv_id = $opt_pvid
682
    AND an.mod_user = usr.user_id
683
    ORDER BY an.note_id
684
END_SQL
685
 
686
    my @items = qw(
687
        -note_id
688
        note_title
689
        note_body 
690
        mod_date
691
        full_name
692
        user_email
693
        );
694
 
695
    populateArrayFromSql( 'GetNotes', \@additionalNotesData, $m_sqlstr, \@items );
696
}
697
 
698
#-------------------------------------------------------------------------------
699
# Function        : GetBuildDepDiff 
700
#
701
# Description     : Get the Differences in Build Deps between this verion and the previous
702
#
703
# Inputs          : 
704
#
705
# Returns         : 
706
#
707
sub GetBuildDepDiff
708
{
709
    #
710
    #   Only if data can be calculated
711
    return unless $opt_prev_pvid;
712
 
713
    my $m_sqlstr = << "END_SQL";
714
  SELECT pkg.pkg_name, comp.PV_ID,comp.OLD_PV_ID,comp.PKG_ID,comp.PKG_VERSION,comp.PREVIOUS_VERSION,comp.STATUS,usr.FULL_NAME, usr.user_email
715
  FROM RELEASE_MANAGER.PACKAGES pkg, 
716
       RELEASE_MANAGER.USERS usr,
717
       (   
718
        SELECT dpv.pv_id AS pv_id, -1 AS old_pv_id, dpv.pkg_id, NULL AS pkg_version, dpv.pkg_version AS previous_version, 'deleted' AS status, dpv.MODIFIER_ID 
719
          FROM RELEASE_MANAGER.PACKAGE_VERSIONS dpv,
720
               RELEASE_MANAGER.PACKAGE_DEPENDENCIES dep,
721
               (
722
                SELECT olddpv.pv_id AS previous_pv_id, newdpv.pv_id AS current_pv_id 
723
                  FROM RELEASE_MANAGER.PACKAGE_VERSIONS newdpv,
724
                       RELEASE_MANAGER.PACKAGE_DEPENDENCIES newdep,
725
                       RELEASE_MANAGER.PACKAGE_VERSIONS olddpv,
726
                       RELEASE_MANAGER.PACKAGE_DEPENDENCIES olddep
727
                 WHERE newdep.DPV_ID = newdpv.PV_ID 
728
                   AND olddep.DPV_ID = olddpv.PV_ID
729
                   AND newdep.pv_id = :PV_ID
730
                   AND olddep.pv_id = :OLD_PV_ID
731
                   AND newdpv.pkg_id = olddpv.pkg_id 
732
                   AND NVL( newdpv.v_ext , 'LINK_A_NULL' ) = NVL( olddpv.v_ext, 'LINK_A_NULL' )
733
               ) diff
734
         WHERE dep.DPV_ID = dpv.PV_ID
735
           AND dep.pv_id = :OLD_PV_ID
736
           AND dpv.pv_id = diff.previous_pv_id (+)  
737
           AND (diff.current_pv_id IS NULL OR diff.previous_pv_id IS NULL)
738
        UNION
739
        SELECT dpv.pv_id AS pv_id, 0 AS old_pv_id, dpv.pkg_id, dpv.pkg_version, NULL AS previous_version, 'added' AS status, dpv.MODIFIER_ID
740
          FROM RELEASE_MANAGER.PACKAGE_VERSIONS dpv,
741
               RELEASE_MANAGER.PACKAGE_DEPENDENCIES dep,
742
               (
743
                SELECT olddpv.pv_id AS previous_pv_id, 
744
                       newdpv.pv_id AS current_pv_id 
745
                  FROM RELEASE_MANAGER.PACKAGE_VERSIONS newdpv,
746
                       RELEASE_MANAGER.PACKAGE_DEPENDENCIES newdep,
747
                       RELEASE_MANAGER.PACKAGE_VERSIONS olddpv,
748
                       RELEASE_MANAGER.PACKAGE_DEPENDENCIES olddep
749
                 WHERE newdep.DPV_ID = newdpv.PV_ID 
750
                   AND olddep.DPV_ID = olddpv.PV_ID
751
                   AND newdep.pv_id = :PV_ID
752
                   AND olddep.pv_id = :OLD_PV_ID
753
                   AND newdpv.pkg_id = olddpv.pkg_id 
754
                   AND NVL( newdpv.v_ext , 'LINK_A_NULL' ) = NVL( olddpv.v_ext, 'LINK_A_NULL' )
755
               ) diff
756
         WHERE dep.DPV_ID = dpv.PV_ID
757
           AND dep.pv_id = :PV_ID
758
           AND dpv.pv_id = diff.current_pv_id (+)  
759
           AND (diff.current_pv_id IS NULL OR diff.previous_pv_id IS NULL)   
760
        UNION
761
        SELECT newdpv.pv_id AS pv_id,
762
               olddep.dpv_id AS old_pv_id, 
763
               newdpv.pkg_id, newdpv.pkg_version,
764
               DECODE( newdpv.pv_id, olddpv.pv_id, NULL, olddpv.pkg_version ) AS previous_version,
765
               DECODE( newdpv.pv_id, olddpv.pv_id, 'same', 'modified' ) AS status, newdpv.MODIFIER_ID
766
          FROM RELEASE_MANAGER.PACKAGE_VERSIONS newdpv,
767
               RELEASE_MANAGER.PACKAGE_DEPENDENCIES newdep,
768
               RELEASE_MANAGER.PACKAGE_VERSIONS olddpv,
769
               RELEASE_MANAGER.PACKAGE_DEPENDENCIES olddep
770
         WHERE newdep.DPV_ID = newdpv.PV_ID 
771
           AND olddep.DPV_ID = olddpv.PV_ID
772
           AND newdep.pv_id = :PV_ID
773
           AND olddep.pv_id = :OLD_PV_ID
774
           AND newdpv.pkg_id = olddpv.pkg_id 
775
           AND NVL( newdpv.v_ext , 'LINK_A_NULL' ) = NVL( olddpv.v_ext, 'LINK_A_NULL' )
776
        ) comp
777
 WHERE comp.pkg_id = pkg.pkg_id  
778
   AND comp.modifier_id = usr.user_id
779
 ORDER BY UPPER(pkg.pkg_name) 
780
END_SQL
781
 
782
    my @items = qw(
783
        name
784
        pvid 
785
        previous_pvid
786
        -pkg_id
787
        version 
788
        previous_version
789
        status 
790
        modifier
791
        modifier_email  
792
        );
793
 
794
    $m_sqlstr =~ s~:PV_ID~$opt_pvid~g;
795
    $m_sqlstr =~ s~:OLD_PV_ID~$opt_prev_pvid~g;
796
    populateArrayFromSql( 'GetBuildDepDiff', \@buildDepDiff, $m_sqlstr, \@items );
797
}
798
 
799
#-------------------------------------------------------------------------------
800
# Function        : GetIssues 
801
#
802
# Description     : Get issues for the current package and its dependencies
803
#                   A list of issues has already been determined. This function
804
#                   will simply get the data behind the issue information
805
#
806
#                   There are two sources of issues
807
#                       ClearQuest
808
#                       Jira - Details held externally
809
#
810
# Inputs          : 
811
#
812
# Returns         : 
813
#
814
sub GetIssues
815
{
816
    GetCQIssues();
817
    GetJiraIssues();
818
}
819
 
820
#-------------------------------------------------------------------------------
821
# Function        : GetCQIssues 
822
#
823
# Description     : Get the body of the CQ Issues required by the package and
824
#                   dependent packages
825
#
826
#                   Already have this data
827
#                   Just need to put it in the right form
828
#
829
#                   Would be nice to get more data about the ClearQuest issues
830
#                   but the database is hard to access - and going away.
831
#
832
# Inputs          : 
833
#
834
# Returns         : 
835
#
836
sub GetCQIssues
837
{
838
 
839
    my $fname = 'GetCQIssues';
840
    my $m_sqlstr = << "END_SQL";
841
       SELECT 
842
             '__enumCLEARQUEST_DEVI_ID__' || '_' || si.dbid as iss_uid,
843
              __enumCLEARQUEST_DEVI_ID__ AS iss_db,
844
              si.dbid AS iss_id,
845
              si.new_num AS iss_num,
846
              si.headline AS summary,
847
              sdef.name AS status,
848
              si.priority AS priority,
849
              dbms_lob.substr( si.releaseinfo, 4000, 1 )as releaseinfo,
850
              si.issue_type AS issue_type,
851
              si.release_part1,
852
              si.release_part2,
853
              si.release_part3,
854
              si.project,
855
              si.product,
856
              si.package_ref,
857
              dbms_lob.substr( si.notes_log, 4000, 1 ),
858
              dbms_lob.substr( si.description, 4000, 1 ),
859
              NULL AS release_id,
860
              NULL AS client_ref,
861
              NULL AS severity,
862
              NULL AS cr_internal,
863
              NULL AS cr_external,
864
              sp.fullname AS submitter,
865
              si.submit_date,
866
              ow.fullname AS owner,
867
              ap.fullname AS approver
868
       FROM release_manager.CQ_software_issue si INNER JOIN
869
            release_manager.CQ_statedef sdef ON si.state = sdef.id INNER JOIN
870
            release_manager.CQ_users sp ON si.submitter = sp.dbid INNER JOIN
871
            release_manager.CQ_users ow ON si.owner = ow.dbid INNER JOIN
872
            release_manager.CQ_users ap ON si.approver = ap.dbid
873
       WHERE si.dbid IN ( __DEVIiss__ )
874
       ORDER BY iss_num ASC
875
END_SQL
876
 
877
        my @items = qw(
878
            iss_uid
879
            iss_db
880
            iss_id
881
            iss_num
882
            summary
883
            status
884
            priority
885
            releaseinfo
886
            issue_type
887
            release_part1
888
            release_part2
889
            release_part3
890
            project
891
            product
892
            package_ref
893
            notes_log
894
            description
895
            release_id
896
            client_ref
897
            severity
898
            cr_internal
899
            cr_external
900
            submitter
901
            submit_date
902
            owner
903
            approver
904
            );
905
 
906
    #
907
    #   Create a list of issues to extract
908
    #       Create a part of an 'in ( xxx xxx )' clause
909
    #       Push a dummy entry (-1) to ensure the list is never empty
910
    #
911
    my @inList;
912
    push @inList, -1;
913
    foreach my $entry ( keys %ClearQuestIssueData) {
914
        push @inList, $ClearQuestIssueData{$entry}{iss_id};
915
        }
916
 
917
    my $inList = join(',',sort @inList);
918
 
919
    #
920
    #   Insert data into the SQL string
921
    #
922
    $m_sqlstr =~ s~__enumCLEARQUEST_DEVI_ID__~4~g;
923
    $m_sqlstr =~ s~__DEVIiss__~$inList~;
924
 
925
    #
926
    #   Perform the query
927
    #       Merge the information from the ClearQuest Database into the hash of data from RM
928
    #
929
   performSqlQueryCallback($fname,
930
                           $m_sqlstr,
931
                           sub {
932
                               my $pHash = \%{$ClearQuestIssueData{$_[0][0]}} ;
933
                               populateHash( $pHash, $_[0], \@items);
934
                               push @ClearQuestIssues, $pHash;
935
                               }
936
                           );
937
 
938
    #DebugDumpData("ClearQuestIssueData", \%ClearQuestIssueData);
939
    #DebugDumpData("ClearQuestIssues", \@ClearQuestIssues);
940
}
941
 
942
#-------------------------------------------------------------------------------
943
# Function        : cleanIssueTest 
944
#
945
# Description     : Clean up multi-line issue text
946
#
947
# Inputs          : Text to clean 
948
#
949
# Returns         : Cleaned text
950
#
951
sub cleanIssueTest
952
{
953
    my ($data) = @_;
954
    #
955
    #   Clean multiline items
956
    #
957
    if ($data && $data =~ m~\n|\r~)
958
    {
959
        $data =~ tr~\r~\n~;
960
        $data =~ tr~\n~\n~s;
961
        $data =~ s~\n~<br>~g;
962
        $data =~ s~<br><br>~<br>~gi;
963
    }
964
  return $data;
965
}
966
 
967
#-------------------------------------------------------------------------------
968
# Function        : GetJiraIssues
969
#
970
# Description     : Get the Jira issues for the current package
971
#                   Extract data from the Jira REST API
972
#
973
# Inputs          : 
974
#
975
# Returns         : 
976
#
977
sub GetJiraIssues
978
{
979
    if (@JiraIssueList)
980
    {
981
        #
982
        #   Build up a JSON request to be posted to Jira
983
        #
984
        my $jsonRequest;
985
        $jsonRequest->{jql} = "key in (".join(',', @JiraIssueList).")";
986
        $jsonRequest->{startAt} = 0;
987
        $jsonRequest->{maxResults} = scalar @JiraIssueList;
988
        $jsonRequest->{validateQuery} = "false";
989
        @{$jsonRequest->{fields}} = qw(key summary status priority issuetype resolution 
990
                                       description created resolutiondate project reporter
991
                                       components assignee);
992
 
993
        my $json_text = to_json ($jsonRequest );
994
 
995
        #
996
        #   Issue the Query
997
        #       Tried to get LWP to do the Basic Authorization - but no joy
998
        #       Create the header entry my self
999
        #
1000
        my $rv;
1001
        my $ua = LWP::UserAgent->new( timeout => 30 );
1002
        $rv = $ua->post( $ENV{GBE_JIRA_URL}. "/rest/api/2/search",
1003
                       'Authorization' => 'Basic ' . encode_base64(join(':',$ENV{GBE_JIRA_USERNAME}, $ENV{GBE_JIRA_PASSWORD})),
1004
                       'Content-Type' => 'application/json',
1005
                       'Content' => $json_text,
1006
                       );
1007
 
1008
        unless ($rv->is_success) {
1009
            DebugDumpData("Jira Request", $rv);
1010
            Error("Jira Issue Access:", $rv->status_line);
1011
        }
1012
        my $rx_json = from_json($rv->content);
1013
 
1014
        #
1015
        #   Extract Issue information from the resultant json (now a hash)
1016
        #
1017
        foreach my $entry ( @{$rx_json->{'issues'}}) {
1018
            my %data;
1019
 
1020
            $data{'priority'} = $entry->{fields}{priority}{name};
1021
            $data{'summary'} = cleanIssueTest($entry->{fields}{summary});
1022
            $data{'description'} = cleanIssueTest($entry->{fields}{description});
1023
            $data{'created'} = $entry->{fields}{created};
1024
            $data{'reporter'} = $entry->{fields}{reporter}{displayName};
1025
            $data{'reporter_email'} = $entry->{fields}{reporter}{emailAddress};
1026
            $data{'status'} = $entry->{fields}{status}{name};
1027
            $data{'resolution'} = $entry->{fields}{resolution}{name};
1028
            $data{'resolutiondate'} = $entry->{fields}{resolutiondate};
1029
            $data{'type'} = $entry->{fields}{issuetype}{name};
1030
            $data{'url'} = $entry->{self};
1031
            $data{'key'} = $entry->{key};
1032
            $data{'project'} = $entry->{fields}{project}{name};
1033
            $data{'category'} = $entry->{fields}{projectCategory}{name};
1034
            $data{'assignee'} = $entry->{fields}{assignee}{displayName};
1035
            $data{'assignee_email'} = $entry->{fields}{assignee}{emailAddress};
1036
 
1037
            foreach my $item ( @{$entry->{fields}{components}} ) {
1038
                push @{$data{'category'}}, $item->{name};
1039
            }
1040
            push @JiraIssues, \%data;
1041
        }
1042
    }
1043
}
1044
 
1045
 
1046
#-------------------------------------------------------------------------------
1047
#   Documentation
1048
#
1049
 
1050
=pod
1051
 
1052
=for htmltoc    SYSUTIL::
1053
 
1054
=head1 NAME
1055
 
1056
jats_get_releasenote_data - Get Release Note Data
1057
 
1058
=head1 SYNOPSIS
1059
 
1060
 jats get_releasenote_data [options]
1061
 
1062
 Options:
1063
    -help              - Brief help message
1064
    -help -help        - Detailed help message
1065
    -man               - Full documentation
1066
    -verbose           - Display additional progress messages
1067
    -pvid=nn           - PVID of package to process
1068
    -outfile=name      - [Optional] Name of the output XML file
1069
 
1070
 
1071
=head1 OPTIONS
1072
 
1073
=over 8
1074
 
1075
=item B<-help>
1076
 
1077
Print a brief help message and exits.
1078
 
1079
=item B<-help -help>
1080
 
1081
Print a detailed help message with an explanation for each option.
1082
 
1083
=item B<-man>
1084
 
1085
Prints the manual page and exits.
1086
 
1087
=item B<-pvid=nn>
1088
 
1089
This option provides identifies the PackageVersion to be processed.
1090
 
1091
This option is mandatory.
1092
 
1093
=item B<-outfile=name>
1094
 
1095
This option specifies the output file name.
1096
 
1097
If not provided by the user the output filename will be created in the current directory
1098
and it will be named after the package name and package version.
1099
 
1100
If the filename does not end in .xml, then .xml will be appended to the file name.
1101
 
1102
=back
1103
 
1104
=head1 DESCRIPTION
1105
 
1106
This utility program is used to extract sufficient information from Release Manager and other
1107
associated databases so that a Release Note can be created.
1108
 
1109
The extracted data is stored in an XML format. The intent is that XSLT will be used to create
1110
an HTML based release note.
1111
 
1112
 
1113
=head1 EXAMPLE
1114
 
1115
=head2 jats get_releasenote_data -pvid=983058 -outfile=tmpdata.xml
1116
 
1117
This will locate a package-version with an id of 983058, extrat required information and create
1118
an XML file called tmpdata.xml.
1119
 
1120
=cut