Newer
Older
# additional patch checks before pushing, e.g. for r-b tags
function checkpatch_commit_push
{
local sha1 managed_branch rv author committer author_outlook cite
cite=$(dim_cite $sha1)
# use real names for people with many different email addresses
author=$(git show -s $sha1 --format="format:%an")
author_email=$(git show -s $sha1 --format="format:%ae")
committer=$(git show -s $sha1 --format="format:%cn")
# outlook mangles mails into "Last, First"
author_outlook=$(git show -s $sha1 --format="format:%an" | sed -e 's/\([^ ]*\) \(.*\)/\2, \1/')
author_translit=$(echo $author | iconv -t ASCII//TRANSLIT)
# check for fd.o mailman From: mangling
if git show -s $sha1 --format="format:%ae %ce"| grep -q '@lists\.freedesktop\.org' ; then
echoerr "$cite: mailman wrangled email address detected."
rv=1
fi
# check for author sign-off
if ! git show -s $sha1 | grep -qi "Signed-off-by:.*\\($author\\|$author_outlook\\|$author_translit\\|$author_email\\)" ; then
echoerr "$cite: author Signed-off-by missing."
fi
# check for committer sign-off
if ! git show -s $sha1 | grep -qi "Signed-off-by:.*$committer" ; then
echoerr "$cite: committer Signed-off-by missing."
fi
# check for Link tag
if [[ $LINK_MISSING_I_KNOW -ne 1 ]] && [[ "$managed_branch" = "1" ]] && ! git show -s $sha1 | grep -qi 'Link:' ; then
echoerr "$cite: Link tag missing."
if ! git show -s $sha1 | grep -qi '\(reviewed\|acked\)\S*-by:' && \
! [[ "$committer" != "$author" ]]; then
echoerr "$cite: mandatory review missing."
# check for leftover dim extract-tags marker
if git show -s $sha1 | grep -qF "$dim_extract_tags_marker" ; then
echoerr "$cite: leftover dim extract-tags marker."
rv=1
fi
if ! checkpatch_fixes_tag $sha1 ; then
rv=1
fi
return $rv
}
local sha1 managed_branch rv body_text cite
sha1=$1
managed_branch=${2}
rv=0
cite=$(dim_cite $sha1)
body_text="$(git show $sha1 -s --format="format:%b" | grep -v "^$" | grep -v "^\S*:")"
if [[ -z "$body_text" ]] ; then
echoerr "$cite: merge commit justification missing."
rv=1
fi
return $rv
}
function checkpatch_commit_push_range
{
rv=0
for sha1 in $(git rev-list "$@" --no-merges) ; do
checkpatch_commit_push $sha1 $managed_branch || rv=1
for sha1 in $(git rev-list "$@" --merges) ; do
checkmerge_commit_push $sha1 $managed_branch || rv=1
done
if [ $rv == "1" ] ; then
warn_or_fail "issues in commits detected"
fi
# push branch $1, rebuild drm-tip. the rest of the arguments are passed to git
local branch remote committer_email commit_count merge_count
shift
assert_branch $branch
committer_email=$(git_committer_email)
checkpatch_commit_push_range 1 "$branch@{u}..$branch" --first-parent --committer="$committer_email"
# Apart from maintainers pushing merges or rebases, most patches should
# be pushed in small batches.
commit_count=$(git rev-list --count --no-merges --first-parent "$branch@{u}..$branch")
merge_count=$(git rev-list --count --merges --first-parent "$branch@{u}..$branch")
if [[ $merge_count -gt 0 ]]; then
if ! ask_user "Pushing $merge_count merges and $commit_count non-merge commits. Merges should only be pushed by maintainers. Are you sure?"; then
echoerr "NOTE: Branch not pushed."
return 1
fi
elif [[ $commit_count -gt 10 ]]; then
if ! ask_user "Pushing $commit_count commits. Commits should be only be pushed in relatively small batches. Are you sure?"; then
echoerr "NOTE: Branch not pushed."
return 1
fi
fi
update_linux_next $branch drm-intel-next drm-intel-next-fixes drm-intel-fixes
update_linux_next $branch drm-intel-gt-next drm-intel-next-fixes drm-intel-fixes \
for-linux-next-gt "" # no for-linux-next-gt-fixes for now
update_linux_next $branch drm-misc-next drm-misc-next-fixes drm-misc-fixes
update_linux_next $branch drm-amd-next drm-amd-next-fixes drm-amd-fixes
dim_alias_pq=push-queued
function dim_push_queued
{
dim_push_branch drm-intel-next "$@"
}
dim_alias_pnf=push-next-fixes
function dim_push_next_fixes
{
dim_push_branch drm-intel-next-fixes "$@"
}
dim_alias_pf=push-fixes
function dim_push_fixes
{
dim_push_branch drm-intel-fixes "$@"
}
function dim_push
{
dim_push_branch $(git_current_branch) "$@"
}
function apply_patch #patch_file
local patch message_id committer_email patch_from sob rv
message_id=$(message_get_id $patch)
committer_email=$(git_committer_email)
patch_from=$(grep "^From:" "$patch" | head -1)
if [[ "$patch_from" != *"$committer_email"* ]] ; then
if ! git am --scissors -3 $sob "$@" $patch ; then
echoerr "ERROR: git apply-mbox failed"
return 1
fi
if [ -n "$message_id" ]; then
dim_commit_add_tag "Link: ${dim_link_base}${message_id}"
echoerr "WARNING: No message-id found in the patch file."
rv=1
if ! checkpatch_commit HEAD branch; then
if ! check_maintainer $branch HEAD; then
rv=1
fi
Ander Conselvan de Oliveira
committed
eval $DRY $DIM_POST_APPLY_ACTION
function check_merge_baseline
{
local pull_sha1 baseline_sha1 upstream_sha1
pull_sha1=$1
baseline_sha1=$2
upstream_sha1=$3
# the merge base between the pull and upstream is supposed to be in our
# tree already
if ! git merge-base --is-ancestor $(git merge-base $pull_sha1 $upstream_sha1) $baseline_sha1 ; then
echoerr "Pull request contains commits from $upstream_sha1"
echoerr "Please backmerge first"
warn_or_fail "Issues in pull request detected"
fi
}
# ensure the patch has prefixes (-p1), since otherwise it can confuse the git am
# 3-way merge logic. check the default source (a/) and destination (b/) prefixes.
function check_diff_prefix
{
local rv patch msg patch_recoded
patch="$1"
rv=$(grep -q -E "^diff --git a/.+ b/.+$" $patch)
if [ -z "$rv" ]; then
msg=$(mktemp --tmpdir dim-msg.XXXXXX)
patch_recoded=$(mktemp --tmpdir dim-patch.XXXXXX)
git mailinfo "$msg" "$patch_recoded" < $patch >/dev/null
rv=$(grep -q -E "^diff --git a/.+ b/.+$" $patch_recoded)
rm "$msg" "$patch_recoded"
fi
return $rv
}
# ensure we're on branch $1, and apply patches. the rest of the arguments are
# passed to git am.
dim_alias_ab=apply-branch
dim_alias_sob=apply-branch
function dim_apply_branch
{
local branch file rv
branch=${1:?$usage}
shift
file=$(mktemp)
dir=$(mktemp -d)
# Transitional
if [[ "$branch" = "drm-intel-next-queued" ]]; then
echoerr "ERROR: Please use drm-intel-next instead of drm-intel-next-queued."
return 1
fi
assert_branch $branch
assert_repo_clean
cat > $file
git mailsplit -b -o$dir $file > /dev/null
if ! check_diff_prefix "$patch"; then
warn_or_fail "Patch does not contain prefixes in its diff and can confuse git-am when applying"
fi
if ! apply_patch $patch "$@"; then
rv=1
fi
done
rm -rf $file $dir
local branch file message_id pull_branch rv merge_msg_file from_line
branch=${1:?$usage}
file=$(mktemp)
assert_branch $branch
assert_repo_clean
cat > $file
pull_branch=$(message_print_body "$file" |
sed -ne '/^[^>].*[gG]it repository at:$/,/for you to fetch/{p}' |
sed -ne '3,$p' | sed -ne '0,/^$/p' | tr '\n' ' ')
from_line=$(grep '^From:' $file | tail -n 1)
if [[ -z "$pull_branch" ]] ; then
echoerr "no pull request found"
return 1
fi
message_id=$(message_get_id $file)
if [ -z "$message_id" ]; then
warn_or_fail "No message-id found in the pull request file."
fi
echo Pulling $pull_branch ...
if [[ -z "$(git rev-list HEAD..FETCH_HEAD)" ]] ; then
warn_or_fail "Nothing in the pull request"
fi
check_merge_baseline FETCH_HEAD $branch $(branch_to_remote drm-fixes)/drm-fixes
check_merge_baseline FETCH_HEAD $branch origin/master
checkpatch_commit_push_range 0 "HEAD..FETCH_HEAD"
if ! $DRY git pull --no-rebase --no-ff $pull_branch ; then
if ! check_conflicts "$pull_branch" ; then
echoerr "Please resolve and then commit normally using git"
merge_msg_file="$(git_dir)/MERGE_MSG"
if [ -n "$message_id" ]; then
echo "$from_line" >> $merge_msg_file
echo "Link: ${dim_link_base}${message_id}" >> $merge_msg_file
return 1
else
$DRY git add -u
$DRY git commit --no-edit --quiet
$DRY dim_commit_add_tag "$from_line"
$DRY dim_commit_add_tag "Link: ${dim_link_base}${message_id}"
eval $DRY $DIM_POST_APPLY_ACTION
if ! dim_list_upstreams | grep -q "^$upstream\$"; then
if ! git rev-parse --verify -q "refs/tags/$upstream" > /dev/null ; then
warn_or_fail "$upstream is neither an upstream branch nor a tag"
fi
tip_remote=$(repo_to_remote drm-tip)
git fetch -q $tip_remote || true
if ! git merge-base --is-ancestor $upstream $tip_remote/drm-tip ; then
echoerr "Upstream $upstream not merged into drm-tip, aborting."
echoerr "Please make sure any backmerge is tested in drm-tip,"
echoerr "to give all the CI bots some time to find bugs."
exit 1
fi
assert_branch $branch
assert_repo_clean
}
function dim_backmerge
{
local branch upstream patch_file
branch=${1:?$usage}
upstream=${2:?$usage}
validate_upstream_baseline $branch $upstream
git merge --rerere-autoupdate --no-commit --no-ff $upstream >& /dev/null || true
cat > $patch_file <<-HERE
Merge $upstream into $branch
*** DETAILED BACKMERGE RATIONALE HERE ***
echoerr "Conflicts found while merging $upstream into $branch."
echoerr "This should only happen when git rerere gets confused"
echoerr "or if there's a manual fixup patch in drm-rerere."
echoerr "Please proceed with extreme caution."
echoerr "Once the conflict is resolved, commit it with"
echoerr " git commit -a"
fi
git add -u
git commit -s
}
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
function dim_rebase
{
local branch upstream patch_file
branch=${1:?$usage}
upstream=${2:?$usage}
validate_upstream_baseline $branch $upstream
git rebase --signoff $upstream >& /dev/null || true
if ! check_conflicts "$upstream" ; then
echoerr "Conflicts found while rebasing $branch onto $upstream."
echoerr "Please proceed with extreme caution."
echoerr "Resolve the conflict and test it. Once the conflict "
echoerr "is resolved, commit it with: "
echoerr " git commit -a"
echoerr "And continue the rebase with: "
echoerr " git rebase --continue"
exit 1
fi
}
function dim_add_link
{
local branch file message_id
shift
file=$(mktemp)
assert_branch $branch
assert_repo_clean
cat > $file
message_id=$(message_get_id $file)
rm -f $file
dim_commit_add_tag "Link: ${dim_link_base}${message_id}"
else
echoerr "No message-id found in the patch file."
fi
}
function dim_add_link_queued
{
dim_add_link drm-intel-next "$@"
}
function dim_add_link_fixes
{
dim_add_link drm-intel-fixes "$@"
}
function dim_add_link_next_fixes
{
dim_add_link drm-intel-next-fixes "$@"
}
dim_alias_aq=apply-queued
function dim_apply_queued
{
dim_apply_branch drm-intel-next "$@"
}
function dim_apply_fixes
{
dim_apply_branch drm-intel-fixes "$@"
}
function dim_apply_next_fixes
{
dim_apply_branch drm-intel-next-fixes "$@"
}
# apply patch to current branch, the rest of the arguments are passed to
# git am
dim_alias_am=apply
function dim_apply
{
dim_apply_branch $(git_current_branch) "$@"
}
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
# require b4 v0.13+ for the --config option and better b4.trailers-ignore-from
# support to ignore trailers from CI and kernel build bot mails
function assert_b4
{
local b4_cur b4_req
if ! hash $DIM_B4 2>/dev/null; then
echoerr "$DIM_B4 not found"
return 1
fi
b4_cur="$($DIM_B4 --version)"
b4_req="0.13"
if [[ "$(echo -e "$b4_req\n$b4_cur" | sort -V | head -n1)" != "$b4_req" ]]; then
echoerr "b4 v0.13 or later is required"
return 1
fi
return 0
}
# b4 shazam to branch $1, the rest of the arguments are passed to b4
function dim_b4_shazam_branch
{
local branch old_head rv
branch=${1:?$usage}
shift
assert_branch $branch
assert_repo_clean
assert_b4
old_head=$(git rev-parse HEAD)
# Ignore trailers from CI and bots. Link defaults to Lore.
$DIM_B4 --config b4.trailers-ignore-from="patchwork@emeril.freedesktop.org,lkp@intel.com" \
shazam --add-link --apply-cover-trailers --add-my-sob "$@"
# Checkpatch and more
for commit in $(git rev-list --reverse $old_head..HEAD); do
if ! checkpatch_commit $commit branch; then
rv=1
fi
if ! check_maintainer $branch $commit; then
rv=1
fi
done
return $rv
}
function dim_b4_shazam
{
dim_b4_shazam_branch $(git_current_branch) "$@"
}
function commit_list_references
local commit remote log
cd $DIM_PREFIX/drm-tip
remote=$(repo_to_remote drm-tip)
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
git fetch -q $remote || true
commit="$1"
log=$(mktemp)
git log --regexp-ignore-case --grep="${commit:0:8}" --oneline \
$commit..$remote/drm-tip > $log
if [ "$(cat $log)" != "" ]; then
echo "Commit ${commit:0:8} is referenced by later commits:"
sed 's/^/\t/' < $log
fi
rm -f $log
cd - >/dev/null
}
function dim_cherry_pick
{
local commit
commit=$(git rev-parse ${1:?$usage})
commit_list_references $commit
$DRY git cherry-pick -s -x -e $commit
function git_list_fixes
{
git log --reverse --format=format:%H --regexp-ignore-case \
--grep="^Cc:.*stable@vger\.kernel\.org" \
--grep="^Fixes: " \
"$@"
}
local branch log fail_log remote needed have_fixes branch_args fixes_branches b
remote=$(branch_to_remote $branch)
assert_branch $branch
case $branch in
drm-intel-next-fixes|drm-intel-fixes)
branch_args="$remote/$branch..$remote/drm-intel-next $remote/$branch..$remote/drm-intel-gt-next -- drivers/gpu/drm/i915"
fixes_branches="drm-intel-fixes drm-intel-next-fixes"
;;
drm-xe-next-fixes|drm-xe-fixes)
branch_args="$remote/$branch..$remote/drm-xe-next -- drivers/gpu/drm/xe"
fixes_branches="drm-xe-fixes drm-xe-next-fixes"
;;
*)
echoerr "Branch $branch not yet supported for the -fixes workflow"
exit 1
esac
# Look for commits *-next branches tagged as fixes.
for commit in $(git_list_fixes $branch_args); do
echo -n "Considering $(dim_cite $commit)... "
# Look at history for already cherry-picked fixes.
# Note: use *local* branches to account for unpushed commits.
for b in $fixes_branches; do
log="$(git log --format=%h --after=6months --grep="cherry picked .* $commit" $b | tr '\n' ' ')"
if [ -n "$log" ]; then
break
fi
done
if [ -n "$log" ]; then
echo "Already backported as $log. OK."
continue
fi
have_fixes=
needed=
for fixes in $(git show -s $commit | grep -i "^ Fixes: *[0-9a-fA-F]" | sed 's/^ *[Ff]ixes: *\([0-9a-fA-F]\+\).*/\1/'); do
have_fixes=1
fixes=$(git log -1 --format=format:%H $fixes 2>/dev/null || true)
if [[ -z "$fixes" ]]; then
continue
# FIXME: see if the commit to be fixed has been
# backported!
echo -n "Fixes: $(dim_cite $fixes). "
if [[ "$(git merge-base $branch $fixes)" = "$fixes" ]]; then
needed=1
fi
fix_of_fix=$(git log --grep="cherry picked from commit $fixes" --after=6months --format=format:%h $remote/$branch -1)
if [ -n "$fix_of_fix" ]; then
break
fi
done
# Note: Cc: stable will overrule Fixes:
if [[ -n "$have_fixes" && -z "$needed" && -z "$fix_of_fix" ]]; then
echo "Fixes a commit not in $branch. OK."
continue
echo "Try to cherry-pick."
commit_list_references $commit
if ! git cherry-pick -x -s $commit; then
echo "FAILED: $(dim_cite $commit)"
else
if [[ "$fix_of_fix" ]]; then
short_fixes_hash=$(git log -1 --format=format:%h $fixes 2>/dev/null || true)
git log -1 --pretty=%B | \
sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' | \
sed "s/$short_fixes_hash/$fix_of_fix/g" | \
git commit --amend -F-
fi
# FIXME: evolve this into an email report to commit authors etc.
if [ "$(cat $fail_log)" != "" ]; then
echo "Failed to cherry-pick:"
cat $fail_log
fi
}
function dim_cherry_pick_fixes
{
dim_cherry_pick_branch drm-intel-fixes "$@"
}
function dim_cherry_pick_next_fixes
{
dim_cherry_pick_branch drm-intel-next-fixes "$@"
dim_alias_ar=apply-resolved
function dim_apply_resolved
{
make $DIM_MAKE_OPTIONS && git add -u && git am --resolved
checkpatch_commit HEAD || true
eval $DRY $DIM_POST_APPLY_ACTION
dim_alias_mrr=magic-rebase-resolve
function dim_magic_rebase_resolve
{
git diff HEAD | patch -p1 -R
dim_magic_patch < $(git_dir)/rebase-merge/patch
git add -u
git rebase --continue
}
local conflict_files
cd $(cat $dim_last_path_file)
conflict_files=$(patch -p1 | grep "saving rejects" | sed -e "s/.*saving rejects to file \(.*\)/\1/")
if [[ $conflict_files != "" ]] ; then
echo conflicts found!
fi
for file in $conflict_files ; do
echo wiggling in ${file%.rej}:
#cat $file
rm -f ${file%.rej}.porig
wiggle -r ${file%.rej} $file || true
done
}
function dim_create_branch
{
local branch repo remote
branch=${1:?$usage}
start=${2:-HEAD}
repo=${branch%%/*}
branch=${branch#*/}
if [[ "$repo" = "$branch" ]]; then
echoerr "give branch in format repo/branch"
return 1
if git branch -r | grep -q "$remote/$branch"; then
echoerr "$branch already exists on $remote"
return 1
fi
# git push gives confusing error messages for non-existing branches,
# even with --dry-run, hence the even quieter $DRY
$DRY git_push $remote +$branch --set-upstream
$DRY sed -i "s/^\() # DO NOT CHANGE THIS LINE\)$/\t\"$repo\t\t${branch//\//\\\/}\"\n\1/" $dim_integration_config
$DRY git add $dim_integration_config
$DRY git commit --quiet -m "Add $repo $branch to $dim_integration_config"
}
function dim_remove_branch
{
local branch repo remote
if [[ -d $DIM_PREFIX/$branch ]] ; then
rm -R $DIM_PREFIX/$branch
git worktree prune &> /dev/null || true
fi
if git_branch_exists $branch && ! $DRY git branch -d $branch; then
warn_or_fail "Can't remove $branch in working repo"
echoerr "$branch not found in $dim_integration_config"
$DRY sed -i "/^[[:space:]]*\"${repo}[[:space:]]\+${branch//\//\\\/}.*$/d" $dim_integration_config
$DRY git add $dim_integration_config
$DRY git commit --quiet -m "Remove $repo $branch from $dim_integration_config"
if [[ -d $DIM_PREFIX/$1 ]] ; then
mkdir -p $(dirname $dim_last_path_file)
echo $path > $dim_last_path_file
local branch repo remote
if ! git_branch_exists $branch ; then
echoerr "$branch not found in $dim_integration_config"
if [ "$remote" == "" ] ; then
exit 1
fi
dim_checkout drm-intel-next "$@"
}
function dim_cof
{
dim_checkout drm-intel-fixes "$@"
}
function dim_conf
{
dim_checkout drm-intel-next-fixes "$@"
}
# $1 branch
# $2 commit
function check_maintainer
{
branch=$1
commit=$2
if [ "$branch" = "drm-intel-next" ]; then
if non_i915_files=$(git diff-tree --no-commit-id --name-only -r $commit | \
grep -v "^\(drivers/gpu/drm/i915/\|include/drm/i915\|include/uapi/drm/i915\|Documentation/gpu/i915\|drivers/gpu/drm/xe/display\\)") && [[ -n "$non_i915_files" ]]; then
echo -e "The following files are outside of i915 maintenance scope:\n"
echo "$non_i915_files"
echo -e "\nConfirm you have appropriate Acked-by and Reviewed-by for above files."
# $1 is the git sha1 to check
# $2 is the checkpatch profile
function checkpatch_commit
local commit rv checkpatch_options profile profile_options
profile=${2:-default}
# special branch profile maps branches to profiles
if [[ "$profile" = "branch" ]]; then
case "$(git_current_branch)" in
drm-intel-next|drm-intel-next-fixes|drm-intel-fixes)
profile=drm-intel
;;
drm-misc-next|drm-misc-next-fixes|drm-misc-fixes)
profile=drm-misc
;;
*)
profile=default
;;
esac
fi
# map profiles to checkpatch options
case "$profile" in
default)
profile_options=""
;;
drm-misc)
profile_options=""
;;
drm-intel)
profile_options="--max-line-length=100 --ignore=BIT_MACRO,SPLIT_STRING,LONG_LINE_STRING,BOOL_MEMBER"
;;
*)
echoerr "Unknown checkpatch profile $profile"
profile_options=""
;;
esac
checkpatch_options="-q --emacs --strict --show-types $profile_options -"
git --no-pager log --oneline -1 $commit
if ! git show --no-use-mailmap --pretty=email $commit |\
scripts/checkpatch.pl $checkpatch_options; then
# turn $1 in to a git commit range
function rangeish()
{
if [ -z "$1" ]; then
elif echo "$1" | grep -q '\.\.'; then
else
function escape_quotes
{
sed 's/"/\\"/g'
}
function dim_extract_tags
{
local branch range file tags
branch=${1:?$usage}
range=$(rangeish "${2:-}")
file=$(mktemp)
assert_branch $branch
assert_repo_clean
cat > $file
tags=$(message_print_body "$file" | grep -ai '^[^>]*[A-Za-z-]\+: [^ ]')
rm -f $file
if [[ -z "$tags" ]]; then
return 0
fi