summaryrefslogtreecommitdiff
path: root/round-robin-notify.sh
blob: d1b2dbb2dd2a5d20fef94d06b638d9468e6cbb7c (plain)
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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
#!/bin/bash

set -euf -o pipefail

scripts=$(dirname $0)
# shellcheck source=jenkins-helpers.sh
. $scripts/jenkins-helpers.sh

convert_args_to_variables "$@"
shift "$SHIFT_CONVERTED_ARGS"

obligatory_variables \
    artifacts BUILD_URL ci_project ci_config current_project \
    first_bad last_good summary
declare \
    artifacts BUILD_URL ci_project ci_config current_project \
    first_bad last_good summary

dryrun="${dryrun-false}"
icommits="interesting-commits"
verbose="${verbose-true}"

if $verbose; then
    set -x
fi

if $dryrun; then
    dryrun="echo DRYRUN: "
else
    dryrun=""
fi

prepare_interesting_commits ()
{
    (
    set -euf -o pipefail

    # Clone interesting-commits.git repo, which contains a regression
    # summaries for SHA1s.  These are the "first_bad" commits.
    clone_or_update_repo $icommits master \
			 https://git-us.linaro.org/toolchain/ci/interesting-commits.git \
			 auto master
    git_init_linaro_local_remote $icommits baseline false
    )
}

# Update interesting-commit's entry for a given commit
# $1: component
# $2: sha1 of first_bad commit
# $3: sha1 of last_good commit
#
# Interesting-commits store regression history in the following hierarchy:
# 1. At the top level we have COMPONENT directories.
# 2. At the 2nd level we have SHA1 directories.
# 2a. We also have "git describe" symlinks to SHA1 directories for convenience.
# 3. At the 3rd level we have CI_PROJECT directories.
# 4. At the 4th level we have CI_CONFIG directories, and ...
# 4a. ... status.txt, which contains status of changes from SHA1 across all
#     CI_CONFIGs in CI_PROJECT.
# 5. At the 5th level we have per-build files last_good, summary.txt, etc.
update_interesting_entry ()
{
    (
    set -euf -o pipefail

    local component="$1"
    local first_bad="$2"
    local last_good="$3"

    local subdir
    subdir=$(interesting_subdir "$component" "$first_bad")

    local describe
    describe=$(describe_sha1 "$component" "$first_bad" false)

    if ! [ -d $icommits/$subdir ] && [ x"$describe" != x"" ]; then
	local d
	d=$(dirname "$describe")
	mkdir -p $icommits/$component/$d
	local symlink=""
	while [ x"$d" != x"." ]; do
	    symlink="../$symlink"
	    d=$(dirname "$d")
	done
	symlink="${symlink}sha1/$first_bad"
	ln -s $symlink $icommits/$component/$describe
	git -C $icommits add $component/$describe
    fi

    # shellcheck disable=SC2154
    subdir=$(interesting_subdir "$component" "$first_bad" \
				"$ci_project" "$ci_config")
    mkdir -p "$icommits/$subdir"
    echo "$BUILD_URL" > "$icommits/$subdir/build_url"
    echo "$last_good" > "$icommits/$subdir/last_good"
    git -C "$icommits" add "$subdir/build_url" "$subdir/last_good"

    cp $summary "$icommits/$subdir/summary.txt"
    git -C "$icommits" add "$subdir/summary.txt"

    local status="$subdir/../status.txt"
    if [ x"$describe" = x"" ]; then
	describe=$(describe_sha1 "$component" "$first_bad" true)
    fi
    cat > $icommits/$status <<EOF
Status of $describe commit for $ci_project:
$(git -C "$component" log -n1 "$first_bad")
EOF
    local ci_config
    while read ci_config; do
	if ! [ -f "$icommits/$subdir/../$ci_config/summary.txt" ]; then
	    continue
	fi

	echo "* $ci_config"
	(
	    cat $icommits/$subdir/../$ci_config/summary.txt
	    cat $icommits/$subdir/../$ci_config/build_url
	) | sed "s/^/** /"
    done < <(cd $icommits/$subdir/..; ls) >> $icommits/$status
    git -C "$icommits" add "$status"
    )
}

update_interesting_commits ()
{
    (
    set -euf -o pipefail

    # Reset to master branch
    git -C $icommits remote update -p
    git -C $icommits reset -q --hard refs/remotes/baseline/master

    local isubdir
    isubdir=$(interesting_subdir "$current_project" "$first_bad" \
				 "$ci_project")
    local reported_before=false
    if [ -d "$icommits/$isubdir/$ci_config" ]; then
	reported_before=true
    fi

    # We have successfully identified a bad commit with a good parent!
    # Add $first_bad to interesting commits.
    update_interesting_entry "$current_project" "$first_bad" "$last_good"

    # Commit and push
    git -C $icommits commit -m "Add entry $first_bad from ${BUILD_URL-$(pwd)}"
    $dryrun git -C $icommits push baseline HEAD:refs/heads/master

    if $reported_before; then
	# This is a re-occurring problem (usually, in linux-next).
	# Don't spam developers.
	rm -f $artifacts/jira-status.txt $artifacts/mail-recipients.txt
    else
	touch $artifacts/jira-status.txt $artifacts/mail-recipients.txt
    fi
    )
}

# Update mail files with status of $first_bad regression
update_mail_files ()
{
    (
    set -euf -o pipefail

    if ! [ -f $artifacts/mail-recipients.txt ]; then
	return
    fi

    local isubdir
    isubdir=$(interesting_subdir "$current_project" "$first_bad" \
				 "$ci_project")

    sed -e "/#INTERESTING_COMMIT_STATUS#/r $icommits/$isubdir/status.txt" \
	-e "/#INTERESTING_COMMIT_STATUS#/d" \
	< $artifacts/mail-body.draft > $artifacts/mail-body.txt

    cp $artifacts/mail-subject.draft $artifacts/mail-subject.txt
    if [ "$(ls "$icommits/$isubdir" | wc -l)" = 2 ]; then
	cp $artifacts/mail-recipients.draft $artifacts/mail-recipients.txt
    else
	# This is not the first entry for $first_bad in $ci_project --
	# don't notify the patch author.
	# One line for ci_config, and one for status.txt.
	echo "bcc:tcwg-validation@linaro.org" \
	    > $artifacts/mail-recipients.txt
    fi
    )
}

# Post update to Jira
post_to_jira ()
{
    (
    set -euf -o pipefail

    if ! [ -f $artifacts/jira-status.txt ]; then
	return
    fi

    local isubdir
    isubdir=$(interesting_subdir "$current_project" "$first_bad" \
				 "$ci_project")

    sed -e "/#INTERESTING_COMMIT_STATUS#/r $icommits/$isubdir/status.txt" \
	-e "/#INTERESTING_COMMIT_STATUS#/d" \
	< $artifacts/jira-status.draft > $artifacts/jira-status.txt

    if [ -f $HOME/.jipdate.yml ]; then
	echo y | $dryrun jipdate.py -f $artifacts/jira-status.txt
    fi
    )
}

prepare_interesting_commits

while true; do
    update_interesting_commits &
    if wait $!; then
	update_mail_files
	post_to_jira
	break
    fi
done