release.php 11.8 KB
Newer Older
1 2 3 4 5
#!/usr/bin/php
<?php
define('INTERNAL', 1);
define('CLI', 1);

6 7 8
#
# Builds release tarballs of Mahara at the given version, ready for
# distribution
9
#
10 11 12 13
# If you're doing a release which has security fixes, add the names
# of the patches to the end of the command line, and the script will
# apply the patches before committing the version bumps and editing
# the changelog.
14
#
15

16
if (count($argv) < 3) {
17 18 19
    echo "Usage is ${argv[0]} [version] [branch] [<changesetnumber>...]\n";
    echo "e.g. ${argv[0]} 16.04.3 16.04_STABLE\n";
    echo "e.g. ${argv[0]} 15.10.1 15.10_STABLE 5793 5795\n";
20
    exit(1);
21 22
}

23 24
# Check for git gpg lp-project-upload

25 26 27 28
if (!@is_executable('/usr/bin/gpg')) {
  echo "You need to install gpg: apt-get install gnupg";
  exit(1);
}
29

30 31 32 33
if (!@is_executable('/usr/bin/git')) {
  echo "You need to install git: apt-get install git-core";
  exit(1);
}
34

35 36 37 38
if (!@is_executable('/usr/bin/lp-project-upload')) {
  echo "You need to install lp-project-upload: apt-get install ubuntu-dev-tools (maverick or earlier) or lptools";
  exit(1);
}
39

40 41 42 43
if (!@is_executable('/usr/bin/m4')) {
  echo "You need to install m4: apt-get install m4";
  exit(1);
}
44

45 46
$GIT_MAJOR = `git --version | cut -d' ' -f 3 | cut -d'.' -f 1`;
$GIT_MINOR = `git --version | cut -d' ' -f 3 | cut -d'.' -f 2`;
47

48 49 50 51
if ($GIT_MAJOR < 1 || ($GIT_MAJOR == 1 && $GIT_MINOR < 6 )) {
  echo "Your version of git is too old. Install git 1.6.";
  exit(1);
}
52 53 54

# Check all parameters

55
$VERSION=$argv[1];
56

57 58 59 60 61 62 63 64
$result = preg_match('/([0-9]+\.[0-9]+)(\.|rc)([0-9]+)/i', $VERSION, $matches);
if (!$result) {
    echo "Invalid version number. It must match the pattern \"15.04.1\" or \"15.04rc1\".";
    exit(1);
}
$MAJOR = $matches[1];
$MINOR = $matches[3];
$releasecandidate = ($matches[2] == 'rc');
65

66
$BRANCH = $argv[2];
67

68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
// Check for unmerged drafts
if ($releasecandidate) {
    // If it's a release candidate, draft patches will be on the master branch still
    $draftbranch = 'master';
}
else {
    $draftbranch = $BRANCH;
}
$draftlines = explode(
    "\n",
    `ssh \$USER@reviews.mahara.org -p 29418 gerrit query is:draft branch:$draftbranch project:mahara "label:Code-Review>=0" "label:Verified>=0"`
);
$draftcount = 0;
foreach ($draftlines as $line) {
    if (preg_match("/rowCount: *([0-9]+)/", $line, $matches)) {
        $draftcount = $matches[1];
        break;
    }
}
if ($draftcount > 0) {
    $response = readline("There are Draft patches that may need to be merged. Do you want to continue with release [y/n]?");
    $response = trim(strtolower($response));
    if ($response == 'yes' || $response == 'y') {
        echo "Continuing...";
    }
    else {
        echo "Quitting out";
        exit(1);
    }
}
98

99 100 101
$BUILDDIR = trim(`mktemp -d /tmp/mahara.XXXXX`);
$CURRENTDIR = getcwd();
$SCRIPTDIR = dirname(__FILE__);
102

103 104
mkdir("${BUILDDIR}/mahara", 0777, true);
chdir("${BUILDDIR}/mahara");
105

106 107 108
# Main Mahara repo to pull from
$PUBLIC="git@github.com:MaharaProject/mahara.git";
$PUBLIC = "https://git.mahara.org/mahara/mahara.git";
109

