Subversion Repositories DevTools

Rev

Rev 7361 | Go to most recent revision | Details | Compare with Previous | 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   : process_release_notes.pl
5
# Module type   : JATS Utility
6
# Compiler(s)   : Perl
7
# Environment(s): jats
8
#
9
# Description   : Poll RM and generate Release Notes as required
10
#                 Must run on the same machine as the package archive
11
#                 It directly manipulates the target package
12
#                 Requires access to the machines sudo mechism
13
#
14
# Usage         : See POD at the end of this file
15
#
16
#......................................................................#
17
 
18
require 5.008_002;
19
 
20
use strict;
21
use warnings;
22
use JatsError;
23
use JatsSystem;
24
use Getopt::Long;
25
use Pod::Usage;                             # required for help support
26
use File::Temp qw/ tempfile tempdir /;
27
use LWP::UserAgent;
28
use HTTP::Request::Common 'POST';
29
use Fcntl ':flock';
30
use FindBin;                                # Determine the current directory
31
 
32
use JatsEnv;
33
use JatsRmApi;
34
use FileUtils;
35
 
36
use DBI;
37
 
38
my $VERSION = "1.0.0";                      # Update this
39
my $GBE_DPKG = $ENV{GBE_DPKG};              # Sanitised by Jats
4698 dpurdie 40
my $GBE_RM_URL = $ENV{GBE_RM_URL};
4625 dpurdie 41
my $RM_DB;
42
my $tempdir;
43
my $sudoUtilsDir = '/home/releasem/sbin';
44
my $lockFile = '/tmp/JATSRN_LOCK';
6762 dpurdie 45
my $lockFile1 = '/tmp/JATSRN_LOCK1';
4625 dpurdie 46
my $scriptDir = "$FindBin::Bin";
6758 dpurdie 47
my $maxRunTime = 5 * 60;                        # Seconds. Time to first warning
48
my $maxRunTime1 = 5 * 60;                       # Seconds. Time to following warnings
4625 dpurdie 49
 
50
#
51
#   Options
52
#
53
my $opt_verbose = 0;
54
my $opt_help = 0;
55
my $opt_age = 2;
56
my $opt_keepTemp = 0;
57
my $opt_status = 0;
58
my $opt_pvid;
59
 
60
#
61
#   Package information
62
#
63
my @Packages;
5586 dpurdie 64
my @packageItems = qw( PV_ID -LINK_PV_ID RTAG_ID NAME VERSION PKG_ID PROJ_ID RNINFO BUILD_TYPE BS_ID);
4625 dpurdie 65
my %rmConfig;
66
 
67
#-------------------------------------------------------------------------------
68
# Function        : Main Entry
69
#
70
# Description     :
71
#
72
# Inputs          :
73
#
74
# Returns         :
75
#
76
my $result = GetOptions (
77
                'help+'         => \$opt_help,          # flag, multiple use allowed
78
                'manual:3'      => \$opt_help,          # flag
79
                'verbose:+'     => \$opt_verbose,       # flag
80
                'age:i'         => \$opt_age,           # Number
81
                'keeptemp!'     => \$opt_keepTemp,      # flag
82
                'status+'       => \$opt_status,        # flag
83
                'pvid:i'        => \$opt_pvid,          # Number
84
                );
85
 
86
#
87
#   Process help and manual options
88
#
89
pod2usage(-verbose => 0, -message => "Version: $VERSION")  if ($opt_help == 1  || ! $result);
90
pod2usage(-verbose => 1)  if ($opt_help == 2);
91
pod2usage(-verbose => 2)  if ($opt_help > 2);
92
 
93
ErrorConfig( 'name'    =>'RelNotes', 
94
             'verbose' => $opt_verbose );
95
$opt_verbose-- if ($opt_verbose > 0);
96
#
97
#   Sanity Test
98
#
99
Error("Not running on a Unix System") unless ($ENV{GBE_UNIX});
100
Error("Sudo Utils not found: $sudoUtilsDir") unless ( -d $sudoUtilsDir);
7361 dpurdie 101
Warning("Not running as a suitable user" ) unless ($ENV{USER} eq 'buildadm' || $ENV{USER} eq 'releasem' || $ENV{USER} eq 'pkgadm');
4625 dpurdie 102
EnvImport ('GBE_PERL');
103
 
