File: release

package info (click to toggle)
augur 24.4.0-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 25,312 kB
  • sloc: python: 14,253; sh: 227; makefile: 35
file content (177 lines) | stat: -rwxr-xr-x 4,694 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#!/bin/bash
#
# Prepares a new version release locally, leaving you ready to either:
#
#   A. Push and upload it if you're satisfied with the state of git and the
#      built distributions, or…
#
#   B. Rewind the process if you're not (via devel/rewind-release or
#      manually).
#
# If you have GPG and git's user.signingKey option configured, a signed tag
# will be created.  Otherwise, an unsigned annotated tag will be used.
#
# The script will prompt you for the new version if you do not provide it as
# the sole argument.
#
set -euo pipefail

devel="$(dirname $0)"
repo="$devel/.."
version_file="$repo/augur/__version__.py"
changes_file="$repo/CHANGES.md"

main() {
    assert-clean-working-dir
    assert-changelog-has-additions

    if [[ $# -gt 0 ]]; then
        version="$1"
    else
        version=$(next-version)
    fi

    assert-version-is-new $version
    update-version $version
    update-changelog $version
    commit-and-tag $version
    build-dist
    remind-to-push $version
}

assert-clean-working-dir() {
    local status="$(git status --porcelain --untracked-files=no | grep -vwF "$(basename "$changes_file")" || true)"

    if [[ -n $status ]]; then
        echo "Please commit all changes before releasing:" >&2
        echo >&2
        echo "$status" >&2
        echo >&2
        echo "Only $(basename "$changes_file") is allowed to have uncommitted changes." >&2
        exit 1
    fi
}

assert-changelog-has-additions() {
    local current_version="$(read-version)"
    local numstat="$(git diff --numstat "$current_version" -- "$changes_file")"
    local insertions deletions rest

    if [[ -z $numstat ]]; then
        insertions=0
        deletions=0
    else
        read -r insertions deletions rest <<<"$numstat"
    fi

    local net_changed=$(($insertions - $deletions))

    if [[ $net_changed -lt 1 ]]; then
        echo "It doesn't look like $(basename "$changes_file") was updated; only $insertions - $deletions = $net_changed line(s) were changed." >&2
        exit 1
    fi
}

assert-version-is-new() {
    local current_version="$(read-version)"
    local new_version="$1"

    if [[ -z $new_version || $new_version == $current_version ]]; then
        echo "You must provide a new version!" >&2
        exit 1
    elif ! version-is-gt $current_version $new_version; then
        echo "You must provide a new version greater than the last!" >&2
        exit 1
    fi
}

version-is-gt() {
    python3 /dev/stdin "$1" "$2" <<<"$(cut -c 9- <<<'
        from sys import argv, exit
        from packaging.version import Version

        version = list(map(Version, argv[1:3]))

        gt = version[1] > version[0]

        exit(int(not gt))
    ')"
}

next-version() {
    local current_version="$(read-version)"

    # The ancient version of bash on macOS does not support the -i option, so
    # test if it works before using it.
    if read -i supported <<<"" 2>/dev/null >&2; then
        read -e -p "Current version is $current_version."$'\n'"New version? " -i "$current_version" new_version
    else
        read -e -p "Current version is $current_version."$'\n'"New version? " new_version
    fi

    echo "$new_version"
}

update-version() {
    local new_version="$1"
    local current_version="$(read-version)"

    perl -pi -e "s/(?<=^__version__ = ')(.*)(?='$)/$new_version/" "$version_file"

    if [[ $new_version != $(read-version) ]]; then
        echo "Failed to update $version_file!" >&2
        exit 1
    fi
}

update-changelog() {
    local new_version="$1"
    local today="$(date +"%d %B %Y")"

    # Remove leading zero from day if present
    today="${today#0}"

    # Add the new version heading immediately after the __NEXT__ heading,
    # preserving the __NEXT__ heading itself.
    perl -pi -e "s/(?<=^## __NEXT__$)/\n\n\n## $new_version ($today)/" "$changes_file"
}

commit-and-tag() {
    local version="$1"

    git commit -m "version $version" "$version_file" "$changes_file"

    if [[ -n "$(git config user.signingKey)" ]]; then
        git tag -sm "version $version" "$version"
    else
        git tag -am "version $version" "$version"
    fi
}

build-dist() {
    rm -rfv build/ dist/ nextstrain_augur.egg-info
    python3 -m build
}

remind-to-push() {
    local version="$1"

    echo
    echo
    echo "Version updated, committed, and tagged!"
    echo
    echo "Please remember to push, including tags:"
    echo
    echo "   git push origin master tag $version"
    echo
    echo "You'll also want to upload the built releases to PyPi:"
    echo
    echo "   twine upload dist/*"
    echo
}

read-version() {
    python3 -c "exec(open('''$version_file''').read()); print(__version__)"
}

main "$@"