110 111 112 113 114 115
echo "Cloning public repository ${PUBLIC} in ${BUILDDIR}/mahara\n";
passthru('git init');
passthru("git remote add -t ${BRANCH} mahara ${PUBLIC}");
passthru("git fetch -q mahara");
passthru("git checkout -b ${BRANCH} mahara/${BRANCH}");
passthru("git fetch -q -t");
116

117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146

// Applying gerrit patches named on the command line
if (count($argv) > 3) {
    $successwithpatches = true;
    for ($i = 3; $i < count($argv); $i++) {
        $patchno = $argv[$i];
        $refline = shell_exec("ssh reviews.mahara.org -p 29418 gerrit query --current-patch-set --format=TEXT change:'{$patchno}'| grep ref");
        if ($refline) {
            $result = preg_match('#ref: (refs/changes/[/0-9]+)#', $refline, $matches);
            if ($result) {
                $return_var = passthru("git fetch ssh://reviews.mahara.org:29418/mahara {$matches[1]} && git cherry-pick FETCH_HEAD");
                if ($return_var != 0) {
                    echo "Couldn't cherry-pick Gerrit change number {$patchno}.\n";
                    $successwithpatches = false;
                }
            }
            else {
                echo "Couldn't find latest patch number for Gerrit change number {$patchno}.\n";
                $succesoverall = false;
            }
        } else {
            echo "Couldn't retrieve information about Gerrit change number {$patchno}.\n";
            $successwithpatches = false;
        }
    }
    if (!$successwithpatches) {
        exit();
    }
}

147 148 149 150 151
# Edit ChangeLog
if (!file_exists("ChangeLog")) {
    echo "The ChangeLog file is missing and this is a stable release. Create an empty file called ChangeLog and commit it.";
    exit(1);
}
152

153 154
// This is a separate variable for historical reasons
$RELEASE = $VERSION;
155

156 157 158
passthru("echo \"#\n# Please add a description of the major changes in this release, one per line.\n# Don't put a dash or asterisk at the front of each line, they'll get added automatically.\n# Also, don't leave any blank lines at the bottom of this file.\n#\" > ${CURRENTDIR}/ChangeLog.temp");
passthru("sensible-editor ${CURRENTDIR}/ChangeLog.temp");
passthru("grep -v \"^#\" ${CURRENTDIR}/ChangeLog.temp > ${CURRENTDIR}/changes.temp");
159

160 161 162 163 164 165 166 167
if (file_exists("ChangeLog")) {
    copy('ChangeLog', 'ChangeLog.back');
    passthru("echo \"$RELEASE (`date +%Y-%m-%d`)\" > ChangeLog");
    passthru("sed 's/^/- /g' ${CURRENTDIR}/changes.temp >> ChangeLog");
    passthru("echo >> ChangeLog");
    passthru("cat ChangeLog.back >> ChangeLog");
    passthru("git add ChangeLog");
}
168

169 170
# Add a version bump commit for the release
$VERSIONFILE='htdocs/lib/version.php';
171

172
# If there's no 'micro' part of the version number, assume it's a stable release, and
173 174 175 176 177 178
# bump version by 1.  If it's an unstable release, use
$OLDVERSION = call_user_func(function($versionfile) {
    require($versionfile);
    return $config->version;
}, $VERSIONFILE);;
$NEWVERSION = $OLDVERSION + 1;
179

180 181
passthru("sed \"s/\$config->version = [0-9]\{10\};/\$config->version = $NEWVERSION;/\" ${VERSIONFILE} > ${VERSIONFILE}.temp");
passthru("sed \"s/\$config->release = .*/\$config->release = '$RELEASE';/\" ${VERSIONFILE}.temp > ${VERSIONFILE}");
182

183 184 185
echo "\n\n";
passthru("git add ${VERSIONFILE}");
passthru("git commit -s -m \"Version bump for $RELEASE\"");
186 187

# Tag the version bump commit
188 189 190 191 192 193 194 195 196 197 198 199 200 201
$LASTTAG = trim(`git describe --abbrev=0`);
$RELEASETAG = strtoupper($RELEASE) . '_RELEASE';
echo "\nTag new version bump commit as '$RELEASETAG'\n";
passthru("git tag -s ${RELEASETAG} -m \"$RELEASE release\"");