104
#
105
#   Ensure only one instance is running
106
#   PerlMonks say to use $0 as the lock file, but that did not work.
6754 dpurdie 107
#       Perhaps the file was open in an editor
108
#       Solution: Create my own file
109
#   Generate an error if the script has been running for too long    
4625 dpurdie 110
#
6758 dpurdie 111
makeFile($lockFile);
112
makeFile($lockFile1) unless -f $lockFile1;
4625 dpurdie 113
 
114
open (my $self, '<', $lockFile) || Error("Couldn't open self: $!");
6754 dpurdie 115
unless ( flock ($self, (LOCK_EX | LOCK_NB)) ){
6758 dpurdie 116
 
117
    my $runTime = getFileTime($lockFile);
118
    my $runTime1 = getFileTime($lockFile1);
119
 
120
    if ( $runTime > $maxRunTime && $runTime1 >= $maxRunTime1) {
121
        unlink $lockFile1;
122
        makeFile($lockFile1);
6754 dpurdie 123
        Error("Script has been running for too long.: $runTime(s)");
124
    }
125
    exit(1);
126
}
4625 dpurdie 127
 
128
#
129
#   Init parameters
130
#
131
$tempdir = tempdir('/tmp/JATSRN_XXXXXX',CLEANUP => !$opt_keepTemp);
132
Warning("Need to remove tempdir: " . DisplayPath($tempdir)) if $opt_keepTemp;
133
Verbose("Tempdir:" , DisplayPath($tempdir));
134
Verbose("scriptDir:" , DisplayPath($scriptDir));
135
 
136
#   Force GBE_ABT. Currently the Release Manager proxy password only works
137
#   When used in this mode
138
$ENV{GBE_ABT} = 1 unless defined $ENV{GBE_ABT};
139
 
140
#
141
#   User RW password, if provided
142
#
143
$ENV{GBE_RM_USERNAME} = $ENV{GBE_RM_USERNAME_RW} if (exists $ENV{GBE_RM_USERNAME_RW});
144
$ENV{GBE_RM_PASSWORD} = $ENV{GBE_RM_PASSWORD_RW} if (exists $ENV{GBE_RM_PASSWORD_RW});
145
 
146
if ($ENV{GBE_ABT} && $ENV{GBE_RM_USERNAME} && $ENV{GBE_RM_USERNAME} !~ m~]$~ )
147
{
148
    Verbose("Access RM database as proxy user");
149
    $ENV{GBE_RM_USERNAME} = $ENV{GBE_RM_USERNAME} . '[release_manager]'; 
150
}
151
 
152
#
153
#   Interogate the RM database and locate packages that need to be processed
154
#
155
$opt_pvid ? LocatePackagesByPvid() : LocatePackages();
156
Verbose("Package to process:" . scalar @Packages);
157
#DebugDumpData("Packages", \@Packages);
158
 
159
#
160
#   Process each found entry
161
#
162
foreach my $entry ( @Packages)
163
{
164
    GenerateReleaseNote( $entry);
165
}
166
 
167
unlink $lockFile;
6758 dpurdie 168
unlink $lockFile1;
4625 dpurdie 169
exit 0;
170
 
171
#-------------------------------------------------------------------------------
172
# Function        : LocatePackages 
173
#
174
# Description     : Locate packages in need of Release Notes
5586 dpurdie 175
#                   The hard part is handling patches
176
#                   The sql will
177
#                       1) Locate packages that may need a release note
178
#                       2) Trace back to the most likly Release that the pakage is in
179
#                          For patches - it may be in many released
180
#                                        Use the latest
4625 dpurdie 181
#
182
# Inputs          : None
183
#
184
# Returns         : Nothing
185
#                   Populates the @Packages array
186
#
187
sub LocatePackages
188
{
189
    my $m_sqlstr =
5586 dpurdie 190
        "select * from (
191
          select aa.*, 
192
              rc.RTAG_ID,
193
              pkg.PKG_NAME, 
194
              pv.PKG_VERSION, 
195
              pv.pkg_id,
196
              rt.PROJ_ID, 
197
              pv.release_notes_info,
198
              pv.build_type,
199
              pv.BS_ID,
200
              TRUNC(sysdate - pv.modified_stamp ) AS age,
201
              row_number() OVER (PARTITION BY aa.pv_id, pkg.pkg_name, pv.pkg_version ORDER BY rc.rtag_id desc) rn
202
          from (
203
            SELECT pv.pv_id, NVL( pp.PV_ID, pv.pv_id) as LINK_PV_ID
204
              FROM release_manager.package_versions pv, release_manager.PACKAGE_PATCHES pp
205
              WHERE (release_notes_info IS NULL
206
              OR (release_notes_info LIKE 'MSG:%'
207
              AND release_notes_info != 'MSG:5' ))
208
              AND pv.dlocked          = 'Y'
209
              AND pv.modified_stamp   > (sysdate - $opt_age)
210
              AND pv.pv_id = pp.PATCH_ID(+)
211
              ) aa,
212
              release_manager.package_versions pv, 
213
              release_manager.packages pkg, 
214
              release_manager.RELEASE_CONTENT rc, 
215
              release_manager.RELEASE_TAGS rt
216
              where aa.PV_ID = pv.PV_ID
217
              AND pv.PKG_ID = pkg.PKG_ID
218
              and RC.pv_id = aa.LINK_PV_ID
219
              AND rt.RTAG_ID = rc.RTAG_ID
220
        ) where RN = 1";
