3 # git-debpush -- create & push a git tag with metadata for an ftp-master upload
5 # Copyright (C) 2019 Sean Whitton
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 set -e$DGIT_TEST_DEBPUSH_DEBUG
23 # PRINCIPLES OF OPERATION
25 # - do not invoke dgit, do anything involving any tarballs, no network
26 # access except `git push` right at the end
28 # - do not look at the working tree, like `git push` `git tag`
30 # - we are always in split brain mode, because that fits this workflow,
31 # and avoids pushes failing just because dgit in the intermediary
32 # service wants to append commits
34 # - if there is no previous tag created by this script, require a quilt
35 # mode; if there is a previous tag, and no quilt mode provided, assume
36 # same quilt mode as in previous tag created by this script
38 # ---- Helper functions and variables
43 if [ -d "$temp" ]; then
57 get_file_from_ref () {
60 if git ls-tree --name-only -r "$branch" \
61 | grep -Eq "^$path$"; then
62 git cat-file blob $branch:$path
66 # ---- Parse command line
68 getopt=$(getopt -s bash -o 'nfu:' \
69 -l 'no-push,force,branch:,remote:,distro:,quilt:,gbp,dpm,\
70 baredebian,baredebian+git,baredebian+tarball' \
73 set -e$DGIT_TEST_DEBPUSH_DEBUG
84 '-n'|'--no-push') pushing=false; shift; continue ;;
85 '-u') git_tag_opts+=(-u "$2"); shift 2; continue ;;
86 '-f'|'--force') force=true; shift; continue ;;
87 '--gbp') quilt_mode='gbp'; shift; continue ;;
88 '--dpm') quilt_mode='dpm'; shift; continue ;;
89 '--branch') branch=$2; shift 2; continue ;;
90 '--remote') remote=$2; shift 2; continue ;;
91 '--distro') distro=$2; shift 2; continue ;;
92 '--quilt') quilt_mode=$2; shift 2; continue ;;
94 '--baredebian'|'--baredebian+git')
95 quilt_mode=baredebian; shift; continue ;;
96 '--baredebian+tarball')
97 quilt_mode=baredebian+tarball; shift; continue ;;
100 *) badusage "unknown option $1" ;;
105 badusage 'no positional arguments allowed'
108 case "$quilt_mode" in
109 linear|auto|smash|nofix|gbp|dpm|unapplied|baredebian|baredebian+tarball|'') ;;
110 baredebian+git) quilt_mode="baredebian" ;;
111 *) badusage "invalid quilt mode: $quilt_mode" ;;
114 # ---- Gather git information
119 # Maybe $branch is a symbolic ref. If so, resolve it
120 branchref="$(git symbolic-ref -q $branch || test $? = 1)"
121 if [ "x$branchref" != "x" ]; then
124 # If $branch is the name of a branch but it does not start with
125 # 'refs/heads/', prepend 'refs/heads/', so that we can know later
126 # whether we are tagging a branch or some other kind of committish
130 branchref="$(git for-each-ref --format='%(objectname)' \
131 '[r]efs/heads/$branch')"
132 if [ "x$branchref" != "x" ]; then
133 branch="refs/heads/$branch"
138 # If our tag will point at a branch, push that branch, and add its
139 # pushRemote and remote to the things we'll check if the user didn't
143 b=${branch#refs/heads/}
145 remoteconfigs+=( branch.$b.pushRemote branch.$b.remote )
149 # also check, if the branch does not have its own pushRemote or
150 # remote, whether there's a default push remote configured
151 remoteconfigs+=(remote.pushDefault)
153 if $pushing && [ "x$remote" = "x" ]; then
154 for c in "${remoteconfigs[@]}"; do
155 remote=$(git config "$c" || test $? = 1)
156 if [ "x$remote" != "x" ]; then break; fi
158 if [ "x$remote" = "x" ]; then
159 fail "pushing, but could not determine remote, so need --remote="
163 # ---- Gather source package information
168 git cat-file blob "$branch":debian/changelog >"$temp/debian/changelog"
169 version=$(cd $temp; dpkg-parsechangelog -SVersion)
170 source=$(cd $temp; dpkg-parsechangelog -SSource)
171 target=$(cd $temp; dpkg-parsechangelog -SDistribution)
175 # ---- Useful sanity checks
179 if [ "$target" = "UNRELEASED" ]; then
180 fail "UNRELEASED changelog"
183 # TODO additional checks we might do:
185 # - are we uploading to a different suite from the last tag
186 # (e.g. unstable after experimental)? user should pass option to
189 # - walking backwards from $branch, if there is an archive/ strictly
190 # before we reach most recent debian/ tag, error, this might be a
191 # push of the dgit view to the maintainer branch
195 # ---- Create the git tag
197 format="$(get_file_from_ref debian/source/format)"
199 '3.0 (quilt)') upstream=true ;;
200 '3.0 (native)') upstream=false ;;
202 if get_file_from_ref debian/source/options | grep '^-sn *$'; then
204 elif get_file_from_ref debian/source/options | grep '^-sk *$'; then
207 fail 'please see "SOURCE FORMAT 1.0" in git-debpush(1)'
211 fail "unsupported debian/source/format $format"
217 upstream_tag=$(git deborig --just-print --version="$version" \
219 upstream_committish=$(git rev-parse ${upstream_tag}^{})
220 upstream_info=" upstream-tag=$upstream_tag upstream=$upstream_committish"
223 # convert according to DEP-14 rules
224 git_version=$(echo $version | tr ':~' '%_' | sed 's/\.(?=\.|$|lock$)/.#/g')
226 debian_tag="$distro/$git_version"
228 # If the user didn't supply a quilt mode, look for it in a previous
229 # tag made by this script
230 if [ "x$quilt_mode" = "x" ] && [ "$format" = "3.0 (quilt)" ]; then
231 set +o pipefail # perl will SIGPIPE git-log(1) here
232 tag=$(git log --pretty=format:'%D' --decorate=full "$branch" \
233 | perl -wne 'use Dpkg::Version;
234 @pieces = split /, /, $_;
235 @debian_tag_vs = sort {version_compare($b, $a)}
236 map { m|tag: refs/tags/debian/(.+)| ? $1 : () } @pieces;
237 if (@debian_tag_vs) { print "debian/$debian_tag_vs[0]\n"; exit }')
238 if [ "x$tag" != "x" ]; then
239 quilt_mode=$(git cat-file -p $(git rev-parse "$tag") \
241 'm/^\[dgit.*--quilt=([a-z+]+).*\]$/;
242 if ($1) { print "$1\n"; exit }')
248 if [ "$format" = "3.0 (quilt)" ]; then
249 if [ "x$quilt_mode" = "x" ]; then
250 echo >&2 "$us: could not determine the git branch layout"
251 echo >&2 "$us: please supply a --quilt= argument"
254 quilt_mode_text=" --quilt=$quilt_mode"
258 git tag "${git_tag_opts[@]}" -s -F- "$debian_tag" "$branch" <<EOF
259 $source release $version for $target
261 [dgit distro=$distro split$quilt_mode_text]
262 [dgit please-upload$upstream_info]
268 git push "$remote" "${push_branch[@]}" "$upstream_tag" "$debian_tag"