# Build the css
if ($OLDVERSION >= 2015091700) {
    echo "Building css...\n";
    echo `make css >> ../css.log 2>&1`;
    if (!file_exists('htdocs/theme/raw/style/style.css')) {
        echo "CSS files did not build correctly! Check $BUILDDIR/css.log for details.";
        exit(1);
    }
}
202

203
# Package up the release
204 205 206 207
$PACKAGEDIR = 'mahara-' . $VERSION;
echo "Package directory: $BUILDDIR/$PACKAGEDIR\n";
passthru("cp -r $BUILDDIR/mahara $BUILDDIR/$PACKAGEDIR");
chdir("$BUILDDIR/$PACKAGEDIR");
208

209
# Delete everything that shouldn't be included
210
if (getcwd() != "$BUILDDIR/$PACKAGEDIR" || $PACKAGEDIR == '') {
211 212 213 214
    echo "Couldn't cd into the right directory";
    exit(1);
}
passthru('find . -type d -name ".git" -execdir rm -Rf {} \; 2> /dev/null');
215
passthru('find . -type f -name ".gitignore" -execdir rm -Rf {} \; 2> /dev/null');
216 217 218 219 220 221 222 223 224
passthru('find . -type d -name "node_modules" -execdir rm -Rf {} \; 2> /dev/null');
passthru('find . -type f -name "gulpfile.js" -execdir rm -Rf {} \; 2> /dev/null');
passthru('find htdocs/theme -type d -name "sass" -execdir rm -Rf {} \; 2> /dev/null');
passthru("rm -Rf test");
passthru("rm -Rf .gitattributes");
passthru("rm -Rf Makefile");
passthru("rm -Rf phpunit.xml");
passthru("rm -Rf external");
passthru("rm -Rf package.json");
225
passthru("rm -Rf ChangeLog.back");
226 227

# Get the location for all phpunit directories
228
$phpunitdirs = explode("\n", `find . -type d -name 'phpunit' -path '*/tests/phpunit' 2> /dev/null`);
229 230 231 232
foreach ($phpunitdirs as $dir) {
    $parentdir = dirname($dir);
    # Determine whether the parent directory contains anything other than
    # phpunit. If not, remove the whole parent directory.
233
    $siblings = explode("\n", `find "$parentdir" -maxdepth 1 -mindepth 1 2> /dev/null`);
234 235 236 237 238 239 240
    if (count($siblings) == 1) {
        passthru("rm -Rf $parentdir");
    }
    else {
        passthru("rm -Rf $dir");
    }
}
241

242 243 244 245 246 247 248
# Create tarballs
chdir($BUILDDIR);
echo "Creating mahara-${RELEASE}.tar.gz\n";
passthru("tar c $PACKAGEDIR | gzip -9 > ${CURRENTDIR}/mahara-${RELEASE}.tar.gz");
echo "Creating mahara-${RELEASE}.tar.bz2\n";
passthru("tar c $PACKAGEDIR | bzip2 -9 > ${CURRENTDIR}/mahara-${RELEASE}.tar.bz2");
echo "Creating mahara-${RELEASE}.zip\n";
249
passthru("zip -rq ${CURRENTDIR}/mahara-${RELEASE}.zip $PACKAGEDIR");
250 251


252
# Save git changelog
253 254 255 256 257 258 259 260 261 262
chdir("$BUILDDIR/mahara");
if ($LASTTAG) {
    echo "Getting changelog from previous tag ${LASTTAG}\n";
    passthru("git log --pretty=format:\"%s\" --no-color --no-merges ${LASTTAG}..${RELEASETAG} > ${CURRENTDIR}/${RELEASETAG}.cl");
    $OLDRELEASE = substr($LASTTAG, 0, -1 * strlen('_RELEASE'));
}
else {
    passthru("git log --pretty=format:\"%s\" --no-color --no-merges ${RELEASETAG} > ${CURRENTDIR}/${RELEASETAG}.cl");
    $OLDRELEASE = '';
}
263