4625 dpurdie 221
 
222
    populateArrayFromSql('LocatePackages', \@Packages, $m_sqlstr, \@packageItems);
223
#    DebugDumpData("Packages", \@Packages);
224
}
225
 
226
#-------------------------------------------------------------------------------
227
# Function        : LocatePackagesByPvid 
228
#
229
# Description     : Locate one package, as specified by its PVID
230
#                   This mode is only used in testing  
231
#
232
# Inputs          : Global: $opt_pvid 
233
#
234
# Returns         : Populate the @Packages array
235
#
236
sub LocatePackagesByPvid
237
{
5586 dpurdie 238
    #   Extract: PV_ID LINK_PV_ID RTAG_ID NAME VERSION PKG_ID PROJ_ID RNINFO AGE 
4625 dpurdie 239
    my $m_sqlstr = "
5586 dpurdie 240
                SELECT pv.pv_id,
241
                       pv.pv_id, 
4625 dpurdie 242
                       rc.rtag_id, 
243
                       pkg.pkg_name, 
244
                       pv.pkg_version, 
245
                       pv.pkg_id, 
246
                       rt.proj_id, 
4706 dpurdie 247
                       pv.release_notes_info,
248
                       pv.build_type,
249
                       pv.BS_ID
4625 dpurdie 250
                FROM release_manager.package_versions pv, 
251
                     release_manager.release_content rc, 
252
                     release_manager.packages pkg, 
253
                     release_manager.release_tags rt
254
                WHERE pv.pv_id = rc.pv_id
255
                AND pkg.pkg_id = pv.pkg_id
256
                AND rc.rtag_id = rt.rtag_id
257
                AND pv.pv_id = $opt_pvid
258
                ";
259
 
260
    populateArrayFromSql('LocatePackagesByPvid', \@Packages, $m_sqlstr, \@packageItems);
261
    #DebugDumpData("Packages", \@Packages);
262
}
263
 
