|
| 1 | +#!/bin/bash |
| 2 | + |
| 3 | +set -e |
| 4 | + |
| 5 | +# For a given argument that is a release version, it will be the tag. For now, want the |
| 6 | +# format of `vX.Y.Z_A`. The underscore and `A` is important to include, as that is our |
| 7 | +# patch version that is separate from the upstream patch version |
| 8 | +release_name=$1 |
| 9 | +echo "release_name ${release_name}" |
| 10 | + |
| 11 | +# The minor number of the version, so of the release_name above which looks like `vX.Y`, |
| 12 | +# we are peeling off the `Y` for further use |
| 13 | +expected_minor=${release_name##*.} |
| 14 | +echo "expected_minor ${expected_minor}" |
| 15 | + |
| 16 | +# What our branch name will be. Upstream uses the format of `release-vX.Y` so to avoid |
| 17 | +# confusion we will pre-pend 'famedly' to that and use a `/` to namespace it. Like this: |
| 18 | +# `famedly-release/vX.Y`. We do want patch levels and hotfixes to live on the same |
| 19 | +# branch as the release major.minor |
| 20 | +release_branch_name="famedly-release/${release_name}" |
| 21 | +echo "release_branch_name ${release_branch_name}" |
| 22 | + |
| 23 | +upstream_release_branch_name="release-${release_name}" |
| 24 | +echo "upstream_release_branch_name ${upstream_release_branch_name}" |
| 25 | + |
| 26 | +logical_cores=$([ $(uname) = 'Darwin' ] && |
| 27 | + sysctl -n hw.logicalcpu_max || |
| 28 | + nproc) |
| 29 | + |
| 30 | +if [ -z "${release_name}" ]; then |
| 31 | + echo "Usage: $0 <release_name>" |
| 32 | + exit 1 |
| 33 | +fi |
| 34 | + |
| 35 | +if [ "${release_name}" = "-h" ]; then |
| 36 | + echo "Usage: $0 <release_name>" |
| 37 | + exit 0 |
| 38 | +fi |
| 39 | + |
| 40 | +echo -e "\e[32m>>>> fetching origin branches\e[0m" |
| 41 | +# If the release_name that was passed already exists as a tag, this will fatal error. |
| 42 | +# Make sure it does not legitimately exist, or that you really mean to replace it before |
| 43 | +# running `git tag -d <release_name>` to remove that one single tag |
| 44 | +git fetch --tags origin |
| 45 | + |
| 46 | +echo -e "\e[32m>>>> fetching upstream branches\e[0m" |
| 47 | +git fetch --tags upstream |
| 48 | + |
| 49 | +echo -e "\e[32m>>>> checkout master branch\e[0m" |
| 50 | +git checkout master-test |
| 51 | +echo -e "\e[32m>>>> resetting master branch\e[0m" |
| 52 | +git reset --hard |
| 53 | + |
| 54 | +echo -e "\e[32m>>>> find/checkout release branch\e[0m" |
| 55 | +# Temporarily disable error catching, as it will cause the script to halt |
| 56 | +# Normally this is not needed, but apparently our chosen branch name for famedly |
| 57 | +# releases causes fatal errors if it does not already exist. I believe it is caused by |
| 58 | +# the '/' in the branch name and how that can be a confusing reference for git to try |
| 59 | +# and sort out. |
| 60 | +# Specifically `famedly-release/vX.Y` comes across as 'fatal' instead of just |
| 61 | +# 'non-existent'. I choose to blame the '/' |
| 62 | +set +e |
| 63 | + |
| 64 | +# Expect this a '0' for exists and a '1' for not-exists. Fatal is a '128'. We apply a |
| 65 | +# NOT so the condition only runs if there was an error |
| 66 | +if ! git switch --quiet "$release_branch_name"; then |
| 67 | + echo "branch did not exist, creating" |
| 68 | + # -c creates the branch at our current checkout. Which should be a clean checkout of |
| 69 | + # the master branch from a moment ago |
| 70 | + git switch -c "$release_branch_name" |
| 71 | +fi |
| 72 | +# Have to re-enable error catching in case something else breaks |
| 73 | +set -e |
| 74 | + |
| 75 | +# Fetch existing tags on this branch. If this was a new branch from main, ours will be the |
| 76 | +# last tag added. If this was an existing branch we are appending to, ours will still be |
| 77 | +# the last tag added. |
| 78 | +last_tag_on_this_branch=$(git describe --tags --abbrev=0) |
| 79 | +echo "last_tag_on_this_branch $last_tag_on_this_branch" |
| 80 | + |
| 81 | +# Our patch level version, everything after the `_` |
| 82 | +famedly_patch_level=${last_tag_on_this_branch#*_} |
| 83 | +echo "famedly_patch_level ${famedly_patch_level}" |
| 84 | + |
| 85 | +# The major, minor and patch level, so `vX.Y.Z` |
| 86 | +long_ver=${last_tag_on_this_branch%_*} |
| 87 | +echo "long_ver ${long_ver}" |
| 88 | + |
| 89 | +# Just the patch level integer, so `Z` |
| 90 | +patch_level=${long_ver##*.} |
| 91 | +echo "patch_level $patch_level" |
| 92 | + |
| 93 | +# The `vX.Y` |
| 94 | +major_minor=${long_ver%.*} |
| 95 | +echo "major_minor $major_minor" |
| 96 | + |
| 97 | +# and just the `Y` |
| 98 | +minor_ver=${major_minor##*.} |
| 99 | +echo "minor_ver $minor_ver" |
| 100 | + |
| 101 | + |
| 102 | +# First determine if the upstream branch has incremented it's patch level |
| 103 | +upstreams_last_tag=$(git ls-remote --tags upstream "$release_name"* | grep -o 'refs/tags/v[0-9]*\.[0-9]*\.[0-9]*' | sort -rV | head -n1 | cut --delimiter='/' --fields=3) |
| 104 | +echo "upstreams_last_tag $upstreams_last_tag" |
| 105 | +upstream_patch_level=${upstreams_last_tag##*.} |
| 106 | +echo "upstream_patch_level $upstream_patch_level" |
| 107 | +upstream_major_minor=${upstreams_last_tag%.*} |
| 108 | +echo "upstream_major_minor $upstream_major_minor" |
| 109 | +upstream_minor_ver=${upstream_major_minor##.*} |
| 110 | + |
| 111 | +# if upstream patch level has increased, we bump ours too |
| 112 | +if [[ "$expected_minor" != "$minor_ver" ]]; then |
| 113 | + # must have been a version bump which means this is a new minor version release. In this case, it's likely that it is the same as what upstream's is |
| 114 | + expected_new_version_tag="${upstreams_last_tag}_1" |
| 115 | + echo -e "Likely new release minor version $expected_new_version_tag" |
| 116 | + |
| 117 | +elif [[ "$upstream_patch_level" -gt "$patch_level" ]]; then |
| 118 | + # no minor version bump but there was a patch level version bump, increment our expected patch level |
| 119 | + expected_new_version_tag="${upstreams_last_tag}_1" |
| 120 | + echo -e "Likely new release patch version $expected_new_version_tag" |
| 121 | + |
| 122 | +else |
| 123 | + # no minor and no patch level increase, this is probably just a famedly patch level increase |
| 124 | + increment_patch_level=$(( famedly_patch_level + 1)) |
| 125 | + expected_new_version_tag="${upstreams_last_tag}_$increment_patch_level" |
| 126 | + echo -e "Likely new famedly release patch version $expected_new_version_tag" |
| 127 | + |
| 128 | +fi |
| 129 | + |
| 130 | +echo -e "\e[32m>>>> merging master into release branch\e[0m" |
| 131 | +# We let this error if there was a merge conflict that needs to be resolved. It should |
| 132 | +# be an idempotent process of just rerunning the script to continue on. After a |
| 133 | +# `git merge --continue`, of course |
| 134 | +git merge "upstream/release-${release_name}" -m "Famedly ${release_name}" |
| 135 | + |
| 136 | + |
| 137 | +# Retrieve the git log entries themselves and format them to fit well into the |
| 138 | +# markdown format. If there were none, we can skip this whole next section |
| 139 | +git_log_output=$(git log $(git describe --tags --abbrev=0)..master-test --pretty=format:'- %s %C(bold blue)(%an)%Creset\' --no-merges --no-decorate | sort -u -f -k2) |
| 140 | + |
| 141 | +if [[ ! -z $git_log_output ]]; then |
| 142 | + echo -e "\e[32m>>>> Listing changes from main branch since last release\e[0m" |
| 143 | + # Find out how many lines down in CHANGES.md that the previous '# Synapse' entry |
| 144 | + # was. This gives us the line number needed to run the insertion. |
| 145 | + changelog_line_number=$(grep -n "# Synapse" CHANGES.md | awk 'NR==2 {print $1}' FS=":") |
| 146 | + |
| 147 | + # Shell expansion is stupid when it comes to escaping things. This is a hack to get the |
| 148 | + # new line character into a string that sed will actually interpret that does not |
| 149 | + # interfere with already appended '\' from the git log output. Used at the end to give |
| 150 | + # us the extra line inside the markdown. |
| 151 | + NL=$'\n' |
| 152 | + # Construct the sed command. This is a little messy. sed requires that new lines are a |
| 153 | + # '\' and not a normal ansi '\n'(and it will insert that for us). We need a basic header |
| 154 | + # for the entry and an additional new line at the end(the markdown itself does not care |
| 155 | + # but this makes it easier to find when opening the file directly). |
| 156 | + sed_command="${changelog_line_number} i\### Famedly additions for ${expected_new_version_tag}\n\n" |
| 157 | + sed_command+="${git_log_output}${NL}" |
| 158 | + |
| 159 | + # That should do it. The changes from our repo that occurred since the last upstream |
| 160 | + # merge(specifically that do not include said merge) should be inserted just above that |
| 161 | + # previous upstream merge(and just underneath the merge we are in the middle of). |
| 162 | + # Nice little bonus, they are printed in the console for us to see as the script runs |
| 163 | + sed -i "${sed_command}" CHANGES.md |
| 164 | + |
| 165 | + # Amend the last commit(which should be the merge commit itself) to incorporate changes |
| 166 | + # from the changelog just produced |
| 167 | + git add CHANGES.md |
| 168 | + git commit --amend --no-edit --allow-empty |
| 169 | +fi |
| 170 | +#echo "Check any changes or adjustments that need to be made, then" |
| 171 | +#read -n 1 -s -r -p "Press any key to continue merge..." |
| 172 | + |
| 173 | +read -n 1 -p "Press 'p' to push branch to Github, or any other key to skip\n" input_key |
| 174 | +if [[ $input_key == "p" ]]; then |
| 175 | + echo -e "\e[32m>>>> pushing release branch\e[0m" |
| 176 | + git push --force -u origin "${release_branch_name}" |
| 177 | +fi |
| 178 | + |
| 179 | +read -n 1 -p "Press 't' to run linting and tests, or any other key to skip\n" input_key |
| 180 | +if [[ $input_key == "t" ]]; then |
| 181 | + echo -e "\e[32m>>>> running lint and tests...\e[0m" |
| 182 | + # Make sure there are no weirdities around poetry. Until the deprecation migration |
| 183 | + # occurs, expect orange things to read here. |
| 184 | + #poetry check |
| 185 | + #poetry install --extras all --no-interaction |
| 186 | + #poetry run ./scripts-dev/lint.sh |
| 187 | + #poetry run trial -j"${logical_cores}" tests |
| 188 | + echo -e "\e[32m>>>> Success!\e[0m" |
| 189 | +fi |
| 190 | + |
| 191 | +read -n 1 -p "Press 't' to create tag and push to Github, or any other key to skip\n" input_key |
| 192 | +if [[ $input_key == "t" ]]; then |
| 193 | + echo -e "\e[32m>>>> updating release tag\e[0m" |
| 194 | + git tag -f -s -m "${expected_new_version_tag}" "${expected_new_version_tag}" |
| 195 | +# git push -f origin "${expected_new_version_tag}" |
| 196 | +fi |
| 197 | +echo -e "\e[32m>>>> Finished!\e[0m" |
0 commit comments