├── .gitignore ├── releasemajor.txt ├── install.sh ├── weeklybuild.txt ├── release.sh ├── fixsvgcompatability.php ├── fixpermissions.php ├── bumpversions.php ├── README.md └── prerelease.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.idea/ 3 | /gitmirror/ 4 | /cvsmoodle/ 5 | /cvsmoodle18/ 6 | /cvsmoodle19/ 7 | /cvsmoodle20/ 8 | /cvsmoodle21/ 9 | /cvsmoodle22/ 10 | /cvsmoodle23/ 11 | -------------------------------------------------------------------------------- /releasemajor.txt: -------------------------------------------------------------------------------- 1 | This file include the extra steps to perform when one 2 | new MAJOR (X.Y) release is about to be performed. 3 | 4 | In order to procced, simply follow the steps defined 5 | for normal weeklies and, at the given points, execute 6 | the steps detailed in the 2 sections below: 7 | 8 | Note, try not to copy/paste the commands but write them 9 | as it's extremely easy to end with "X.Y" tags, branches 10 | and friends ;-) 11 | 12 | 20110701 first version - Eloy Lafuente (stronk7) 13 | 14 | ========== ========== ========== ========== 15 | 16 | A) STEPS FOR MAJOR RELEASE 17 | 18 | 19 | 1) Change master version.php to: 20 | 21 | $version = YYYYMMDD00.00; // CHANGEMETORELEASEDATE = branching date YYYYMMDD - do not modify! 22 | $release = 'X.Y (Build: YYYYMMDD)'; 23 | $branch = 'XY'; 24 | $maturity = MATURITY_STABLE; 25 | 26 | 2) Commit it with message "Moodle release X.Y" 27 | 28 | 3) git tag -a vX.Y.0 -m MOODLE_XY (we don't delay 29 | tagging. If there is need to repackage, next minor release 30 | X.Y.1 will be done - agreed @ HQ chat). 31 | 32 | 4) git branch MOODLE_XY_STABLE 33 | 34 | 5) Change master version.php to: 35 | 36 | $version = YYYYMMDD00.00; // YYYYMMDD = weekly release date of this DEV branch 37 | $release = 'X.Y+1dev (Build: YYYYMMDD)'; 38 | $branch = 'XY+1'; 39 | $maturity = MATURITY_ALPHA; 40 | 41 | 6) Commit it with message "weekly release X.Y+1dev" 42 | 43 | 7) git push [integration_remote] MOODLE_XY_STABLE && git push [integration_remote] --tags 44 | 45 | 8) git push [integration_remote] master 46 | 47 | 9) Add support for the new branch in all the mdlrelease scripts used (master branch only): 48 | - install.sh 49 | - prerelease.sh 50 | - release.sh 51 | 52 | 10) Create a new repo, view and jobs (clonig from master) in the Jenkins servers, so the new branch 53 | becomes tested by 1st time. 54 | 55 | 11) Verify integration.git looks 100% perfect before continue 56 | 57 | 12) Done! A) STEPS Ok. Go back to next step in weeklybuild.txt 58 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This scripts prepares git checkout necessary for the prerelease and release.sh scripts 4 | # Please note you need to have public ssh key in all the remotes below (github, gitorious, bitbucket) 5 | # And also, can decide about the protocol (ssh, https) to be used against moodle main repositories. 6 | 7 | protocol=${1:-ssh} 8 | username=${2:-} 9 | 10 | if [[ "${protocol}" != "ssh" ]] && [[ "${protocol}" != "https" ]]; then 11 | echo "incorrect protocol '${protocol}' used. Valid values: ssh (default) and https" 12 | exit 1 13 | fi 14 | 15 | if [[ -n "${username}" ]]; then 16 | username="${username}@" 17 | fi 18 | 19 | if [[ "${protocol}" == "ssh" ]]; then 20 | remotem="git@git.in.moodle.com:moodle/moodle.git" 21 | remotei="git@git.in.moodle.com:moodle/integration.git" 22 | else 23 | remotem="https://${username}git.in.moodle.com/moodle/moodle.git" 24 | remotei="https://${username}git.in.moodle.com/moodle/integration.git" 25 | fi 26 | 27 | echo "About to clone integration repository using '${protocol}' with" 28 | echo "remote url '${remotei}'" 29 | 30 | read -r -p "Are you sure? [y/N] " response 31 | response="$(tr [A-Z] [a-z] <<< "${response}")" 32 | if [[ $response =~ ^(yes|y)$ ]]; then 33 | echo "Ok, proceeding" 34 | else 35 | echo "Ok, cancelled" 36 | exit 37 | fi 38 | 39 | if [ -d gitmirror ]; then 40 | read -r -p "Directory gitmirror already exists. Do you agree to remove it? [y/N] " response 41 | response="$(tr [A-Z] [a-z] <<< "${response}")" 42 | if [[ $response =~ ^(yes|y)$ ]]; then 43 | rm -rf gitmirror && echo "Directory removed" || echo "Unable to remove directory gitmirror. Aborting"; exit 44 | else 45 | echo "Installation cancelled" 46 | exit 47 | fi 48 | fi 49 | 50 | git clone ${remotei} gitmirror 51 | cd gitmirror 52 | 53 | # Set a push URL for the origin (integration) remote repository. 54 | git remote set-url --push origin ${remotei} 55 | 56 | # Add the public repositories as a single remote to make pushing easy. 57 | git remote add public ${remotem} 58 | git remote set-url --add --push public ${remotem} 59 | git remote set-url --add --push public git@github.com:moodle/moodle.git 60 | git remote set-url --add --push public git@gitorious.org:moodle/moodle.git 61 | git remote set-url --add --push public git@bitbucket.org:moodle/moodle.git 62 | 63 | git branch --track MOODLE_26_STABLE refs/remotes/origin/MOODLE_26_STABLE 64 | git branch --track MOODLE_25_STABLE refs/remotes/origin/MOODLE_25_STABLE 65 | git branch --track MOODLE_24_STABLE refs/remotes/origin/MOODLE_24_STABLE 66 | # Discontinued 20140113 - git branch --track MOODLE_23_STABLE refs/remotes/origin/MOODLE_23_STABLE 67 | # Discontinued 20130708 - git branch --track MOODLE_22_STABLE refs/remotes/origin/MOODLE_22_STABLE 68 | # Discontinued 20130114 - git branch --track MOODLE_21_STABLE refs/remotes/origin/MOODLE_21_STABLE 69 | # Discontinued 20120706 - git branch --track MOODLE_20_STABLE refs/remotes/origin/MOODLE_20_STABLE 70 | # Discontinued 20140113 - git branch --track MOODLE_19_STABLE refs/remotes/origin/MOODLE_19_STABLE 71 | cd .. 72 | -------------------------------------------------------------------------------- /weeklybuild.txt: -------------------------------------------------------------------------------- 1 | NOTE: For continuous integration periods where only master is 2 | built, see the on-demand-master-only branch in this repository 3 | 4 | 0/ run install.sh xxxxx (xxxx being your login @ git.moodle.org) 5 | (this only needs to be done the 1st time) 6 | 7 | 1a/ for all the branches >= 23_STABLE && master, pull changes from: 8 | git://git.moodle.org/moodle-install.git (install_xxxxx branches match) 9 | and push them to integration. Some day we'll automate this. 10 | 11 | 1b/ if producing releases (major or minor), for all the branches, ensure that the en_fix changes have been integrated in the last cycle. 12 | 13 | 1c/ for all the branches >= 24_STABLE && master, execute the CLI script: 14 | php theme/base/cli/svgtool.php --ie9fix 15 | (you will need to specify also --path= if it's not a moodle configured site) 16 | 17 | It will add some tags to all svgs missing them in order to bring svg 18 | compatibility with IE9. Verify changes (preserveAspectRatio="xMinYMid meet" added) 19 | and commit. If for some reason some svg in core must not be processed, there is one 20 | blacklist in the cli script. Amend & commit it to exclude that svg for next executions. 21 | More info: http://tracker.moodle.org/browse/MDL-36436 22 | 23 | 2/ for all the branches >= 23_STABLE && master, fix all permission 24 | using the fixpermissions.php in integration 25 | 26 | A) STEPS FOR MAJOR RELEASE GO HERE!!! (follow them if necessary, step 3 below 27 | is not needed in major releases for master, but for the rest of stables that 28 | will be a normal weekly builds) 29 | 30 | 3/ Tip: Try to do this, first master, and then from older to newer stables, because commit date affects how files are listed here and there. 31 | 32 | 3/ a) update version.php of all changed branches and push to integration.git 33 | Messages use to be: 34 | - weekly [on sync] release x.y[.z+|dev] (on normal weeklies) 35 | - on-demand release x.y[beta|rc1…] (for continuous integration periods - master only) 36 | - emergency release x.y[.z+|dev|beta|rc1…] (for any emergency release) 37 | - Moodle release x.y[.z|beta|rc1|..] (for any major/minor/beta/rc release) 38 | 39 | 3/ b) Wait for the CI server to finish executing all the integration checks! 40 | 41 | 3/ c) [If necessary] Tags will be created and pushed to integration.git 42 | 43 | NOTE: Since Moodle 2.2.2 (March 2012) we have agreed to tag always on packaging and, if some (rare) 44 | emergency build is needed, it's ok to produce a new package with the 3rd digit in the version 45 | incremented. Link: http://moodle.org/local/chatlogs/index.php?conversationid=9717#c338379 46 | 47 | To create tags - on minor release, betas and rcs, pointing to the version.php 48 | commit with: git tag -a vX.Y.Z[-beta|-rcN] -m MOODLE_XY[Z|_BETA|_RCN] - 49 | 50 | 4/ Spread changes in integration to moodle.git and mirrors using ./release.sh (you may need, on releases, to comment some branches if not releasing all them together). 51 | 52 | 5/ close all issues in Tracker (reseting linked MDLQA ones if existing) 53 | 54 | 6/ annotate the number of closed issues & the number of reopened ones 55 | (Tracker - CI - Count reopened issues) in the sheet. 56 | 57 | 7/ add one entry @ http://moodle.org/mod/forum/view.php?f=1153 commenting 58 | about numbers, major ones, special thanks... 59 | -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This scripts propagates changes from official integration Moodle git repository 4 | # to main repostiory and mirrors 5 | # 6 | # Please note you need to have public ssh keys in all remotes except the origin! 7 | # 8 | # This script base dir 9 | 10 | # Reset to normal. 11 | N="$(tput setaf 9)" 12 | # Red. 13 | R="$(tput setaf 1)" 14 | # Green. 15 | G="$(tput setaf 2)" 16 | # Yellow. 17 | Y="$(tput setaf 3)" 18 | # Cyan. 19 | C="$(tput setaf 6)" 20 | bold=`tput bold` 21 | normal=`tput sgr0` 22 | _verbose=true # Make lots of noise. 23 | _showhelp=false 24 | _confirmed=false 25 | _dryrun=false 26 | _tags=true 27 | 28 | show_help() { 29 | echo "" 30 | echo "${bold}Moodle release - release.sh script${normal}" 31 | echo "" 32 | echo "This tool spreads the already prepared release from integration.git" 33 | echo "to moodle.git and then onto the other public repositories we maintain." 34 | echo "" 35 | echo "${Y}Warning:${normal} Only run this script after you have prepared the release!" 36 | echo "" 37 | echo "${bold}Usage:${normal}" 38 | echo " ./release.sh [-c|--confirm] [-n|--dry-run] [-q|--quiet] [-h|--help]" 39 | echo " [--no-tags]" 40 | echo "" 41 | echo "${bold}Arguments:${normal}" 42 | echo " ${bold}-c${normal}, ${bold}--confirm${normal}" 43 | echo " This script requires that you confirm the action you are about to take." 44 | echo " By giving this argument you acknowledge you understand what is going to" 45 | echo " be done and are happy for this script to just get on with it, without" 46 | echo " prompting you to check." 47 | echo " ${bold}-n${normal}, ${bold}--dry-run${normal}" 48 | echo " Do everything except actually send the updates." 49 | echo " ${bold}-q${normal}, ${bold}--quiet${normal}" 50 | echo " If set this script produces no progress output. It'll let you know when " 51 | echo " its finished however." 52 | echo " You must confirm [-c|--confirm] if using this option." 53 | echo " ${bold}-h${normal}, ${bold}--help${normal}" 54 | echo " Prints this help and exits." 55 | echo " ${bold}--no-tags${normal}" 56 | echo " By default tags are pushed as well, this prevents that from happening." 57 | echo " I hope you know what you're doing!" 58 | echo "" 59 | echo "May the --force be with you" 60 | exit 0; 61 | } 62 | 63 | output() { 64 | if $_verbose ; then 65 | if [ ! -z $2 ] ; then 66 | echo -n "$1" 67 | else 68 | echo "$1" 69 | fi 70 | fi 71 | } 72 | 73 | while test $# -gt 0; 74 | do 75 | case "$1" in 76 | -c | --confirm) 77 | _confirmed=true 78 | shift 79 | ;; 80 | -h | --help) 81 | _showhelp=true 82 | shift 83 | ;; 84 | -n | --dry-run) 85 | _dryrun=true 86 | shift 87 | ;; 88 | -q | --quiet) 89 | _verbose=false 90 | shift # Get rid of the flag. 91 | ;; 92 | --no-tags) 93 | _tags=false 94 | shift # Get rid of the flag. 95 | ;; 96 | *) 97 | echo "${R}* Invalid option $1 given.${N}" 98 | _showhelp=true 99 | shift 100 | esac 101 | done 102 | 103 | if $_showhelp ; then 104 | show_help 105 | fi 106 | 107 | mydir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 108 | if [[ ! -d ${mydir}/gitmirror ]] ; then 109 | output "Directory ${mydir}/gitmirror not found. You may need to create it with install.sh" 110 | exit 1 111 | fi 112 | 113 | output "${G}Moodle release propogator${N}" 114 | 115 | cd ${mydir}/gitmirror 116 | git fetch --quiet origin 117 | 118 | if ! $_confirmed ; then 119 | if ! $_verbose ; then 120 | echo "${R}Error${N}: you must auto-confirm [-c|--confirm] when running silent [-q|--quiet]" 121 | exit 1 122 | fi 123 | output "${bold}Confirm:${normal} please confirm you intention to update the public repositories with the" 124 | output " prepared release: [y|n] " true 125 | read -n 1 confirminput 126 | if [ "$confirminput" != "y" ] && [ "$confirminput" != "Y" ] ; then 127 | output " ... release script ${bold}cancelled${normal}. Have a nice day!" 128 | exit 0 129 | else 130 | output " ... proceeding" 131 | fi 132 | fi 133 | 134 | output "" 135 | output "${bold}Propogating${normal} ... " true 136 | 137 | pushargs="" 138 | if $_tags ; then 139 | pushargs="${pushargs} --tags" 140 | fi 141 | if $_dryrun ; then 142 | pushargs="${pushargs} --dry-run" 143 | fi 144 | 145 | # Update public repositories 146 | # * moodle - git://git.moodle.org/moodle.git 147 | # * github - git@github.com:moodle/moodle.git 148 | # * gitorious - git@gitorious.org:moodle/moodle.git 149 | # * bitbucket - git@bitbucket.org:moodle/moodle.git 150 | git push ${pushargs} public refs/remotes/origin/master:refs/heads/master \ 151 | refs/remotes/origin/MOODLE_26_STABLE:refs/heads/MOODLE_26_STABLE \ 152 | refs/remotes/origin/MOODLE_25_STABLE:refs/heads/MOODLE_25_STABLE \ 153 | refs/remotes/origin/MOODLE_24_STABLE:refs/heads/MOODLE_24_STABLE 154 | # Discontinued 20140113 - refs/remotes/origin/MOODLE_23_STABLE:refs/heads/MOODLE_23_STABLE 155 | # Discontinued 20140113 - refs/remotes/origin/MOODLE_19_STABLE:refs/heads/MOODLE_19_STABLE 156 | # Discontinued 20130708 - refs/remotes/origin/MOODLE_22_STABLE:refs/heads/MOODLE_22_STABLE 157 | # Discontinued 20130114 - refs/remotes/origin/MOODLE_21_STABLE:refs/heads/MOODLE_21_STABLE 158 | # Discontinued 20120706 - refs/remotes/origin/MOODLE_20_STABLE:refs/heads/MOODLE_20_STABLE 159 | 160 | output "${G}Done!${N}" 161 | exit 0 162 | -------------------------------------------------------------------------------- /fixsvgcompatability.php: -------------------------------------------------------------------------------- 1 | false, 'ie9fix'=>false, 'noaspectratio'=>false, 'path'=>dirname(__FILE__).'/gitmirror'), 17 | array('h'=>'help')); 18 | 19 | if ($unrecognized) { 20 | $unrecognized = implode("\n ", $unrecognized); 21 | cli_error("Unrecognised options:\n {$unrecognized}\nPlease use --help option."); 22 | } 23 | 24 | // If necessary add files that should be ignored - such as in 3rd party plugins. 25 | $blacklist = array(); 26 | $path = $options['path']; 27 | if (!file_exists($path)) { 28 | cli_error("Invalid path $path"); 29 | } 30 | 31 | $CFG = new stdClass; 32 | $CFG->dirroot = $path; 33 | 34 | if ($options['ie9fix']) { 35 | theme_base_recurse_svgs($path, '', 'theme_base_svgtool_ie9fix', $blacklist); 36 | 37 | } else if ($options['noaspectratio']) { 38 | theme_base_recurse_svgs($path, '', 'theme_base_svgtool_noaspectratio', $blacklist); 39 | 40 | } else { 41 | $help = 42 | "Some svg image tweaks for icon designers. 43 | 44 | Options: 45 | 46 | -h, --help Print out this help 47 | --ie9fix Adds preserveAspectRatio=\"xMinYMid meet\" to every svg image 48 | --noaspectratio Removes preserveAspectRatio from svg files 49 | --path=PATH Path to directory or file to be converted, by default \$CFG->dirroot 50 | 51 | Examples: 52 | \$ php svgtool.php --ie9fix 53 | \$ php svgtool.php --ie9fix --path=../../../pix 54 | \$ php svgtool.php --noaspectratio 55 | "; 56 | 57 | echo $help; 58 | die; 59 | } 60 | 61 | exit(0); 62 | 63 | 64 | function theme_base_svgtool_ie9fix($file) { 65 | global $CFG; 66 | 67 | if (strpos($file, $CFG->dirroot.DIRECTORY_SEPARATOR) === 0) { 68 | $relfile = substr($file, strlen($CFG->dirroot)); 69 | } else { 70 | $relfile = $file; 71 | } 72 | 73 | $content = file_get_contents($file); 74 | 75 | if (!preg_match('/]*>/', $content, $matches)) { 76 | echo " skipping $relfile (invalid format)\n"; 77 | return; 78 | } 79 | $svg = $matches[0]; 80 | if (strpos($svg, 'preserveAspectRatio') !== false) { 81 | return; 82 | } 83 | 84 | if (!is_writable($file)) { 85 | echo " skipping $relfile (can not modify file)\n"; 86 | return; 87 | } 88 | 89 | $newsvg = rtrim($svg, '>').' preserveAspectRatio="xMinYMid meet">'; 90 | 91 | $content = str_replace($svg, $newsvg, $content); 92 | echo "converting $relfile\n"; 93 | file_put_contents($file, $content); 94 | } 95 | 96 | function theme_base_svgtool_noaspectratio($file) { 97 | global $CFG; 98 | 99 | if (strpos($file, $CFG->dirroot.DIRECTORY_SEPARATOR) === 0) { 100 | $relfile = substr($file, strlen($CFG->dirroot)); 101 | } else { 102 | $relfile = $file; 103 | } 104 | 105 | $content = file_get_contents($file); 106 | 107 | if (!preg_match('/]*>/', $content, $matches)) { 108 | echo " skipping $relfile (invalid format)\n"; 109 | return; 110 | } 111 | $svg = $matches[0]; 112 | if (strpos($svg, 'preserveAspectRatio="xMinYMid meet"') === false) { 113 | return; 114 | } 115 | 116 | if (!is_writable($file)) { 117 | echo " skipping $relfile (can not modify file)\n"; 118 | return; 119 | } 120 | 121 | $newsvg = preg_replace('/ ?preserveAspectRatio="xMinYMid meet"/', '', $svg); 122 | 123 | $content = str_replace($svg, $newsvg, $content); 124 | echo "resetting $relfile\n"; 125 | file_put_contents($file, $content); 126 | } 127 | 128 | function theme_base_recurse_svgs($base, $sub, $filecallback, $blacklist) { 129 | if (is_dir("$base/$sub")) { 130 | $items = new DirectoryIterator("$base/$sub"); 131 | foreach ($items as $item) { 132 | if ($item->isDot()) { 133 | continue; 134 | } 135 | $file = $item->getFilename(); 136 | theme_base_recurse_svgs("$base/$sub", $file, $filecallback, $blacklist); 137 | } 138 | unset($item); 139 | unset($items); 140 | return; 141 | 142 | } else if (is_file("$base/$sub")) { 143 | if (substr($sub, -4) !== '.svg') { 144 | return; 145 | } 146 | $file = realpath("$base/$sub"); 147 | if (in_array($file, $blacklist)) { 148 | return; 149 | } 150 | $filecallback($file); 151 | } 152 | } 153 | 154 | /** 155 | * Returns cli script parameters. 156 | * 157 | * Copied from lib/clilib.php 20/09/2013 158 | * 159 | * @param array $longoptions array of --style options ex:('verbose'=>false) 160 | * @param array $shortmapping array describing mapping of short to long style options ex:('h'=>'help', 'v'=>'verbose') 161 | * @return array array of arrays, options, unrecognised as optionlongname=>value 162 | */ 163 | function cli_get_params(array $longoptions, array $shortmapping=null) { 164 | $shortmapping = (array)$shortmapping; 165 | $options = array(); 166 | $unrecognized = array(); 167 | 168 | if (empty($_SERVER['argv'])) { 169 | // bad luck, we can continue in interactive mode ;-) 170 | return array($options, $unrecognized); 171 | } 172 | $rawoptions = $_SERVER['argv']; 173 | 174 | //remove anything after '--', options can not be there 175 | if (($key = array_search('--', $rawoptions)) !== false) { 176 | $rawoptions = array_slice($rawoptions, 0, $key); 177 | } 178 | 179 | //remove script 180 | unset($rawoptions[0]); 181 | foreach ($rawoptions as $raw) { 182 | if (substr($raw, 0, 2) === '--') { 183 | $value = substr($raw, 2); 184 | $parts = explode('=', $value); 185 | if (count($parts) == 1) { 186 | $key = reset($parts); 187 | $value = true; 188 | } else { 189 | $key = array_shift($parts); 190 | $value = implode('=', $parts); 191 | } 192 | if (array_key_exists($key, $longoptions)) { 193 | $options[$key] = $value; 194 | } else { 195 | $unrecognized[] = $raw; 196 | } 197 | 198 | } else if (substr($raw, 0, 1) === '-') { 199 | $value = substr($raw, 1); 200 | $parts = explode('=', $value); 201 | if (count($parts) == 1) { 202 | $key = reset($parts); 203 | $value = true; 204 | } else { 205 | $key = array_shift($parts); 206 | $value = implode('=', $parts); 207 | } 208 | if (array_key_exists($key, $shortmapping)) { 209 | $options[$shortmapping[$key]] = $value; 210 | } else { 211 | $unrecognized[] = $raw; 212 | } 213 | } else { 214 | $unrecognized[] = $raw; 215 | continue; 216 | } 217 | } 218 | //apply defaults 219 | foreach ($longoptions as $key=>$default) { 220 | if (!array_key_exists($key, $options)) { 221 | $options[$key] = $default; 222 | } 223 | } 224 | // finished 225 | return array($options, $unrecognized); 226 | } 227 | 228 | /** 229 | * Write error notification 230 | * 231 | * Copied from lib/clilib.php 20/09/2013 232 | * 233 | * @param $text 234 | * @return void 235 | */ 236 | function cli_problem($text) { 237 | fwrite(STDERR, $text."\n"); 238 | } 239 | 240 | /** 241 | * Write to standard out and error with exit in error. 242 | * 243 | * Copied from lib/clilib.php 20/09/2013 244 | * 245 | * @param string $text 246 | * @param int $errorcode 247 | * @return void (does not return) 248 | */ 249 | function cli_error($text, $errorcode=1) { 250 | fwrite(STDERR, $text); 251 | fwrite(STDERR, "\n"); 252 | die($errorcode); 253 | } 254 | -------------------------------------------------------------------------------- /fixpermissions.php: -------------------------------------------------------------------------------- 1 | $ignore) { 109 | if (strpos($ignore, '/') === false) { 110 | // keep all globs 111 | continue; 112 | } else { 113 | // detect if the ignore from parent belongs to this dir 114 | if (substr($ignore, 0, 1) !== '/') { 115 | // normalise 116 | $ignore = '/'.$ignore; 117 | } 118 | $parts = explode('/', $ignore); 119 | array_shift($parts); 120 | $current = array_shift($parts); 121 | if ($current === basename($source)) { 122 | // related to this dir - just remove the current dir part 123 | $gitignore[$key] = implode('/', $parts); 124 | } else { 125 | // some other subdir - ignore 126 | unset($gitignore[$key]); 127 | } 128 | } 129 | } 130 | 131 | // add gitignore from current dir 132 | if (PARSEGITIGNORE and file_exists("$source/.gitignore")) { 133 | $newgitignore = file("$source/.gitignore"); 134 | foreach ($newgitignore as $ignore) { 135 | $ignore = trim($ignore); 136 | if ($ignore === '') { 137 | // ignore empty lines 138 | } else if (strpos($ignore, '/') === false) { 139 | // keep all globs 140 | if (!in_array($ignore, $gitignore, true)) { 141 | $gitignore[] = $ignore; 142 | } 143 | } else { 144 | if (substr($ignore, 0, 1) !== '/') { 145 | // normalize 146 | $ignore = '/'.$ignore; 147 | } 148 | if (!in_array($ignore, $gitignore, true)) { 149 | $gitignore[] = $ignore; 150 | } 151 | } 152 | } 153 | } 154 | 155 | $iterator = new DirectoryIterator($source); 156 | foreach($iterator as $file) { 157 | if ($file->isDot()) { 158 | // dots would lead to infinite loops 159 | continue; 160 | } 161 | $name = $file->getFilename(); 162 | 163 | if ($file->isLink()) { 164 | // we do not support symbolic links! 165 | continue; 166 | } 167 | 168 | if (is_ignored($file, $gitignore)) { 169 | if (VERBOSE) { 170 | echo " ignoring: $source/$name\n"; 171 | } 172 | continue; 173 | } 174 | 175 | if ($file->isDir()) { 176 | verify_dir_permissions("$source/$name"); 177 | process_dir("$source/$name", $executables, $gitignore); 178 | 179 | } else if ($file->isFile()) { 180 | verify_file_permissions("$source/$name", $executables); 181 | } 182 | } 183 | // release file handles 184 | unset($file); 185 | unset($iterator); 186 | } 187 | 188 | function is_ignored($file, $gitignore) { 189 | $name = $file->getFilename(); 190 | 191 | foreach($gitignore as $ignore) { 192 | $pignore = preg_quote($ignore, '|'); 193 | $pignore = str_replace('\?', '.', $pignore); // one char 194 | $pignore = str_replace('\*', '.*', $pignore); // any chars 195 | 196 | if (strpos($ignore, '/') === false) { 197 | // shell blob pattern - both dirs and files 198 | if (preg_match("|^$pignore$|", $name)) { 199 | return true; 200 | } 201 | } else { 202 | if (substr($ignore, 0, 1) !== '/') { 203 | // this should be already normalised, anyway..... 204 | $ignore = '/'.$ignore; 205 | } 206 | // file or directory depending on trailing / 207 | if (substr($ignore, -1) === '/') { 208 | // ignore directory 209 | if ($file->isDir() and preg_match("|^$pignore$|", "/$name/")) { 210 | return true; 211 | } 212 | } else { 213 | // ignore file 214 | if ($file->isFile() and preg_match("|^$pignore$|", "/$name")) { 215 | return true; 216 | } 217 | } 218 | } 219 | } 220 | 221 | return false; 222 | } 223 | 224 | function verify_dir_permissions($dir) { 225 | if (!chmod($dir, 0755)) { 226 | echo "Can not change $dir permissions\n"; 227 | } 228 | } 229 | function verify_file_permissions($file, $executables) { 230 | $file = realpath($file); 231 | $oldpermissions = fileperms($file); 232 | $oldpermissions = $oldpermissions & 0777; // we just want the basic permissions 233 | 234 | if (isset($executables[$file])) { 235 | if ($oldpermissions !== 0755) { 236 | #echo "0755: $file\n"; 237 | if (!chmod($file, 0755)) { 238 | echo "Can not change $file permissions\n"; 239 | } 240 | } 241 | 242 | } else { 243 | if ($oldpermissions !== 0644) { 244 | #echo "0644: $file\n"; 245 | if (!chmod($file, 0644)) { 246 | echo "Can not change $file permissions\n"; 247 | } 248 | } 249 | } 250 | } -------------------------------------------------------------------------------- /bumpversions.php: -------------------------------------------------------------------------------- 1 | getMessage(); 23 | $result = $ex->getCode(); 24 | } 25 | echo $release; 26 | exit($result); 27 | 28 | 29 | 30 | function bump_version($path, $branch, $type, $rc = null, $date = null) { 31 | 32 | validate_branch($branch); 33 | validate_type($type); 34 | validate_path($path); 35 | 36 | $versionfile = file_get_contents($path); 37 | 38 | validate_version_file($versionfile, $branch); 39 | 40 | $is19 = ($branch === 'MOODLE_19_STABLE'); 41 | $isstable = branch_is_stable($branch); 42 | $today = date('Ymd'); 43 | 44 | $versionmajorcurrent = null; 45 | $versionminorcurrent = null; 46 | $commentcurrent = null; 47 | $releasecurrent = null; 48 | $buildcurrent = null; 49 | $branchcurrent = null; 50 | $maturitycurrent = null; 51 | 52 | $branchquote = null; 53 | $releasequote = null; 54 | 55 | $versionmajornew = null; 56 | $versionminornew = null; 57 | $commentnew = null; 58 | $releasenew = null; 59 | $buildnew = null; 60 | $branchnew = null; 61 | $maturitynew = null; 62 | 63 | if (!preg_match('#^ *\$version *= *(?P\d{10})\.(?P\d{2})\d?[^\/]*(?P/[^\n]*)#m', $versionfile, $matches)) { 64 | throw new Exception('Could not determine version.', __LINE__); 65 | } 66 | $versionmajornew = $versionmajorcurrent = $matches['major']; 67 | $versionminornew = $versionminorcurrent = $matches['minor']; 68 | $commentnew = $commentcurrent = $matches['comment']; 69 | 70 | if (!preg_match('#^ *\$release *= *(?P\'|")(?P[^ \+]+\+?) *\(Build: (?P\d{8})\)\1#m', $versionfile, $matches)) { 71 | throw new Exception('Could not determine the release.', __LINE__); 72 | } 73 | $releasenew = $releasecurrent = $matches['release']; 74 | $releasequote = $matches['quote']; 75 | $buildcurrent = $matches['build']; 76 | $buildnew = empty($date) ? $today : $date; // Observe forced date. 77 | 78 | if (!$is19) { 79 | if (!preg_match('# *\$branch *= *(?P\'|")(?P\d+)\1#m', $versionfile, $matches)) { 80 | throw new Exception('Could not determine branch.', __LINE__); 81 | } 82 | $branchquote = $matches['quote']; 83 | $branchnew = $branchcurrent = $matches['branch']; 84 | if (!preg_match('# *\$maturity *= *(?PMATURITY_[A-Z]+)#m', $versionfile, $matches)) { 85 | throw new Exception('Could not determine maturity.', __LINE__); 86 | } 87 | $maturitynew = $maturitycurrent = $matches['maturity']; 88 | } 89 | 90 | if ($isstable) { 91 | // It's a stable branch. 92 | if ($type === 'weekly') { 93 | // It's a stable branch. We need to bump the minor version and add a + if this was the first 94 | // weekly release after a major or minor release. 95 | if (strpos($releasenew, '+') === false) { 96 | // Add the + 97 | $releasenew .= '+'; 98 | } 99 | $versionminornew++; 100 | $maturitynew = 'MATURITY_STABLE'; 101 | } else if ($type === 'minor' || $type === 'major') { 102 | // If it's minor fine, it's if major then stable gets a minor release. 103 | // 2.6+ => 2.6.1 104 | // 2.6.12+ => 2.6.13 105 | if (strpos($releasenew, '+') !== false) { 106 | // Strip the +1 off 107 | $releasenew = substr($releasenew, 0, -1); 108 | } 109 | if (preg_match('#^(?P\d+\.\d+)\.(?P\d+)#', $releasenew, $matches)) { 110 | $increment = $matches['increment'] + 1; 111 | $releasenew = $matches['version'].'.'.(string)$increment; 112 | } else { 113 | // First minor release on this stable branch. Yay X.Y.1. 114 | $releasenew .= '.1'; 115 | } 116 | $versionmajornew = (int)$versionmajornew + 1; 117 | $versionmajornew = (string)$versionmajornew; 118 | $versionminornew = '00'; 119 | // Now handle builddate for releases. 120 | if (empty($date)) { // If no date has been forced, stable minors always are released on Monday. 121 | if ((int)date('N') !== 1) { // If today is not Monday, calculate next one. 122 | $buildnew = date('Ymd', strtotime('next monday')); 123 | } 124 | } 125 | } 126 | 127 | } else { 128 | // Ok it's the master branch. 129 | if ($type === 'weekly' || $type === 'minor') { 130 | // If it's weekly fine, if it's minor the master branch doesn't get a minor release so really it's a weekly anyway. 131 | // It's the master branch. We need to bump the version, if the version is already higher than today*100 then we need 132 | // to bump accordingly. 133 | // We also need to add "dev" to the end of the version if it's not there (first weekly after a major release). 134 | if (strpos($releasecurrent, 'dev') === false) { 135 | // Must be immediately after a major release. Bump the release version and set maturity to Alpha. 136 | $releasenew = (float)$releasenew + 0.1; 137 | $releasenew = (string)$releasenew.'dev'; 138 | $maturitynew = 'MATURITY_ALPHA'; 139 | } 140 | list($versionmajornew, $versionminornew) = bump_master_ensure_higher($versionmajornew, $versionminornew); 141 | } else if ($type === 'beta') { 142 | $releasenew = preg_replace('#^(\d+.\d+) *(dev)#', '$1', $releasenew); 143 | $branchnew = str_replace('.', '', $releasenew); 144 | $releasenew .= 'beta'; 145 | list($versionmajornew, $versionminornew) = bump_master_ensure_higher($versionmajornew, $versionminornew); 146 | $maturitynew = 'MATURITY_BETA'; 147 | } else if ($type === 'rc') { 148 | $releasenew = preg_replace('#^(\d+.\d+) *(dev|beta)\+?#', '$1', $releasenew); 149 | $branchnew = str_replace('.', '', $releasenew); 150 | $releasenew .= 'rc'.$rc; 151 | list($versionmajornew, $versionminornew) = bump_master_ensure_higher($versionmajornew, $versionminornew); 152 | $maturitynew = 'MATURITY_RC'; 153 | } else if ($type === 'on-demand') { 154 | list($versionmajornew, $versionminornew) = bump_master_ensure_higher($versionmajornew, $versionminornew); 155 | } else if ($type === 'on-sync') { 156 | $versionminornew++; 157 | } else if ($type === 'back-to-dev') { 158 | if (strpos($releasecurrent, 'dev') === false) { // Ensure it's not a "dev" version already. 159 | // Must be immediately after a major release. Bump comment, release and maturity. 160 | $commentnew = '// YYYYMMDD = weekly release date of this DEV branch.'; 161 | $releasenew = (float)$releasenew + 0.1; 162 | $branchnew = str_replace('.', '', $releasenew); 163 | $releasenew = (string)$releasenew.'dev'; 164 | $maturitynew = 'MATURITY_ALPHA'; 165 | } 166 | } else { 167 | // Awesome major release! 168 | $releasenew = preg_replace('#^(\d+.\d+) *(dev|beta|rc\d+)\+?#', '$1', $releasenew); 169 | $branchnew = str_replace('.', '', $releasenew); 170 | list($versionmajornew, $versionminornew) = bump_master_ensure_higher($versionmajornew, $versionminornew); 171 | $maturitynew = 'MATURITY_STABLE'; 172 | // Now handle builddate for releases. 173 | if (empty($date)) { // If no date has been forced, master majors always are released on Monday. 174 | if ((int)date('N') !== 1) { // If today is not Monday, calculate next one. 175 | $buildnew = date('Ymd', strtotime('next Monday')); 176 | } 177 | } 178 | $commentnew = '// ' . $buildnew . ' = branching date YYYYMMDD - do not modify!'; 179 | // TODO: Move this to bump_master_ensure_higher() to keep thigs clear. Require new params. 180 | // Also force version for major releases. Must match "next Monday" or --date (if specified) 181 | if (empty($date)) { // If no date has been forced, master majors always are released on Monday. 182 | if ((int)date('N') !== 1) { // If today is not Monday, calculate next one. 183 | $versionmajornew = date('Ymd', strtotime('next Monday')) . '00'; 184 | } 185 | } else { 186 | $versionmajornew = $date . '00'; // Apply $date also to major versions. 187 | } 188 | } 189 | } 190 | 191 | // Replace the old version with the new version. 192 | if (strlen($versionminornew) === 1) { 193 | $versionminornew = '0'.$versionminornew; 194 | } 195 | $versionfile = str_replace($versionmajorcurrent.'.'.$versionminorcurrent, $versionmajornew.'.'.$versionminornew, $versionfile); 196 | // Replace the old build with the new build. 197 | $versionfile = str_replace('Build: '.$buildcurrent, 'Build: '.$buildnew, $versionfile); 198 | // Replace the old release with the new release if they've changed. 199 | if ($releasecurrent !== $releasenew) { 200 | $versionfile = str_replace($releasequote.$releasecurrent, $releasequote.$releasenew, $versionfile); 201 | } 202 | // Replace the old comment with the new one if they've changed 203 | if ($commentcurrent !== $commentnew) { 204 | $versionfile = str_replace($commentcurrent, $commentnew, $versionfile); 205 | } 206 | 207 | if (!$is19) { 208 | // Replace the branch value if need be. 209 | if ($branchcurrent !== $branchnew) { 210 | $versionfile = str_replace($branchquote.$branchcurrent.$branchquote, $branchquote.$branchnew.$branchquote, $versionfile); 211 | } 212 | // Replace the maturity value if need be. 213 | if ($maturitycurrent !== $maturitynew) { 214 | $versionfile = str_replace('= '.$maturitycurrent, '= '.$maturitynew, $versionfile); 215 | } 216 | } 217 | 218 | file_put_contents($path, $versionfile); 219 | 220 | return $releasenew; 221 | } 222 | 223 | function bump_master_ensure_higher($major, $minor) { 224 | $today = date('Ymd'); 225 | if ($major >= $today*100) { 226 | // Version is already past today * 100, increment minor version instead of major version. 227 | $minor = (int)$minor + 1; 228 | $minor = (string)$minor; 229 | } else { 230 | $major = $today.'00'; 231 | $minor = '00'; 232 | } 233 | return array($major, $minor); 234 | } 235 | 236 | function branch_is_stable($branch) { 237 | return (strpos($branch, '_STABLE') !== false); 238 | } 239 | 240 | function validate_branch($branch) { 241 | if (!preg_match('#^(master|MOODLE_(\d+)_STABLE)$#', $branch, $matches)) { 242 | throw new Exception('Invalid branch given', __LINE__); 243 | } 244 | return true; 245 | } 246 | 247 | function validate_type($type) { 248 | $types = array('weekly', 'minor', 'major', 'beta', 'rc', 'on-demand', 'on-sync', 'back-to-dev'); 249 | if (!in_array($type, $types)) { 250 | throw new Exception('Invalid type given.', __LINE__); 251 | } 252 | return true; 253 | } 254 | 255 | function validate_path($path) { 256 | if (file_exists($path) && is_readable($path)) { 257 | if (is_writable($path)) { 258 | return true; 259 | } 260 | throw new Exception('Path cannot be written to.', __LINE__); 261 | } 262 | throw new Exception('Invalid path given.', __LINE__); 263 | } 264 | 265 | function validate_version_file($contents, $branch) { 266 | $hasversion = strpos($contents, '$version ') !== false; 267 | $hasrelease = strpos($contents, '$release ') !== false; 268 | $hasbranch = strpos($contents, '$branch ') !== false; 269 | $hasmaturity = strpos($contents, '$maturity ') !== false; 270 | 271 | if ($hasversion && $hasrelease && $hasbranch && $hasmaturity) { 272 | return true; 273 | } 274 | if ($branch === 'MOODLE_19_STABLE' && $hasversion && $hasrelease) { 275 | return true; 276 | } 277 | throw new Exception('Invalid version file found.', __LINE__); 278 | } 279 | 280 | function get_option_from_options_array(array $options, $short, $long) { 281 | if (!isset($options[$short]) && !isset($options[$long])) { 282 | throw new Exception("Required option -$short|--$long must be provided.", __LINE__); 283 | } 284 | if ((isset($options[$short]) && is_array($options[$short])) || 285 | (isset($options[$long]) && is_array($options[$long])) || 286 | (isset($options[$short]) && isset($options[$long]))) { 287 | throw new Exception("Option -$short|--$long specified more than once.", __LINE__); 288 | } 289 | return (isset($options[$short])) ? $options[$short] : $options[$long]; 290 | } 291 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Moodle release tool 2 | =================== 3 | 4 | This project contains the scripts used to prepare Moodle code for Major, Minor and weekly releases. 5 | 6 | * [About this tool](#about-this-tool) 7 | * [Installation](#installation) 8 | * [Update](#update) 9 | * [Release types](#release-types) 10 | * [Weekly release](#weekly-release) 11 | * [Minor release](#minor-release) 12 | * [Beta release](#beta-release) 13 | * [RC release](#rc-release) 14 | * [Major release](#major-release) 15 | * [Advanced release types](#advanced-release-types) 16 | * [On-demand release](#on-demand-release) 17 | * [On-sync release](#on-sync-release) 18 | * [Back-to-dev release](#back-to-dev-release) 19 | * [After the release](#after-the-release) 20 | * [Pre-release options](#pre-release-options) 21 | * [Advanced pre-release options](#advanced-pre-release-options) 22 | * [Reset the local repository](#reset-the-local-repository) 23 | * [Show the state of the local repository](#show-the-state-of-the-local-repository) 24 | 25 | 26 | About this tool 27 | ---------------------- 28 | This tool helps you prepare a Moodle release. 29 | It includes details on the required steps and scripts to facilliate those steps. 30 | In producing a release you simple need to work through the steps. 31 | 32 | As this involves pushing Moodle source code to the public git repositories we maintain you must ensure you have had your 33 | ssh keys added to the following repositories by an administrator. 34 | 35 | * git://git.moodle.ord/moodle.git 36 | * git://github.com/moodle/moodle.git 37 | * git://gitorious.org/moodle/moodle.git 38 | 39 | Installation 40 | ------------ 41 | Before running releases this project needs to be set up. This only need to be done the very first time you use this tool. 42 | Set up is dead easy thanks to a the installation script: 43 | 44 | git clone git://github.com/moodlehq/mdlrelease.git 45 | cd mdlrelease 46 | ./install.sh protocol username 47 | 48 | protocol: defaults to 'ssh', also accepts 'https'. 49 | username: ignored for 'ssh' (keys are used there), optional for 'https' (git will ask for it if not set). 50 | 51 | For more info about the protocols and their differences, read the "Setup required for new iTeam member" article. 52 | 53 | The installation script prepares a Moodle repository and the necessary branches. As this involves a Moodle checkout the process can take some time to complete. 54 | Please be patient. 55 | 56 | Release types 57 | ----------------- 58 | 59 | There are several different types of release that can be made by this tool. In fact it covers all of the planned release types. 60 | 61 | **Weekly release** - the most common release, made every week and containing all the newly integrated work. Includes master and all stables branches. 62 | 63 | **Minor release** - every two to three months we make a minor release, this release type handles everything involved with that. Only stable branches are worked on here. 64 | 65 | **Beta release** - Around a month or two before a major release we create a beta release of the master branch. This usually occurs when QA testing starts and only affects the master branch. 66 | 67 | **RC release** - The release candidate release. Usually one or more release candidate releases are prepared for the master branch in the final lead up to the major release. Again master only. 68 | 69 | **Major release** - twice a year we make a major release (and usually a minor release of stables at the same time). This affects only the master branch although it leads to the next stable branch being produced. 70 | 71 | There are also a handful of advanced release types. These release types are usually very specific and you may - or may not be required to run them. As such they are unplanned and usually only required if the situation demands it. 72 | 73 | ### Weekly release 74 | 75 | The following steps must be followed to perform a weekly release. 76 | 77 | **1. Run the pre-release script.** 78 | 79 | ./prerelease.sh 80 | 81 | By default this script prepares the branches and gives you the commands to push. It doesn't actually push up to the integration server. 82 | there is an optional argument *-p* which if specified pushes the updated branches to the integration repository. 83 | This option is useful if you trust the script more than you should ;) 84 | 85 | **2. Review the branches very carefully.** 86 | 87 | **3. Push to the public repositories** 88 | 89 | Spread changes in integration to moodle.git and mirrors using ./release.sh (you may need, on releases, to comment some branches if not releasing all them together). 90 | 91 | ### Minor release 92 | 93 | The following steps must be followed to perform a minor release. 94 | The minor release affects all stable branches, master however is skipped as you cannot produce a minor release on an unreleased branch. 95 | 96 | **1. Run the pre-release script.** 97 | 98 | ./prerelease.sh --type minor 99 | 100 | By default this script prepares the branches and gives you the commands to push. It doesn't actually push up to the integration server. 101 | there is an optional argument *-p* which if specified pushes the updated branches to the integration repository. 102 | 103 | **2. Review the branches very carefully.** 104 | 105 | **3. Push to the public repositories** 106 | 107 | Spread changes in integration to moodle.git and mirrors using ./release.sh (you may need, on releases, to comment some branches if not releasing all them together). 108 | 109 | ### Beta release 110 | 111 | The following steps must be followed to perform a beta release. 112 | The beta release puts the master branch into a beta state. This usually happens in conjunction with QA testing, however it can happen any time we feel the master branch is maturing + stabilising in the lead up to a major release. Stable branches are skipped of course. 113 | 114 | **1. Run the pre-release script.** 115 | 116 | ./prerelease.sh --type beta 117 | 118 | By default this script prepares the branches and gives you the commands to push. It doesn't actually push up to the integration server. 119 | there is an optional argument *-p* which if specified pushes the updated branches to the integration repository. 120 | 121 | **2. Review the branches very carefully.** 122 | 123 | **3. Push to the public repositories** 124 | 125 | Spread changes in integration to moodle.git and mirrors using ./release.sh (you may need, on releases, to comment some branches if not releasing all them together). 126 | 127 | ### RC release 128 | 129 | The following steps must be followed to perform a release candidate release. 130 | There can be one or more release candidate releases made as the final build up to a major release. They signify that we believe master branch is now stable and that we don't expect to find any more significant issues before release. We have usually addressed all QA related issues and release blocking issues. Again master only. 131 | 132 | **1. Run the pre-release script.** 133 | 134 | ./prerelease.sh --type rc 2 135 | 136 | Where 2 is the release candidate version. 137 | By default this script prepares the branches and gives you the commands to push. It doesn't actually push up to the integration server. 138 | there is an optional argument *-p* which if specified pushes the updated branches to the integration repository. 139 | 140 | **2. Review the branches very carefully.** 141 | 142 | **3. Push to the public repositories** 143 | 144 | Spread changes in integration to moodle.git and mirrors using ./release.sh (you may need, on releases, to comment some branches if not releasing all them together). 145 | 146 | ### Major release 147 | 148 | The following steps must be followed to perform a major release. 149 | Hurrah - we are ready for a major release, a twice yearly occasion normally. This will take the master branch only, produce a major release, and then create the next stable branch. 150 | After running this release type you will be required to edit these scripts and add a reference to the newly created stable release so that it is included in the processes here-after. 151 | 152 | **1. Run the pre-release script.** 153 | 154 | ./prerelease.sh --type major 155 | 156 | By default this script prepares the branches and gives you the commands to push. It doesn't actually push up to the integration server. 157 | there is an optional argument *-p* which if specified pushes the updated branches to the integration repository. 158 | 159 | **2. Review the branches very carefully.** 160 | 161 | **3. Update the mdlrelease scripts** 162 | 163 | Add support for the new branch in install.sh, prerelease.sh, and release.sh 164 | 165 | **4. Prepare the current integration server** 166 | 167 | Create a new repo, view and jobs (cloning from master) in the Jenkins servers, so the new branch becomes tested by 1st time. 168 | 169 | **5. Double check everything.** 170 | 171 | Verify integration.git looks 100% perfect before continuing 172 | 173 | **6. Push to the public repositories** 174 | 175 | Spread changes in integration to moodle.git and mirrors using ./release.sh (you may need, on releases, to comment some branches if not releasing all them together). 176 | 177 | Advanced release types 178 | ---------------------- 179 | 180 | The following advanced release types are also available. 181 | 182 | ### On demand release 183 | 184 | Used to produce an on-demand release for the master branch. This type of release skips all stable branches. 185 | The following steps must be followed to perform an on-demand release. 186 | 187 | **1. Run the pre-release script.** 188 | 189 | ./prerelease.sh --type on-demand 190 | 191 | By default this script prepares the branches and gives you the commands to push. It doesn't actually push up to the integration server. 192 | there is an optional argument *-p* which if specified pushes the updated branches to the integration repository. 193 | 194 | **2. Review the branches very carefully.** 195 | 196 | **3. Push to the public repositories** 197 | 198 | Spread changes in integration to moodle.git and mirrors using ./release.sh (you may need, on releases, to comment some branches if not releasing all them together). 199 | 200 | ### On sync release 201 | 202 | Used to produce an on-sync release for the master branch. This type of release skips all stable branches. 203 | This release type should only be used when the Moodle's master branch must stay "in sync" with the latest stable branch after a major release. 204 | The following steps must be followed to perform an on-sync release. 205 | 206 | **1. Run the pre-release script.** 207 | 208 | ./prerelease.sh --type on-sync 209 | 210 | By default this script prepares the branches and gives you the commands to push. It doesn't actually push up to the integration server. 211 | there is an optional argument *-p* which if specified pushes the updated branches to the integration repository. 212 | 213 | **2. Review the branches very carefully.** 214 | 215 | **3. Push to the public repositories** 216 | 217 | Spread changes in integration to moodle.git and mirrors using ./release.sh (you may need, on releases, to comment some branches if not releasing all them together). 218 | 219 | ### Back to dev release 220 | 221 | Used to produce a back-to-dev release after a major release. 222 | This release type should only be used immediately after a major release has been successfully completed in order to set the master branch back to a development state. 223 | The following steps must be followed to perform an on-sync release. 224 | 225 | **1. Run the pre-release script.** 226 | 227 | ./prerelease.sh --type back-to-dev 228 | 229 | By default this script prepares the branches and gives you the commands to push. It doesn't actually push up to the integration server. 230 | there is an optional argument *-p* which if specified pushes the updated branches to the integration repository. 231 | 232 | **2. Review the branches very carefully.** 233 | 234 | **3. Push to the public repositories** 235 | 236 | Spread changes in integration to moodle.git and mirrors using ./release.sh (you may need, on releases, to comment some branches if not releasing all them together). 237 | 238 | After the release 239 | ----------------- 240 | 241 | You're not quite done yet, you must do the following after all releases. 242 | 243 | **1. Tidy up tracker.** 244 | 245 | Close all issues in Tracker (reseting linked MDLQA ones if existing or moving them FROM MDLQA-1 to MDLQA-5249 if behat-covered) 246 | 247 | **2. Update our records.** 248 | 249 | Annotate the number of closed issues & the number of reopened ones (Tracker - CI - Count reopened issues) in the sheet. 250 | 251 | **3. Let the world know.** 252 | 253 | Add one entry @ http://moodle.org/mod/forum/view.php?f=1153 commenting about numbers, major ones, special thanks... 254 | 255 | Pre-release options 256 | ------------------- 257 | 258 | The following options can be used to customise how the selected release type is prepared. 259 | 260 | * **-b | --branch** 261 | 262 | Limits the operation to just the branch that has been given. By default the appropriate branches for the release type will all be operated on. 263 | 264 | * **-d | --date** 265 | 266 | Enforces a build date for all the branches being processed. The use of this option overrides the default behavior, that is the following: 267 | 1. "next monday" is used for major and minor releases. 268 | 2. "today" is used for any other release type. 269 | 270 | * **-n | --not-forced** 271 | 272 | By default the version file on all branches will be bumped. If this option has been specified then the version file will only be bumped if there are new commits on the branch 273 | 274 | * **-p | --pushup** 275 | 276 | By default this script prepares everything to be pushed by does not push. 277 | If this option is specified the staged commits and any tags will be pushed up to the integration server. 278 | 279 | * **-q | --quiet** 280 | 281 | If set this script produces no progress output. It'll let you know when its finished however. 282 | 283 | * **-t | --type** 284 | 285 | The type of release to prepare. 286 | 287 | * **--no-create** 288 | 289 | If this tool finds that one of the expected branches does not exist then by default it creates it. If this option is specified the tool will not create the branch but will exit with an error. 290 | 291 | Advanced pre-release options 292 | ---------------------------- 293 | 294 | The pre-release script has several arguments that can set to alter how the release is prepared, what steps are taken, and other functions to aid the integrator in the release process. 295 | 296 | For detailed information on these options you can already run the following from your console: 297 | 298 | ./prerelease.sh --help 299 | 300 | ### Reset the local repository 301 | 302 | This resets the expected branches in the local repository. 303 | 304 | ./prerelease.sh --reset 305 | 306 | Please be aware that it doesn't actually fetch upstream changes, it simply resets the expected branches to the currently tracked state. 307 | This is a particularly useful option if you've naughtily being hacking on the mdlrelease repository. 308 | 309 | Note: this is an exclusive function, the prerelease script exits immediately after the reset operations have been completed. 310 | 311 | ### Show the state of the local repository 312 | 313 | This displays the state of the local repository, making it clear if there are any changes that would get in the way of preparing a release. 314 | 315 | ./prerelease.sh --show 316 | 317 | It also gives you the option of viewing the changes that have been made on a branch that is not in-sync with its tracked upstream branch. 318 | 319 | Note: this is an exclusive function, the prerelease script exits immediately after the show operations have been completed. 320 | -------------------------------------------------------------------------------- /prerelease.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This script performs required pre-release processing. 3 | 4 | # Reset to normal. 5 | N="$(tput setaf 9)" 6 | # Red. 7 | R="$(tput setaf 1)" 8 | # Green. 9 | G="$(tput setaf 2)" 10 | # Yellow. 11 | Y="$(tput setaf 3)" 12 | # Cyan. 13 | C="$(tput setaf 6)" 14 | # This script base dir 15 | mydir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 16 | # The branches to push to integration. 17 | integrationpush="" 18 | 19 | # Command line arguments 20 | _pushup=false # Push to integration when complete 21 | _verbose=true # Make lots of noise. 22 | _type='weekly' # The type of release we are making. 23 | _forcebump=true # If true we make the bump regardless 24 | _onlybranch='' # Gets set to a single branch if we only want one. 25 | _reset=false # To discard any local change not available @ integration.git 26 | _show=false # To show all the changes performed locally, comparing with integration.git 27 | _date='' # To enforce any build date at any moment 28 | _rc=0 # Sets the release candidate version 29 | _types=("weekly" "minor" "major" "beta" "rc" "on-demand" "on-sync" "back-to-dev"); 30 | _nocreate=false 31 | localbuffer="" 32 | 33 | # Try to observe the "master first, then stables from older to newer" rule. 34 | # We don't make a weekly release of the security only branch any more. It is however still released during a minor release. 35 | weeklybranches=("master" "MOODLE_25_STABLE" "MOODLE_26_STABLE"); 36 | minorbranches=("MOODLE_24_STABLE" "MOODLE_25_STABLE" "MOODLE_26_STABLE"); 37 | majorbranches=("master"); 38 | betabranches=("master"); 39 | rcbranches=("master"); 40 | 41 | # Prepare an all branches array. 42 | OLDIFS="$IFS" 43 | IFS=$'\n' 44 | allbranches=("${weeklybranches[@]}" "${minorbranches[@]}" "${majorbranches[@]}" "${betabranches[@]}" "${rcbranches[@]}") 45 | allbranches=(`for b in "${allbranches[@]}" "${allbranches[@]}" ; do echo "$b" ; done | sort -du`) 46 | IFS="$OLDIFS" 47 | 48 | in_array() { 49 | for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done 50 | return 1 51 | } 52 | 53 | git_staged_changes() { 54 | if ! git diff-index --quiet --cached --ignore-submodules HEAD -- ; then 55 | return 0 56 | fi 57 | return 1 58 | } 59 | 60 | git_unstaged_changes() { 61 | if ! git diff-files --quiet --ignore-submodules ; then 62 | return 0 63 | fi 64 | return 1 65 | } 66 | 67 | git_last_commit_hash() { 68 | echo `git log --pretty=format:'%H' -n 1` 69 | return 0 70 | } 71 | 72 | all_clean() { 73 | er=false 74 | if git_unstaged_changes ; then 75 | echo "${R}There are unstaged changes in the gitmirror repository.${N}" 76 | er=true 77 | fi 78 | 79 | if git_staged_changes ; then 80 | echo "${R}There are uncommit changes in the gitmirror repository.${N}" 81 | er=true 82 | fi 83 | 84 | if $er ; then 85 | exit 1 86 | fi 87 | } 88 | 89 | # Argument 1: branch 90 | # Argument 2: type 91 | # Argument 3: pwd 92 | # Argument 4: rc 93 | # Argument 5: date 94 | bump_version() { 95 | local release=`php ${mydir}/bumpversions.php -b "$1" -t "$2" -p "$3" -r "$4" -d "$5"` 96 | local outcome=$? 97 | local return=0 98 | local weekly=false 99 | local ondemand=false 100 | local onsync=false 101 | local backtodev=false 102 | 103 | if [ "$2" == "weekly" ] ; then 104 | # It's a weekly release... easy! 105 | weekly=true 106 | elif [ "$2" == "on-demand" ] ; then 107 | # It's a on-demand relese... easy too! 108 | ondemand=true 109 | elif [ "$2" == "on-sync" ] ; then 110 | # It's a on-sync relese... easy too! 111 | onsync=true 112 | elif [ "$2" == "back-to-dev" ] ; then 113 | # Just returning master to dev after major 114 | backtodev=true 115 | elif [ "$1" == "master" ] && [ "$2" == "minor" ] ; then 116 | # It's the master branch and a minor release - master just gets a weekly. 117 | weekly=true 118 | fi 119 | 120 | if (( outcome > 0 )) ; then 121 | output " - ${R}Failed to bump version file [$outcome].${N}" 122 | _pushup=false 123 | else 124 | git add version.php 125 | if git_staged_changes ; then 126 | if $weekly ; then 127 | git commit --quiet -m "weekly release $release" 128 | elif $ondemand ; then 129 | git commit --quiet -m "on-demand release $release" 130 | elif $onsync ; then 131 | git commit --quiet -m "weekly on-sync release $release" 132 | elif $backtodev ; then 133 | git commit --quiet -m "weekly back-to-dev release $release" 134 | else 135 | git commit --quiet -m "Moodle release $release" 136 | local tagversion=`get_release_tag_version "$release"` # v2.6.0 137 | local tagannotation=`get_release_tag_annotation "$release"` # MOODLE_26 138 | local taghash=`git_last_commit_hash` # The full git commit hash for the last commit on the branch 139 | if $_pushup ; then 140 | #git tag -a "$tagversion" -m "$tagannotation" $taghash 141 | echo "git tag -a '$tagversion' -m '$tagannotation' $taghash" 142 | else 143 | localbuffer="$localbuffer\ngit tag -a '$tagversion' -m '$tagannotation' $taghash" 144 | fi 145 | 146 | if [ "$1" == "master" ] && [ "$2" == "major" ] ; then 147 | # Exciting 148 | local newbranch=`get_new_stable_branch "$release"` # MOODLE_26_STABLE 149 | output = " - Creating new stable branch $newbranch" 150 | git branch -f "$newbranch" master # create from (or reset to) master 151 | integrationpush="$integrationpush $newbranch" 152 | fi 153 | 154 | fi 155 | newcommits=$((newcommits+1)) 156 | else 157 | # Failed bump the version - ensure we don't push up. 158 | output " - ${R}Version file changes unsuccessful.${N}" 159 | _pushup=false 160 | return=1 161 | fi 162 | fi 163 | return $return; 164 | } 165 | 166 | # Argument 1: Release 167 | get_release_tag_annotation() { 168 | local first=`expr match "$1" '\([0-9]\+\)'` 169 | local second=`expr match "$1" '[0-9]\+\.\([0-9]\+\)'` 170 | local third=`expr match "$1" '[0-9]\+\.[0-9]\+\.\([0-9]\+\)'` 171 | local beta=`expr match "$1" '[0-9\.]\+ \?beta'` 172 | local rc=`expr match "$1" '[0-9\.]\+ \?rc\([0-9]\)'` 173 | local forth='' 174 | if [[ beta -gt 0 ]] ; then 175 | forth='_BETA' 176 | fi 177 | if [[ rc -gt 0 ]] ; then 178 | forth="_RC$rc" 179 | fi 180 | echo "MOODLE_$first$second$third$forth" 181 | } 182 | 183 | # Argument 1: Release 184 | get_release_tag_version() { 185 | local tag='' 186 | local release=`expr match "$1" '\([0-9\.]\+\)'` 187 | if [ -z `expr match "$release" '[0-9]\+\.[0-9]\+\(\.[0-9]\)'` ] ; then 188 | tag="v$release.0" 189 | else 190 | tag="v$release" 191 | fi 192 | local beta=`expr match "$1" '[0-9\.]\+ \?beta'` 193 | local rc=`expr match "$1" '[0-9\.]\+ \?rc\([0-9]\)'` 194 | local sub='' 195 | if [[ beta -gt 0 ]] ; then 196 | sub='-beta' 197 | fi 198 | if [[ rc -gt 0 ]] ; then 199 | sub="-rc$rc" 200 | 201 | fi 202 | echo "$tag$sub" 203 | } 204 | 205 | get_new_stable_branch() { 206 | local first=`expr match "$1" '\([0-9]\+\)'` 207 | local second=`expr match "$1" '[0-9]\+\.\([0-9]\+\)'` 208 | echo "MOODLE_${first}${second}_STABLE" 209 | } 210 | output() { 211 | if $_verbose ; then 212 | echo "$1" 213 | fi 214 | } 215 | show_help() { 216 | bold=`tput bold` 217 | normal=`tput sgr0` 218 | echo "" 219 | echo "${bold}Moodle release - prerelease.sh script${normal}" 220 | echo "" 221 | echo "This tool prepares the gitmirror moodle repository for the next release and then" 222 | echo "spreads it to the integration server." 223 | echo "Before running this tool you must have run the installation script, this needs " 224 | echo "to be done only once." 225 | echo "" 226 | echo "${bold}Usage:${normal}" 227 | echo " ./prelease.sh [-b |--branch ] [-h|--help] [-n|--not-forced]" 228 | echo " [-p|--pushup] [-q|--quiet] [-t |--type ]" 229 | echo "" 230 | echo "${bold}Arguments:${normal}" 231 | echo "The following options can be used to control how this script runs:" 232 | echo " ${bold}-b${normal}, ${bold}--branch${normal}" 233 | echo " Limits the operation to just the branch that has been given." 234 | echo " By default the appropriate branches for the release type will all be" 235 | echo " operated on." 236 | echo " [${allbranches[@]}]" 237 | echo " ${bold}-d${normal}, ${bold}--date${normal}" 238 | echo " Enforces a build date for all the branches being processed. The use of" 239 | echo " this option overrides the default behavior, that is the following:" 240 | echo " 1) \"next monday\" is used for major and minor releases." 241 | echo " 2) \"today\" is used for any other release type." 242 | echo " ${bold}-n${normal}, ${bold}--not-forced${normal}" 243 | echo " By default the version file on all branches will be bumped. If this option" 244 | echo " has been specified then the version file will only be bumped if there are" 245 | echo " new commits on the branch" 246 | echo " ${bold}-p${normal}, ${bold}--pushup${normal}" 247 | echo " By default this script prepares everything to be pushed by does not push." 248 | echo " If this option is specified the staged commits and any tags will be pushed " 249 | echo " up to the integration server." 250 | echo " ${bold}-q${normal}, ${bold}--quiet${normal}" 251 | echo " If set this script produces no progress output. It'll let you know when " 252 | echo " its finished however." 253 | echo " ${bold}-t${normal}, ${bold}--type${normal}" 254 | echo " The type of release to prepare." 255 | echo " [${_types[@]}]" 256 | echo " ${bold}--no-create${normal}" 257 | echo " If this tool finds that one of the expected branches does not exist then" 258 | echo " by default it creates it. If this option is specified the tool will not" 259 | echo " create the branch but will exit with an error." 260 | echo "" 261 | echo " ${bold}-h${normal}, ${bold}--help${normal}" 262 | echo " Prints this help and exits." 263 | echo "" 264 | echo " ${bold}-r${normal}, ${bold}--reset${normal}" 265 | echo " Use this (exclusive) option to discard any current change in the local git" 266 | echo " clone (gitmirror dir), reseting it back to origin (integration.git)." 267 | echo " Causes the script to exit." 268 | echo "" 269 | echo " ${bold}-s${normal}, ${bold}--show${normal}" 270 | echo " Use this (exclusive) option to display all the current changes applied" 271 | echo " to the local git clone (gitmirror dir), comparing with integration.git." 272 | echo " If this option is specified it will output what it wants and the script" 273 | echo " Causes the script to exit." 274 | echo "" 275 | echo "If no arguments are provided to this script it prepares a weekly release on all " 276 | echo "expected branches." 277 | echo "For more information about the release process and how to go about it please " 278 | echo "have a look at: https://github.com/moodlehq/mdlrelease" 279 | echo "" 280 | echo "${bold}Examples:${normal}" 281 | echo "" 282 | echo " ${bold}./prerelease.sh${normal} runs a standard weekly release" 283 | echo " ${bold}./prerelease.sh -b MOODLE_19_STABLE${normal} runs a weekly release for one branch" 284 | echo " ${bold}./prerelease.sh -t minor${normal} runs a minor release" 285 | echo " ${bold}./prerelease.sh -t major${normal} runs a major release for master only" 286 | echo " ${bold}./prerelease.sh -t beta${normal} runs a beta release for master only" 287 | echo " ${bold}./prerelease.sh -t rc 2${normal} runs a release for rc2 for master only" 288 | echo " ${bold}./prerelease.sh -t on-demand 2${normal} runs a weekly on-demand (pre-release) for master only" 289 | echo " ${bold}./prerelease.sh -t on-sync 2${normal} runs a weekly on-sync (post-release) for master only" 290 | exit 0 291 | } 292 | 293 | reset_repo() { 294 | for branch in ${allbranches[@]}; do 295 | git show-ref --verify --quiet refs/heads/$branch 296 | if [[ $? -ge 1 ]] ; then 297 | output " - ${Y}Expected ${branch} not found.${N}"; 298 | output " It will be automatically created the next time you run a release"; 299 | output " unless you specify the --no-create option"; 300 | else 301 | output " - Reseting ${branch} to origin/${branch}." 302 | git checkout --quiet ${branch} && git reset --hard --quiet origin/${branch} 303 | fi 304 | done 305 | output " - Discarding any modification in the worktree." 306 | git clean -dfxq 307 | exit 0 308 | } 309 | 310 | show_changes() { 311 | changedbranches=() 312 | counter=1 313 | for branch in ${allbranches[@]}; do 314 | git show-ref --verify --quiet refs/heads/$branch 315 | if [[ $? -ge 1 ]] ; then 316 | output " - ${Y}Expected ${branch} not found.${N}"; 317 | output " It will be automatically created the next time you run a release"; 318 | output " unless you specify the --no-create option"; 319 | else 320 | logs="$( git log origin/${branch}..${branch} --oneline )" 321 | if [[ -n "${logs}" ]] ; then 322 | count=$(echo "${logs}" | wc -l) 323 | output " - Changes found in ${R}${branch}${N} (${count} commits). [${counter}]" 324 | changedbranches[${counter}]="${branch}" 325 | maxfound=${counter} 326 | let counter++ 327 | IFS=$'\n' 328 | for line in ${logs} ; do 329 | output " -> ${line}" 330 | done 331 | else 332 | output " - No changes in ${branch}" 333 | fi 334 | fi 335 | done 336 | output "" 337 | option="L" # Default to list status 338 | while [[ "${option}" != "Q" ]] ; do 339 | case "${option}" in 340 | L) # list status. 341 | if [ ${#changedbranches[@]} -eq 0 ]; then 342 | output "There are no local changes. Friendly exiting. Bye!" 343 | exit 0 344 | else 345 | output "These branches have local changes" 346 | for i in "${!changedbranches[@]}"; do 347 | output " [${i}] => ${changedbranches[$i]}" 348 | done 349 | fi 350 | ;; 351 | 352 | A) # show all branches details. 353 | if [ ${#changedbranches[@]} -eq 0 ]; then 354 | output "There are no local changes. Friendly exiting. Bye!" 355 | exit 0 356 | else 357 | for i in "${!changedbranches[@]}"; do 358 | output "You are going to view ${G}${changedbranches[$i]}${N} local changes. Press any key." 359 | read -sn1 360 | LESS=-+F-r git diff origin/${changedbranches[$i]}..${changedbranches[$i]} 361 | done 362 | fi 363 | ;; 364 | 365 | [123456789]) # show 1 branch detail. 366 | if [[ ${option} -gt ${maxfound} ]]; then 367 | output "Option out of range, please use a correct alternative [1..${maxfound}]." 368 | else 369 | output "You are going to view ${G}${changedbranches[$option]}${N} local changes. Press any key." 370 | read -sn1 371 | LESS=-+F-r git diff origin/${changedbranches[$option]}..${changedbranches[$option]} 372 | fi 373 | ;; 374 | 375 | Q) # bye! 376 | exit 377 | ;; 378 | 379 | *) 380 | output "Incorrect option, please try again!" 381 | ;; 382 | esac 383 | output "" 384 | output "${G}Pick an option ${N}([${R}L${N}]ist status, [[${R}1..${maxfound}${N}] => 1 branch details, [${R}A${N}]ll branches details, [${R}Q${N}]uit):" 385 | read -n1 option 386 | option=$(echo $option | tr '[:lower:]' '[:upper:]') 387 | output "" 388 | done 389 | exit 0 390 | } 391 | 392 | _showhelp=false 393 | while test $# -gt 0; 394 | do 395 | case "$1" in 396 | -b | --branch) 397 | shift # Get rid of the flag. 398 | _onlybranch="$1" 399 | shift # Get rid of the value. 400 | ;; 401 | -t | --type) 402 | shift # Get rid of the flag. 403 | if in_array "$1" "${_types[@]}"; then 404 | _type=$1 405 | else 406 | echo "" 407 | echo "${R}* Invalid type specified.${N}" 408 | _showhelp=true 409 | fi 410 | shift # Get rid of the value. 411 | if [ "$_type" = "rc" ] ; then 412 | _rc=$1 413 | shift # Get rid of the RC release value 414 | fi 415 | ;; 416 | -p | --pushup) 417 | # _pushup=true 418 | echo "${Y}* The pushup option has been disabled until we really trust this script.${N}" 419 | shift # Get rid of the flag. 420 | ;; 421 | -n | --not-forced) 422 | _forcebump=false 423 | shift # Get rid of the flag. 424 | ;; 425 | -q | --quiet) 426 | _verbose=false 427 | shift # Get rid of the flag. 428 | ;; 429 | -d | --date) 430 | shift # Get rid of the flag. 431 | _date="$1" 432 | shift # Get rid of the value. 433 | ;; 434 | -r | --reset) 435 | _reset=true 436 | shift # Get rid of the flag. 437 | ;; 438 | -s | --show) 439 | _show=true 440 | shift # Get rid of the flag. 441 | ;; 442 | -h | --help) 443 | _showhelp=true 444 | shift 445 | ;; 446 | --no-create) 447 | _nocreate=true 448 | shift 449 | ;; 450 | *) 451 | echo "${R}* Invalid option $1 given.${N}" 452 | _showhelp=true 453 | shift 454 | esac 455 | done 456 | 457 | if $_showhelp ; then 458 | show_help 459 | fi 460 | 461 | if [[ ! -d ${mydir}/gitmirror ]] ; then 462 | output "Directory ${mydir}/gitmirror not found. You may need to create it with install.sh" 463 | exit 1 464 | fi 465 | cd ${mydir}/gitmirror 466 | pwd=`pwd` 467 | 468 | # Perform a reset before anything else. It's an exlusive and final option. 469 | if $_reset ; then 470 | output "${G}Reseting all local branches to origin and discarding worktree changes.${N}" 471 | reset_repo 472 | fi 473 | 474 | # Show all local changes before anything else. It's an exclusive and final option. 475 | if $_show ; then 476 | output "${G}Show changes in all the local branches compared with integration.git.${N}" 477 | show_changes 478 | fi 479 | 480 | if [[ $_rc -gt 0 ]] ; then 481 | output "${G}Starting pre-release processing for release candidate $_rc release.${N}" 482 | else 483 | output "${G}Starting pre-release processing for $_type release.${N}" 484 | fi 485 | 486 | # Check there are no changes in the repo that would cause us issues. 487 | all_clean 488 | output " - Git repository clean" 489 | output " - Fetching remotes" 490 | 491 | git fetch --all --prune --quiet 492 | if [[ $? -ge 1 ]] ; then 493 | # Drat it failed to fetch updates - we've got to bail. 494 | echo "$?" 495 | output "Failed to fetch updates from the remote repositories" 496 | exit 1 497 | fi 498 | 499 | # Establish the branches array by coping the relevant type array into it. 500 | branches=() 501 | case $_type in 502 | "weekly" ) 503 | branches=(${weeklybranches[@]}) 504 | ;; 505 | "minor" ) 506 | branches=(${minorbranches[@]}) 507 | ;; 508 | "major" ) 509 | branches=(${majorbranches[@]}) 510 | ;; 511 | "beta" ) 512 | branches=(${betabranches[@]}) 513 | ;; 514 | "rc" ) 515 | branches=(${rcbranches[@]}) 516 | ;; 517 | "on-demand" ) 518 | branches=(${rcbranches[@]}) 519 | ;; 520 | "on-sync" ) 521 | branches=(${rcbranches[@]}) 522 | ;; 523 | "back-to-dev" ) 524 | branches=(${rcbranches[@]}) 525 | ;; 526 | esac 527 | 528 | if [ ${#branches[@]} = 0 ] ; then 529 | # Obviously they didn't provide a valid type, there are no branches. 530 | output "Invalid type specified. This should never happen." 531 | exit 1 532 | fi 533 | 534 | branchesstr=$(printf ", %s" "${branches[@]}") 535 | if [[ $_onlybranch != '' ]] ; then 536 | if in_array "$_onlybranch" "${branches[@]}"; then 537 | # Only one branch requested and it's valid. Simplify the branches array. 538 | branches=($_onlybranch) 539 | else 540 | output "${R}The requested branch $_onlybranch is not a valid choice (${branchesstr:2}) for this release type${N}" 541 | exit 1 542 | fi 543 | fi 544 | 545 | output " - Operating on $_type branches: ${branchesstr:2}" 546 | 547 | # We're going to iterate over all branches, fast-forward them and then merge install strings. 548 | for branch in ${branches[@]}; 549 | do 550 | 551 | output "${G}Processing $branch${N}" 552 | 553 | # Ensure the branch exists. Useful when there have been major releases 554 | # since you last ran this tool. 555 | git show-ref --verify --quiet refs/heads/$branch 556 | if [[ $? -ge 1 ]] ; then 557 | # New branch. 558 | if $_nocreate ; then 559 | output "${R} Error: expected branch $branch does not exist.${N}" 560 | exit 1 561 | fi 562 | output " - Expected branch $branch does not exist, creating it now." 563 | git checkout --quiet -b $branch refs/remotes/origin/$branch 564 | else 565 | # Existing branch - change to it. 566 | git checkout --quiet $branch 567 | if [[ $? -ge 1 ]] ; then 568 | output "${Y}Failed to checkout $branch, skipping.${N}" 569 | continue; 570 | fi 571 | 572 | # Reset it. 573 | git reset --quiet --hard origin/$branch 574 | if [[ $? -ge 1 ]] ; then 575 | output "${Y}Failed to reset $branch, skipping.${N}" 576 | continue; 577 | fi 578 | fi 579 | 580 | # Set default operations. 581 | fixpermissions=true 582 | fixsvg=true 583 | mergestrings=true 584 | 585 | # Check that we do actually want to process this branch. 586 | if [ "$branch" == "master" ] ; then 587 | # master branch is included in everything except a minor release. 588 | if [ "$_type" == "minor" ] ; then 589 | # It's a minor release so we don't do anything with master. 590 | output "${Y}Skipping master as it's a minor release.${N}" 591 | continue 592 | fi 593 | mergestringsbranch="install_$branch" 594 | else 595 | # Must be a stable branch. 596 | # Stable branches are not included in major, beta, or rc releases. 597 | if [ "$_type" == "major" ] ; then 598 | # It's a major release so we don't do anything with the stable branches. 599 | output "${Y}Skipping $branch as it's a major release.${N}" 600 | continue 601 | fi 602 | if [ "$_type" == "beta" ] ; then 603 | # It's a beta release so we don't do anything with the stable branches. 604 | output "${Y}Skipping $branch as it's a beta release.${N}" 605 | continue 606 | fi 607 | if [ "$_type" == "rc" ] ; then 608 | # It's a rc release so we don't do anything with the stable branches. 609 | output "${Y}Skipping $branch as it's a rc release.${N}" 610 | continue 611 | fi 612 | if [ "$_type" == "on-demand" ] ; then 613 | # It's a on-demand release so we don't do anything with the stable branches. 614 | output "${Y}Skipping $branch as it's a on-demand release.${N}" 615 | continue 616 | fi 617 | if [ "$_type" == "on-sync" ] ; then 618 | # It's a on-sync release so we don't do anything with the stable branches. 619 | output "${Y}Skipping $branch as it's a on-sync release.${N}" 620 | continue 621 | fi 622 | # Get the segment of the stable branch name to use for merges. 623 | stable=`expr "$branch" : 'MOODLE_'` 624 | mergestringsbranch="install_${branch:$stable}" 625 | version=${branch:$stable:2} 626 | if (( "$version" < 24 )) ; then 627 | # Version less than Moodle 24 628 | fixsvg=false 629 | fi 630 | if (( "$version" < 23 )) ; then 631 | # Version less than Moodle 23 632 | mergestrings=false 633 | fixpermissions=false 634 | fi 635 | fi 636 | 637 | # Now merge in install strings. 638 | if $mergestrings ; then 639 | output " - Merging install strings..." 640 | git fetch --quiet https://git.in.moodle.com/amosbot/moodle-install.git $mergestringsbranch && git merge FETCH_HEAD --no-edit --quiet 641 | fi 642 | 643 | # Now fix SVG images if need be. 644 | if $fixsvg ; then 645 | output " - Fixing SVG permissions..." 646 | php ${mydir}/fixsvgcompatability.php --ie9fix --path=$pwd 647 | 648 | if git_unstaged_changes ; then 649 | # Add modifications and deletions. 650 | git add -u 651 | if git_staged_changes ; then 652 | git commit --quiet -m "NOBUG: Fixed SVG browser compatibility" 653 | fi 654 | # Make sure everything is clean again. 655 | all_clean 656 | output " ${Y}Fixes made as required.${N}" 657 | fi 658 | fi 659 | 660 | if $fixpermissions ; then 661 | output " - Fixing file permissions..." 662 | php ${mydir}/fixpermissions.php $pwd 663 | if git_unstaged_changes ; then 664 | # Add modifications and deletions. 665 | git add -u 666 | if git_staged_changes ; then 667 | git commit --quiet -m "NOBUG: Fixed file access permissions" 668 | fi 669 | # Make sure everything is clean again. 670 | all_clean 671 | output " ${Y}Permissions fixed as required.${N}" 672 | fi 673 | fi 674 | 675 | # Determine if we need to push this branch up to the integration server. 676 | newcommits=`git rev-list HEAD...origin/$branch --ignore-submodules --count` 677 | 678 | if (( $newcommits > 0 )) || $_forcebump ; then 679 | # Bump the version file. 680 | output " - Bumping version." 681 | if bump_version "$branch" "$_type" "$pwd" "$_rc" "$_date"; then 682 | # Yay it worked! 683 | if [ "$branch" == "master" ] && [ "$_type" == "major" ] ; then 684 | output " - Don't forget to read the notes." 685 | fi 686 | fi 687 | fi 688 | 689 | if (( $newcommits > 0 )) ; then 690 | output " + ${C}$branch done! $newcommits new commits to push.${N}" 691 | integrationpush="$integrationpush $branch" 692 | else 693 | output " + ${C}$branch done! No new commits to push.${N}" 694 | fi 695 | done; 696 | 697 | if $_pushup ; then 698 | # We're going to push to integration... man I hope this worked OK. 699 | output "${G}Pushing modified branches to the integration server${N}..." 700 | git push origin $integrationpush 701 | output "" 702 | echo "Pre-release processing has been completed and all changes have been propagated to the integration repository" 703 | 704 | else 705 | # We're not pushing up to integration so instead give the integrator the commands to do so. 706 | localbuffer="\ngit push origin$integrationpush\n$localbuffer" 707 | output "" 708 | echo "Pre-release processing has been completed." 709 | echo "Changes can be reviewed using the --show option." 710 | if [ $_type = "weekly" ] ; then 711 | echo "Changes have ${R}not${N} been propagated to the integration repository. If you wish to do this run the following:" 712 | else 713 | echo "Please propogate these changes to the integration repository with the following:" 714 | fi 715 | printf "$localbuffer\n"; 716 | # If any tag has been added locally, add a comment about CI and pushing the tag. 717 | if [[ $localbuffer =~ 'git tag -a' ]]; then 718 | echo "" 719 | echo "Once CI jobs have ended successfully, you can safely push the release tag(s) to the integration repository:" 720 | echo "" 721 | echo "git push origin --tags" 722 | fi 723 | fi 724 | echo "" 725 | 726 | if [ $_type == "major" ] || [ $_type == "minor" ]; then 727 | if [ $_type == "major" ] ; then 728 | echo "${Y}Notes${N}: " 729 | echo " As this was a major release you will need to update prerelease.sh to include the new stable branch as an expected branch." 730 | echo " As this was a major release you will need to update release.sh to include the new stable branch when releasing" 731 | fi 732 | echo " Follow the instructions for major and minor releases @ http://docs.moodle.org/dev/Release_process_(Combined)#Packaging." 733 | echo "" 734 | fi 735 | --------------------------------------------------------------------------------