264
#-------------------------------------------------------------------------------
265
# Function        : GenerateReleaseNote  
266
#
267
# Description     : Generate One Release Note
268
#                   Invoke several JATS utilities to do the hard work
269
#
270
# Inputs          : $entry          - Hash of useful infomation
271
#
272
# Returns         : Nothing
273
#                   Will exit on error
274
#
275
sub GenerateReleaseNote
276
{
277
    my ($entry) = @_;
278
    my $outfile;
279
    my $rv;
280
    my @args;
281
 
282
    #DebugDumpData("Entry", $entry);
283
    Message("-------------------- $entry->{NAME}, $entry->{VERSION}") if $opt_status || $opt_verbose;
284
 
285
    my $pkgBase = catdir($GBE_DPKG, $entry->{NAME}, $entry->{VERSION});
286
    Verbose("Processing: $pkgBase");
287
 
288
    #
4706 dpurdie 289
    #   Handle special class of packages
290
    #       Manually Built
291
    #       No Build Standard
292
    #       Not in dpkg_archive
293
    #   Example: unit_test_br_kcm_ct_saftp
294
    #   This type of package appears to be a place holder
295
    #   Still needs some level of processing
4625 dpurdie 296
    #
4706 dpurdie 297
    if ($entry->{BUILD_TYPE}  eq 'M' && $entry->{BS_ID} == 3 && ! -d $pkgBase)
298
    {
299
        Verbose ("Placeholder package detected");
300
        #DebugDumpData("Entry", $entry);
301
        updatePlaceHolderRmNoteInfo($entry);
302
        $rv = 0;
303
    }
304
    else
305
    {
306
        #
307
        #
308
        unless (-d $pkgBase) {
309
            Warning("Package not in archive: $pkgBase");
310
            return;
311
        }
4625 dpurdie 312
 
4706 dpurdie 313
        #
314
        #   Make the target Package Version Writable and Ensure that the doc directory
315
        #   exists. This is done via a script that is invoked with SUDO, partially to
316
        #   interwork with the existing system  
317
        #
318
        runSudoCommand('make_writable', 'dpkg_archive', $entry->{NAME},$entry->{VERSION});
319
        runSudoCommand('make_docFolder', 'dpkg_archive', $entry->{NAME},$entry->{VERSION}, 'doc');
4625 dpurdie 320
 
4706 dpurdie 321
        #
322
        #   Get the basic data required for the Release Note
323
        #   jats jats_get_releasenote_data.pl -pvid=1002782
324
        #
325
        $outfile = catdir($tempdir, join('_',$entry->{NAME},$entry->{VERSION})) . '.xml';
326
        $rv = localTool('jats_get_releasenote_data', '-verbose', $opt_verbose, '-pvid', $entry->{PV_ID}, '-outfile', $outfile );
327
 
328
        #
329
        #   Generate the actual release note and update the Release Manager
330
        #   jats jats_gen_releasenote.pl -releasenote=mcrdemo_1.2.3157.cr.xml -UpdateRmFiles
331
        unless ($rv)
332
        {
333
            $rv = localTool('jats_gen_releasenote.pl', '-verbose', $opt_verbose, '-UpdateRmFiles', '-releasenote', $outfile);
334
        }
335
 
336
        #
7383 dpurdie 337
        #   Make the target PackageVersion ReadOnly
4706 dpurdie 338
        #
7383 dpurdie 339
        runSudoCommand('make_readonly', 'dpkg_archive', $entry->{NAME},$entry->{VERSION});
340
 
4706 dpurdie 341
        #
7383 dpurdie 342
        #   TarZip the package
343
        #   This will be used simplify transfering the package to dpkg_acrhive replicas
344
        #       
345
        runSudoCommand('make_tarzip', 'dpkg_archive', $entry->{NAME},$entry->{VERSION});
4625 dpurdie 346
    }
347
 
7383 dpurdie 348
    #   Release note complete - or failed
349
    #       Signal End of Package Processing - which will trigger blat
350
    #   Do this even if we have a Release Note Failure
351
    #   
4625 dpurdie 352
    #    make_release_changed 
353
    #       archive=archive-path 
4632 dpurdie 354
    #       pkg_name="package-name" 
355
    #       pkg_version="package-version" 
4625 dpurdie 356
    #       rtag_id=release-tag-id 
357
    #       pkg_id=package-id 
358
    #       pv_id=package-version-id 
359
    #       proj_id=project-id 
360
    #       mode_id=change-mode-id (1 pkg added, 2 pkg removed, 3 pkg released)
6923 dpurdie 361
    #           3 = enumRELEASE_CHANGE_MODE_PKG_RELEASED
4625 dpurdie 362
    #
4632 dpurdie 363
    #   Note: The ReleasedPackagereport tool parses the make_released_changed entries
364
    #         It requires quotes on the pkg_name and pkg_version for correct parsing
365
    #
4625 dpurdie 366
    push @args, 'archive=dpkg_archive';
367
    push @args, 'mode_id=3';
7383 dpurdie 368
    push @args, 'pkg_name="'    . $entry->{NAME}     . '"';
369
    push @args, 'pkg_version="' . $entry->{VERSION}  . '"';
370
    push @args, 'rtag_id='      . $entry->{RTAG_ID};
371
    push @args, 'pkg_id='       . $entry->{PKG_ID};
372
    push @args, 'pv_id='        . $entry->{PV_ID};
373
    push @args, 'proj_id='      . $entry->{PROJ_ID};
4625 dpurdie 374
 
375
    runSudoCommand('make_release_changed', @args);
376
 
377
    #
378
    #   Email interested users
379
    #
380
    notifyInterestedUsers($entry);
381
 
382
    Error ("Did not generate Release Note: $entry->{NAME}, $entry->{VERSION}") if ($rv);
383
}
384
 
