/[drupal]/contributions/tricks/cvs-release-notes/cvs-release-notes.php
ViewVC logotype

Contents of /contributions/tricks/cvs-release-notes/cvs-release-notes.php

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.8 - (show annotations) (download) (as text)
Tue Jul 1 00:47:47 2008 UTC (16 months, 3 weeks ago) by bdragon
Branch: MAIN
CVS Tags: HEAD
Changes since 1.7: +5 -3 lines
File MIME type: text/x-php
Fix two bugs.
1) use continue; instead of next; to skip warning lines.
2) Don't bork on double newlines in the log message. (boolean test considers an empty string to be false!)
1 #!/usr/bin/php
2 <?php
3
4 // $Id: cvs-release-notes.php,v 1.7 2008/02/13 22:15:33 weitzman Exp $
5
6 /**
7 * @file
8 * Parses all CVS log messages between 2 release tags and automatically
9 * generates initial HTML for the release notes. This script must be
10 * run inside the root directory of a local CVS workspace of the project
11 * you want to generate release notes for. Assumes "cvs" is in your
12 * PATH, and that the workspace has already been checked out with the
13 * appropriate CVSROOT.
14 *
15 * Usage:
16 * cvs-release-notes.php [previous-release-tag] [current-release-tag]
17 *
18 * TODO:
19 * - Option to include patch committer if "by" isn't included in message
20 * - Pretty formatting of previous release version (instead of the tag)
21 * - Lookup issues on d.o to group changes by issue type (bug, feature)
22 * - Should strip out leading dashes: "- something"
23 * - Should remove the word "Patch " before patch #s so they are
24 * formatted consistently.
25 *
26 * @author Derek Wright (http://drupal.org/user/46549)
27 *
28 */
29
30 if (count($argv) < 3) {
31 usage("You must specify the release tags to compare");
32 }
33 $prev = $argv[1];
34 $cur = $argv[2];
35
36 // This line allows you keep one copy of this script at a given location.
37 // Setup a shell alias to this file and then just call the alias from the dir
38 // whose notes need generating.
39 chdir(getcwd());
40
41 if (!is_dir("CVS")) {
42 usage("You must run this script in a local CVS workspace for your project");
43 }
44
45 $changes = get_changes($prev, $cur);
46 print "<p>Changes since $prev:</p>\n";
47 print_changes($changes);
48
49
50 function usage($msg = NULL) {
51 global $argv;
52 if (!empty($msg)) {
53 print "ERROR: $msg\n";
54 }
55 print <<<EOF
56 Usage: $argv[0] [previous_release_tag] [current_release_tag]
57 For example:
58 $argv[0] DRUPAL-4-7--1-0 DRUPAL-4-7--1-1
59
60 EOF;
61 exit(empty($msg) ? 0 : 1);
62 }
63
64 // Based loosely on cvs.module cvs_process_log()
65 function get_changes($prev, $cur) {
66 $changes = array();
67 $rval = '';
68 $logs = array();
69 exec("cvs -qf log -NS -r$prev::$cur 2>&1", $logs, $rval);
70 if ($rval) {
71 print "ERROR: 'cvs log' returned failure: $rval";
72 print implode("\n", $logs);
73 exit(1);
74 }
75 $msg_sep = '----------------------------';
76 $file_sep = '=============================================================================';
77 $in_log = false;
78 while (($line = next($logs)) !== false) {
79 if (preg_match('/^cvs log:.*$/', $line)) {
80 // This line was a warning generated by cvs log, skip it.
81 // @todo An alternative to this would be redirecting STDERR to /dev/null... Why aren't we doing that?
82 continue;
83 }
84 if (trim($line) == $msg_sep || $in_log) {
85 if (!$in_log) {
86 $in_log = true;
87 }
88 $entry = new stdClass();
89 $parts = explode(' ', next($logs));
90 $entry->revision = trim($parts[1]);
91 $parts = explode(';', next($logs));
92 $entry->date = strtotime(cvs_explode($parts[0]));
93 $entry->user = cvs_explode($parts[1]);
94 $entry->state = cvs_explode($parts[2]);
95 $entry->commitid = cvs_explode($parts[4]);
96 $parts = explode(' ', cvs_explode($parts[3]));
97 $entry->lines_added = abs($parts[0]);
98 $entry->lines_removed = abs($parts[1]);
99 $temp = next($logs);
100 $comment = substr($temp, 0, 9) != 'branches:' ? $temp : '';
101 $cur_log = true;
102 while ($cur_log && ($line = next($logs)) !== FALSE) {
103 if (trim($line) == $msg_sep) {
104 prev($logs); // Need to rewind so our outer loop isn't confused.
105 $cur_log = false;
106 }
107 elseif (trim($line) == $file_sep) {
108 $cur_log = false;
109 $in_log = false;
110 }
111 else {
112 $comment .= "\n" . $line;
113 }
114 }
115 $entry->comment = trim($comment);
116 $changes[$entry->commitid] = $entry;
117 }
118 }
119 return $changes;
120 }
121
122 function print_changes($changes) {
123 // Sort changes chronologically
124 usort($changes, 'log_date_cmp');
125 print "<ul>\n";
126 foreach ($changes as $k => $obj) {
127 print '<li>' . preg_replace('/#(\d+)/', '<a href="/node/$1">#$1</a>', $obj->comment) . "</li>\n";
128 }
129 print "</ul>\n";
130 }
131
132 function cvs_explode($text, $delim = ':') {
133 $parts = explode($delim, $text, 2);
134 return trim($parts[1]);
135 }
136
137 function log_date_cmp($a, $b) {
138 if ($a->date == $b->date) {
139 return 0;
140 }
141 return ($a->date < $b->date) ? -1 : 1;
142 }

  ViewVC Help
Powered by ViewVC 1.1.2