github-merge-pr: add option to use SSH key for github auth
[maintainer-tools.git] / update_git_source_package.sh
1 #!/usr/bin/env bash
2 # update_git_source_package.sh: (c) 2023 Jo-Philipp Wich <jo@mein.io>
3 # Licensed under the terms of the Apache License, Version 2.0
4
5 MAKEFILE=$1
6 COMMIT=${2:-HEAD}
7 TOPDIR=$3
8
9 [ -n "$MAKEFILE" ] || {
10 cat <<-EOT
11 Usage: $0 <package name or makefile path> [revision] [topdir]
12
13 Update an OpenWrt package Makefile with PKG_SOURCE_PROTO:=git to
14 the given upstream revision (or 'HEAD' if omitted).
15
16 The script either accepts a package name, like "netifd" or
17 an absolute or relative path to a Makefile, e.g.
18 "./package/utils/ucode/Makefile".
19
20 If the revision argument is ommitted, the package is updated
21 to the current HEAD of the remote Git repository.
22
23 By default, this script tries to infer the buildroot directory
24 from the package Makefile path but it may be overridden by
25 passing it as 3rd argument. This is useful in situation where
26 the Makefile to update does not reside within an OpenWrt buildroot.
27
28 On success, the package Makefile is automatically modified and
29 the resulting changes are committed in the currently checked
30 buildroot branch using a standard commit message format.
31 EOT
32
33 exit 1
34 }
35
36 MAKE=$(which gmake) || MAKE=$(which make)
37 FIND=$(which gfind) || FIND=$(which find)
38
39 [ -x "$MAKE" ] || {
40 echo "Unable to locate `make` executable" >&2
41 exit 1
42 }
43
44 [ -x "$FIND" ] || {
45 echo "Unable to locate `find` executable" >&2
46 exit 1
47 }
48
49 [ -e "$MAKEFILE" ] || {
50 MAKEFILE=$("$FIND" "${TOPDIR:-.}/package/" -type f -path "*/$MAKEFILE/Makefile" | head -n1)
51 }
52
53 [ -f "$MAKEFILE" ] || {
54 echo "Usage: $0 <path/to/Makefile> [target commit] [path/to/buildroot/topdir]"
55 exit 1
56 }
57
58 grep -sq BuildPackage "$MAKEFILE" || {
59 echo "The file '$MAKEFILE' does not appear to be an OpenWrt package Makefile." >&2
60 exit 1
61 }
62
63 [ -n "$TOPDIR" ] || {
64 TOPDIR=$(cd "$(dirname "${MAKEFILE%/*}")"; pwd)
65
66 while [ "$TOPDIR" != "/" ]; do
67 TOPDIR=$(dirname "$TOPDIR")
68 [ -f "$TOPDIR/rules.mk" ] && break
69 done
70
71 [ -f "$TOPDIR/rules.mk" ] || {
72 echo "Unable to determine buildroot directory." >&2
73 exit 1
74 }
75 }
76
77 export TOPDIR
78 export PATH="$TOPDIR/staging_dir/host/bin:$PATH"
79
80 eval $(
81 "$MAKE" --no-print-directory -C "$(dirname "$MAKEFILE")" \
82 var.PKG_NAME \
83 var.PKG_RELEASE \
84 var.PKG_SOURCE_PROTO \
85 var.PKG_SOURCE_URL \
86 var.PKG_SOURCE_DATE \
87 var.PKG_SOURCE_VERSION \
88 var.PKG_MIRROR_HASH
89 )
90
91 case "$PKG_SOURCE_PROTO:$PKG_SOURCE_URL" in
92 git:http://*|git:https://*|git:git://*|git:file:*)
93 :
94 ;;
95 *)
96 echo "Unsupported combination of source protocol ('$PKG_SOURCE_PROTO') and url ('$PKG_SOURCE_URL')." >&2
97 exit 1
98 ;;
99 esac
100
101 TEMP_GIT_DIR=
102
103 for signal in INT TERM EXIT; do
104 trap '
105 [ -d "$TEMP_GIT_DIR" ] && rm -rf "$TEMP_GIT_DIR";
106 git -C "$(dirname "$MAKEFILE")" checkout --quiet "$(basename "$MAKEFILE")"
107 ' $signal
108 done
109
110 TEMP_GIT_DIR=$(mktemp -d) || {
111 echo "Unable to create temporary Git directory." >&2
112 exit 1
113 }
114
115 git clone --bare "$PKG_SOURCE_URL" "$TEMP_GIT_DIR" || {
116 echo "Unable to clone Git repository '$PKG_SOURCE_URL'." >&2
117 exit 1
118 }
119
120 GIT_LOG="$(git -C "$TEMP_GIT_DIR" log \
121 --reverse --no-merges \
122 --abbrev=12 \
123 --format="%h %s" \
124 "$PKG_SOURCE_VERSION..$COMMIT" \
125 )" || {
126 echo "Unable to determine changes from commit '$PKG_SOURCE_VERSION' to '$COMMIT'." >&2
127 exit 1
128 }
129
130 GIT_DATE_COMMIT=$(git -C "$TEMP_GIT_DIR" log \
131 -1 --format='%cd %H' \
132 --date='format:%Y-%m-%d' \
133 "$COMMIT" \
134 ) || {
135 echo "Unable to determine target commit ID and date." >&2
136 exit 1
137 }
138
139 GIT_FIXES="$(
140 IFS=$', \t\n'
141 for issue in $(
142 git -C "$TEMP_GIT_DIR" log \
143 --format="%b" \
144 "$PKG_SOURCE_VERSION..$COMMIT" \
145 | sed -rne 's%^Fixes:(([ ,]*([[:alnum:]_]*#[0-9]+|https?://[^[:space:]]+))+)$%\1%p'
146 ); do
147 case "$issue" in
148 http://*|https://*)
149 echo "$issue"
150 ;;
151 GH#[0-9]*|openwrt#[0-9]*)
152 echo "https://github.com/openwrt/openwrt/issues/${issue#*#}"
153 ;;
154 FS#[0-9]*)
155 echo "https://bugs.openwrt.org/?task_id=${issue#FS#}"
156 ;;
157 [a-zA-Z0-9_]*#[0-9]*)
158 echo "https://github.com/openwrt/${issue%#*}/issues/${issue#*#}"
159 ;;
160 '#'[0-9]*)
161 case "$PKG_SOURCE_URL" in
162 *://github.com/*)
163 echo "${PKG_SOURCE_URL%/}/issues/${issue#\#}"
164 ;;
165 *://git.openwrt.org/project/*)
166 project=${PKG_SOURCE_URL#*://git.openwrt.org/project/}
167 project=${project%.git}
168 echo "https://github.com/openwrt/${project}/issues/${issue#\#}"
169 ;;
170 esac
171 ;;
172 esac
173 done \
174 | sort --version-sort \
175 | uniq \
176 | sed -e 's#^#Fixes: #'
177 )"
178
179 sed -i -r \
180 -e "/PKG_SOURCE_VERSION/s#\<$PKG_SOURCE_VERSION\>#${GIT_DATE_COMMIT#* }#" \
181 -e "/PKG_SOURCE_DATE/s#\<$PKG_SOURCE_DATE\>#${GIT_DATE_COMMIT% *}#" \
182 "$MAKEFILE"
183
184 if [ -n "$PKG_RELEASE" ] && [ "$PKG_RELEASE" != "1" ]; then
185 sed -i -r \
186 -e "/PKG_RELEASE/s#\<$PKG_RELEASE\>#1#" \
187 "$MAKEFILE"
188 fi
189
190 eval $(
191 "$MAKE" --no-print-directory -C "$(dirname "$MAKEFILE")" \
192 var.PKG_SOURCE
193 )
194
195 "$MAKE" -C "$(dirname "$MAKEFILE")" download CONFIG_SRC_TREE_OVERRIDE= || {
196 echo "Unable to download and pack updated Git sources." >&2
197 exit 1
198 }
199
200 DL_HASH=$(sha256sum "$TOPDIR/dl/$PKG_SOURCE") || {
201 echo "Unable to determine archive checksum." >&2
202 exit 1
203 }
204
205 sed -i -r \
206 -e "/PKG_MIRROR_HASH/s#\<$PKG_MIRROR_HASH\>#${DL_HASH%% *}#" \
207 "$MAKEFILE"
208
209 git -C "$(dirname "$MAKEFILE")" commit \
210 --signoff --no-edit \
211 --message "$PKG_NAME: update to Git $COMMIT (${GIT_DATE_COMMIT% *})" \
212 --message "$GIT_LOG" \
213 ${GIT_FIXES:+--message "$GIT_FIXES"} \
214 "$(basename "$MAKEFILE")"
215
216 "$MAKE" --no-print-directory -C "$(dirname "$MAKEFILE")" check || {
217 echo "WARNING: Package check failed for updated Makefile!"
218 exit 1
219 }