385
#-------------------------------------------------------------------------------
4706 dpurdie 386
# Function        : updatePlaceHolderRmNoteInfo 
387
#
388
# Description     : Insert Release Note Info into the Release Manager Database
389
#                   This has the side effect that RM will see the Release Note
390
#                   as being fully generated.
391
#
392
#                   Used only by special PlaceHolder packages
393
#
394
# Inputs          : $entry          - Hash of useful infomation
395
#
396
# Returns         : 
397
#
398
sub updatePlaceHolderRmNoteInfo
399
{
400
    my ($entry) = @_;
401
 
402
    executeRmQuery (
403
        'updateRmNoteInfo', 
404
        'update release_manager.package_versions set release_notes_info=\'MSG:5\' where pv_id=' . $entry->{PV_ID}
405
        );
406
}
407
 
408
#-------------------------------------------------------------------------------
4625 dpurdie 409
# Function        : localTool 
410
#
411
# Description     : Run a jats tool from the same directory as this script 
412
#
413
# Inputs          : $name           - Name of the script
414
#                   ...             - Arguments for the command
415
#
416
# Returns         : 
417
#
418
sub localTool
419
{
420
    my $cmd = shift;
421
    $cmd .= '.pl' unless ( $cmd =~ m~\.pl$~i );
422
    $cmd = catdir($scriptDir, $cmd);
423
    Error ("Command not found: $cmd") unless -f $cmd;
424
 
425
    return System ( '--NoShell', $::GBE_PERL, $cmd, @_ );
426
}
427
 
428
 
429
#-------------------------------------------------------------------------------
430
# Function        : notifyInterestedUsers  
431
#
432
# Description     : A user can register interest in a package (name) being built in a 
433
#                   specific Project 
434
#                   Perhaps this should be done by the build tool, but at the moment 
435
#                   this release note generation process is really a part of the build
436
#
437
#                   NOTE: Similar code exists in the RM web server to handle manually
438
#                         released packages.
439
#                   
440
# Inputs          : $entry          - Hash of useful infomation
441
#
442
# Returns         : 
443
#
444
sub notifyInterestedUsers
445
{
446
    my ($entry) = @_;
447
    my @userList;
448
 
449
    #
450
    #   Determine interested users
451
    #
452
    my $m_sqlstr = "SELECT U.user_email, prj.proj_name, rt.rtag_name, pkg.pkg_name, pv.pkg_version ,pv.pv_id, rt.rtag_id
4706 dpurdie 453
        FROM RELEASE_MANAGER.PACKAGE_INTEREST PI, 
454
             RELEASE_MANAGER.PACKAGES PKG, 
455
             RELEASE_MANAGER.PACKAGE_VERSIONS PV, 
456
             RELEASE_MANAGER.USERS U,
457
             RELEASE_MANAGER.RELEASE_TAGS RT, 
458
             RELEASE_MANAGER.PROJECTS PRJ 
4625 dpurdie 459
        WHERE PKG.PKG_ID = PI.PKG_ID 
460
          AND RT.RTAG_ID = $entry->{RTAG_ID}
461
          AND PV.PV_ID = $entry->{PV_ID}
462
          AND PV.PKG_ID = PKG.PKG_ID 
463
          AND PRJ.PROJ_ID = RT.PROJ_ID 
464
          AND PRJ.PROJ_ID = PI.PROJ_ID 
465
          AND U.USER_ID = PI.USER_ID";
466
 
467
    my @items = qw( USER_EMAIL PROJ_NAME RTAG_NAME PKG_NAME PKG_VERSION PV_ID RTAG_ID );
468
 
469
    populateArrayFromSql('notifyInterestedUsers', \@userList, $m_sqlstr, \@items);
470
 
471
    #
472
    #   Do we have something to do
473
    #
474
    return unless (@userList);
475
    #DebugDumpData("userList", \@userList);
476
 
477
    #   Ensure we have basic emailing information
478
    #
479
    getRmConfig();
480
 
481
    #
482
    #   Send Email to all the required users
483
    #   Note: This emailer requires a sendmail utility
484
    #
485
    foreach my $entry ( @userList)
486
    {
487
        #$entry->{USER_EMAIL} = 'dpurdie@vixtechnology.com';
488
        #Debug0("Sending email to David Purdie indead of real user");
489
 
4698 dpurdie 490
        my $rnUrl = $GBE_RM_URL . "/fixed_issues.asp?pv_id=$entry->{PV_ID}&rtag_id=$entry->{RTAG_ID}";
4625 dpurdie 491
        my $subject = "Package Release Notification: $entry->{PKG_NAME} $entry->{PKG_VERSION}";
4698 dpurdie 492
        my $content = "Version <a href='$rnUrl'>$entry->{PKG_VERSION}</a> of Package $entry->{PKG_NAME} in Project $entry->{PROJ_NAME} on Release Branch $entry->{RTAG_NAME} has been released.";
493
           $content .= "<p>Package Link: $rnUrl";
4625 dpurdie 494
           $content .= "<p>You have received this email as a result of your interest in this package. If you do not wish to receive further emails then remove your package interest from the notifications area in Release Manager.";
495
 
496
 
497
        my $req = POST( 'mailto:' . $entry->{USER_EMAIL},
498
            From         => $rmConfig{'BUILD FAILURE MAIL SENDER'},
499
            CC           => 'buildadm@vixtechnology.com',
500
            Date         => scalar localtime,
501
            Subject      => $subject,
502
            Content_Type => qq(text/html),
503
            Content      => $content,
504
        );
505
 
506
        my $response = LWP::UserAgent->new->request($req);
507
        if ($response->code != 202)
508
        {
509
            Warning("Email Send Error: $response->code");
510
            #DebugDumpData("Response", \$response);
511
        }
512
    }
513
}
514
 