264 265
# Prepare release notes
// TODO: Replace this with a simple find/replace, to remove the m4 dependency
266
$TMP_M4_FILE = '/tmp/mahara-releasenotes.m4.tmp';
267 268 269 270 271
$m4script = <<<STRING
changecom
define(\\`__RELEASE__',\\`${RELEASE}')dnl
define(\\`__OLDRELEASE__',\\`${OLDRELEASE}')dnl
define(\\`__MAJOR__',\\`${MAJOR}')dnl
272

273 274 275 276 277 278 279 280 281
STRING;
file_put_contents($TMP_M4_FILE, $m4script);
if ($releasecandidate) {
    $TEMPLATE = 'releasenotes.rc.template';
}
else {
    $TEMPLATE = 'releasenotes.stable.template';
}
passthru("m4 ${TMP_M4_FILE} ${SCRIPTDIR}/${TEMPLATE} > ${CURRENTDIR}/releasenotes-${RELEASE}.txt");
282

283
# Second version bump for post-release
284 285
$NEWVERSION = $NEWVERSION + 1;
$NEWRELEASE = $MAJOR . ($releasecandidate ? 'rc' : '.') . ($MINOR + 1) . "testing";
286

287 288
passthru("sed \"s/\$config->version = [0-9]\{10\};/\$config->version = $NEWVERSION;/\" ${VERSIONFILE} > ${VERSIONFILE}.temp");
passthru("sed \"s/\$config->release = .*/\$config->release = '$NEWRELEASE';/\" ${VERSIONFILE}.temp > ${VERSIONFILE}");
289

290 291
passthru("git add ${VERSIONFILE}");
passthru("git commit -s -m \"Version bump for $NEWRELEASE\"");
292

293
# Add gerrit repo, for pushing the new security patches, version bump & changelog commits
294 295
$GERRIT = "ssh://reviews.mahara.org:29418/mahara";
passthru("git remote add gerrit ${GERRIT}");
296

297
# Output commands to push to the remote repository and clean up
298 299 300
$CLEANUPSCRIPT = "$CURRENTDIR/release-${RELEASE}-cleanup.sh";
$cleanup  = <<<CLEANUP
#!/bin/sh
301

302
set -e
303

304 305 306
cd ${BUILDDIR}/mahara
git push gerrit ${BRANCH}:refs/heads/${BRANCH}
git push gerrit ${RELEASETAG}:refs/tags/${RELEASETAG}
307

308 309 310
gpg --armor --sign --detach-sig ${CURRENTDIR}/mahara-${RELEASE}.tar.gz
gpg --armor --sign --detach-sig ${CURRENTDIR}/mahara-${RELEASE}.tar.bz2
gpg --armor --sign --detach-sig ${CURRENTDIR}/mahara-${RELEASE}.zip
311

312 313 314 315
cd ${CURRENTDIR}
lp-project-upload mahara ${RELEASE} mahara-${RELEASE}.tar.gz
lp-project-upload mahara ${RELEASE} mahara-${RELEASE}.tar.bz2
lp-project-upload mahara ${RELEASE} mahara-${RELEASE}.zip
316

317
echo
318 319
echo "All done. Once you've checked that the files were uploaded successfully, run this:"
echo "  rm -rf ${BUILDDIR}"
320
CLEANUP;
321

322 323
file_put_contents($CLEANUPSCRIPT, $cleanup);
chmod($CLEANUPSCRIPT, 0700);
324 325

# Clean up
326 327 328 329 330 331 332 333 334 335 336 337
passthru("rm ${VERSIONFILE}.temp");
passthru("rm ${CURRENTDIR}/ChangeLog.temp");
passthru("rm ${CURRENTDIR}/changes.temp");
passthru("rm ${TMP_M4_FILE}");

echo "\n\nTarballs, release notes & changelog for Launchpad:\n\n";
chdir($CURRENTDIR);
passthru("ls -l mahara-${RELEASE}.tar.gz mahara-${RELEASE}.tar.bz2 mahara-${RELEASE}.zip releasenotes-${RELEASE}.txt ${RELEASETAG}.cl");

echo "\n1. Check that everything is in order in the ${BUILDDIR}/mahara repository.\n";
echo "\n2. Create the release on launchpad at https://launchpad.net/mahara/+milestone/${RELEASE}\n";
echo "\n3. Run the commands in ${CLEANUPSCRIPT} to push the changes back to the remote repository and upload the tarballs.\n";