515
 
516
#-------------------------------------------------------------------------------
517
# Function        : getRmConfig 
518
#
519
# Description     : Get Basic config from Release Manager
520
#                   Only do it once
521
#
522
#                   Just need:
523
#                       'BUILD FAILURE MAIL SENDER'
524
#                       'MAIL SERVER'
525
#
526
# Inputs          : None
527
#
528
# Returns         : Populates a global hash
529
#
530
sub getRmConfig
531
{
532
    return if keys(%rmConfig) > 0;
533
    my $m_sqlstr = "SELECT * from BUILD_SERVICE_CONFIG";
534
 
535
    performSqlQueryCallback('getRmConfig', 
536
                            $m_sqlstr, 
537
                            sub { 
538
                                my ($pRow) = @_;
539
                                $rmConfig{ $pRow->[0] } = $pRow->[1];
540
                                }
541
                            );
542
#DebugDumpData("rmConfig", \%rmConfig);
543
}
544
 
545
 
546
#-------------------------------------------------------------------------------
547
# Function        : runSudoCommand 
548
#
549
# Description     : Run a Unix command as root via the sodo system
550
#                   Requires that target commands be available
551
#                   Requires sudo to be configured to allow this user to run them
552
#
553
# Notes           : The sudoers file on the archive server needs to be configured to allow:
554
#                       This user to run programs from /home/releasem/sbin without a password
555
#                       The users sudo credentials must not timeout (or be used)
556
#
557
# Inputs          : prog            - Command to run
558
#                   arguments       - Command arguments
559
#
560
# Returns         : Nothing 
561
#
562
sub runSudoCommand
563
{
564
    my ($prog, @arguments) = @_;
565
    my $cmd;
566
    my $rv;
567
 
568
    #
569
    #   Construct command
570
    #
571
    $cmd = catdir($sudoUtilsDir, $prog);
572
    $rv = System('--NoShell','sudo','-n', $cmd, @arguments);
573
    Warning("SudoCmd Result: $prog: $rv") if ($rv);
574
}
575
 
576
#-------------------------------------------------------------------------------
577
# Function        : performSqlQueryCallback 
578
#
579
# Description     : Perform a general Sql query and invoke a user function for
580
#                   each row of results
581
#
582
# Inputs          : $fname                  - Name of query for error reporting
583
#                   $m_sqlstr               - Query string
584
#                   $f_process              - Function called for each row in the result
585
#                                             Use closure to have callback modify other data
586
#
587
# Returns         : Number of rows found
588
#
589
sub performSqlQueryCallback
590
{
591
    my ($fname, $m_sqlstr, $f_process ) = @_;
592
    my $found = 0;
593
 
594
    #
595
    #   Connect to the database - once
596
    #
597
    connectRM(\$RM_DB, $opt_verbose) unless $RM_DB;
598
 
599
    $m_sqlstr =~ s~\s+~ ~g;
600
    Verbose3("SQL:", $m_sqlstr);
601
    my $sth = $RM_DB->prepare($m_sqlstr);
602
    if ( defined($sth) )
603
    {
604
        if ( $sth->execute( ) )
605
        {
606
            if ( $sth->rows )
607
            {
608
                while ( my @row = $sth->fetchrow_array )
609
                {
610
                    $found++;
611
                    &$f_process(\@row);
612
                }
613
            }
614
            $sth->finish();
615
        }
616
        else
617
        {
618
            Error("$fname:Execute failure: $m_sqlstr", $sth->errstr() );
619
        }
620
    }
621
    else
622
    {
623
        Error("$fname:Prepare failure" );
624
    }
625
 
626
    unless ( $found )
627
    {
628
        Verbose("$fname:No data found");
629
    }
630
    return $found;
631
}
632
 
633
#-------------------------------------------------------------------------------
634
# Function        : populateArrayFromSql 
635
#
636
# Description     : Issue an SQL query and push the results into an array of hashes
637
#                   where each row from the query is a hash and the entire result is an 
638
#                   array 
639
#
640
# Inputs          :     name                - For error reporting
641
#                       pArray              - Ref to the output array
642
#                       sql                 - Sql to process
5586 dpurdie 643
#                       pItems              - Array of items to extract
4625 dpurdie 644
#                                             Must match the SQL SELECT arguments
645
#                                             Item names starting with '-' do not end up in the
646
#                                             generated XML
647
# Returns         : 
648
#
649
sub populateArrayFromSql
650
{
651
    my ($fname, $pArray, $m_sqlstr, $pItems) = @_;
652
 
653
    performSqlQueryCallback($fname, 
654
                            $m_sqlstr, 
655
                            sub { 
656
                                my ($pRow) = @_;
657
                                my %entry;
658
                                push @{$pArray}, populateHash( \%entry, $pRow, $pItems);
659
                                }
660
                            );
661
#DebugDumpData("populateArrayFromSql", $pArray);
662
}
663
 
664
#-------------------------------------------------------------------------------
665
# Function        : populateHash 
666
#
667
# Description     : Put an array of data items into a hash
668
#
669
# Inputs          : pHash           - ref to output hash
670
#                   pRow            - Ref to the row data 
671
#                   pItems          - Ref to an hash array of entry names
672
#
673
# Returns         : pHash
674
#
675
sub populateHash
676
{
677
    my ($pHash, $pRow, $pItems) = @_;
678
 
679
    foreach my $item ( @{$pItems} ) {
680
        my $data = shift @{$pRow};
681
 
682
        if (defined $data)
683
        {
684
            $data =~ s~^\s+~~;
685
            $data =~ s~\s+$~~;
686
 
687
            #
688
            #   Store in hash
689
            #
690
            $pHash->{$item} = $data;
691
        }
692
    }
693
    return $pHash;
694
}
695
 
696
#-------------------------------------------------------------------------------
4706 dpurdie 697
# Function        : executeRmQuery 
698
#
699
# Description     : Execute a simple RM query. One that does not expect any return data
700
#
701
# Inputs          : $fname           - OprName, for error reporting
702
#                   $m_sqlstr        - SQL String
703
#
704
# Returns         : Will exit on error
705
#
706
sub executeRmQuery
707
{
708
    my ($fname, $m_sqlstr) = @_;
709
 
710
    #
711
    #   Connect to the Database - once
712
    #
713
    connectRM(\$RM_DB, 0) unless $RM_DB;
714
 
715
    Verbose2('ExecuteQuery:', $fname);
716
    #
717
    #   Create the full SQL statement
718
    #
719
    my $sth = $RM_DB->prepare($m_sqlstr);
720
    if ( defined($sth) )
721
    {
722
        if ( $sth->execute() )
723
        {
724
            $sth->finish();
725
        }
726
        else
727
        {
728
            Error("$fname: Execute failure: $m_sqlstr", $sth->errstr() );
729
        }
730
    }
731
    else
732
    {
733
        Error("$fname: Prepare failure");
734
    }
735
}
736
 
737
#-------------------------------------------------------------------------------
6766 dpurdie 738
# Function        : getFileTime  
739
#
740
# Description     : Get the timestamp from a file 
741
#
742
# Inputs          : Path to the file
743
#
744
# Returns         : Time since the file was created in seconds 
745
#
746
 
747
sub getFileTime
748
{
749
    my ($fname, $idx) = @_;
750
    my $stamp = (stat($fname))[8];
751
    if (defined $stamp) {
752
        $stamp = time() - $stamp;
753
    } else {
754
        $stamp = 0;
755
    }
756
    return $stamp;
757
}
758
 
759
#-------------------------------------------------------------------------------
760
# Function        : makeFile 
761
#
762
# Description     : Create a file
763
#
764
# Inputs          : Path to the file 
765
#
766
# Returns         : 
767
#
768
 
769
sub makeFile
770
{
771
    my ($name) = @_;
772
    my $fh;
773
    open( $fh, '>',$name);
774
    print $fh '';
775
    close $fh;
776
}
777
 
778
#-------------------------------------------------------------------------------
4625 dpurdie 779
#   Documentation
780
#
781
 
782
=pod
783
 
784
=for htmltoc    SYSUTIL::
785
 
786
=head1 NAME
787
 
788
process_release_notes - Create Release Notes for newly created packages
789
 
790
=head1 SYNOPSIS
791
 
792
 jats process_release_notes [options]
793
 
794
 Options:
795
    -help              - Brief help message
796
    -help -help        - Detailed help message
797
    -man               - Full documentation
798
    -verbose           - Display additional progress messages
799
    -pvid=nn           - PVID of package to process(test mode)
800
    -age=nn            - Examine packages created in last n days
801
    -keeptemp          - Keep the temp workspace
802
    -status            - Display status
803
 
804
=head1 OPTIONS
805
 
806
=over 8
807
 
808
=item B<-help>
809
 
810
Print a brief help message and exits.
811
 
812
=item B<-help -help>
813
 
814
Print a detailed help message with an explanation for each option.
815
 
816
=item B<-man>
817
 
818
Prints the manual page and exits.
819
 
820
=item B<-pvid=nn>
821
 
822
This option bypasses the normal mechanism of determining packages to be processed and 
823
will process just the specified package. This is normally only used to test the operation 
824
of the subsystem.
825
 
826
=item B<-age=nn>
827
 
7383 dpurdie 828
This option control the period of time period used in determining which packages to process. 
4625 dpurdie 829
 
830
The number is in days. The default value is 2 days.
831
 
832
=item B<-keeptemp>
833
 
834
If this option is specified, then the temporary directory created in the processing will be 
835
retained. The user is responsible for deleting the directory.
836
 
837
This option is normally only used in testing.
838
 
839
=item B<-status>
840
 
841
When set, this option will cause the program to display the package name and version of each
842
package being processed.
843
 
844
=back
845
 
846
=head1 DESCRIPTION
847
 
848
This utility program is apart of the Package Release process. It is an interim solution.
849
 
7383 dpurdie 850
The script is designed to be run as a cron job on the dpkg_archive server.
4625 dpurdie 851
 
852
It will scan the Release Manager database for packages that have been release, but do 
853
not yet have release notes. For each package it will then generate a Release Note by: 
854
 
855
=over 4
856
 
857
=item *
858
 
859
Invoke jats_get_releasenote_data to:
860
 
7383 dpurdie 861
Extract relevant information from
4625 dpurdie 862
 
863
=over 4
864
 
865
=item *
866
 
867
The Release Manager database
868
 
869
=item *
870
 
7383 dpurdie 871
the ClearQuest database (now contained within the Release Manager database)
4625 dpurdie 872
 
873
=item *
874
 
875
the Jira Issue server 
876
 
877
=back
878
 
879
and create and XML file.
880
 
881
=item *
882
 
883
Invoke jats_gen_releasenote to:
884
 
885
=over 4
886
 
887
=item *
888
 
7383 dpurdie 889
Process the XML file created above, and package list info found within the new package. 
4625 dpurdie 890
 
7383 dpurdie 891
If no package information is found then the utility will create a package list, but this is 
4625 dpurdie 892
much slower than having it created by the package builder.
893
 
894
=item *
895
 
896
Create an XML file containing all the package information
897
 
898
=item *
899
 
900
Create an HTML based Release Note, from the XML file. This file could also be used to create a Release note in another format if required. 
901
 
902
=item *
903
 
904
Transfer these two files into the package in dpkg_archive
905
 
906
=item *
907
 
908
Insert the packages file list into the Release Manager database.
909
 
910
=back
911
 
912
=item *
913
 
914
Make the package read-only. This will trigger any post-install processing of the 
915
package. This is only required for packages that form a part of the build system.
916
 
917
=item *
918
 
7383 dpurdie 919
Create a tar-zip of the package. This is stored within dpkg_archive and is available to other
920
tools to transfer the package as a single entity. The tarZip is only retained as long as it 
921
is needed by the other tools.
922
 
923
 
924
=item *
925
 
926
Flag that the package has been released. This may trigger the BLAT package file transfer process 
4625 dpurdie 927
and the package will be transferred to remote sites.
928
 
929
=item *
930
 
931
Determine the users that have registered interest in being informed when the package is released. 
932
It will then email these users.
933
 
934
=back
935
 
936
=head1 EXAMPLE
937
 
938
=head2 process_release_notes
939
 
940
This will perform a single scan of the Release Manager database and generate Release Notes as required.
941
 
942
=cut
943