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
|
/* eslint-disable no-unused-vars */
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
exports.id = "integration_monitor";
const gerritTools = require("../../gerritRESTTools");
// This plugin requires no additional config, and relies
// on the base cherry-pick-bot credentials.
// This plugin listens for failed integrations owned by the cherry-pick
// bot (The owner of a change is the uploader of the first patch set and cannot
// be changed). When such a change fails to integrate, this plugin adds
// the author of the most recent patch set to the attention set and posts
// a basic message.
class integration_monitor {
constructor(notifier) {
this.notifier = notifier;
this.logger = notifier.logger;
this.retryProcessor = notifier.retryProcessor;
this.requestProcessor = notifier.requestProcessor;
this.handleIntegrationFailed = this.handleIntegrationFailed.bind(this);
this.handlePatchsetCreated = this.handlePatchsetCreated.bind(this);
function pickbotIsOwner(userEmail) {
return userEmail == "cherrypick_bot@qt-project.org";
}
notifier.registerCustomListener(notifier.server, "integration_monitor_failed",
this.handleIntegrationFailed);
notifier.server.registerCustomEvent("integration_monitor_failed", "change-integration-fail",
function (req) {
// The change-integration-fail event doesn't have the patchset author,
// so query gerrit for the full change details.
gerritTools.queryChange(req.uuid, req.fullChangeID, undefined, undefined,
function(success, changeData) {
if (success) {
let author = changeData.revisions[changeData.current_revision].commit.author.email;
let pickbotIsAuthor = author == "cherrypick_bot@qt-project.org";
if (pickbotIsOwner(req.change.owner.email) && !pickbotIsAuthor) {
// A real user is the author and should be added to the attention set.
notifier.server.emit("integration_monitor_failed", req, author);
}
} else {
this.logger.log(`Failed to query gerrit for ${req.fullChangeID}`, "error", req.uuid);
}
}
);
}
);
notifier.registerCustomListener(notifier.server, "integration_monitor_patchset-created",
this.handlePatchsetCreated);
notifier.server.registerCustomEvent("integration_monitor_patchset-created", "patchset-created",
function(req) {
if (req.change.status == "MERGED")
return; // The CI created a new patchset upon change merge.
let uploader = req.uploader.email;
let pickbotIsUploader = uploader == "cherrypick_bot@qt-project.org";
if (pickbotIsOwner(req.change.owner.email) && !pickbotIsUploader) {
// A real user is the uploader and should be added to the attention set.
notifier.server.emit("integration_monitor_patchset-created", req, uploader);
}
}
);
}
doAddToAttentionSet(req, user, reason, callback) {
let _this = this;
gerritTools.addToAttentionSet(
req.uuid, req.change, user, reason, undefined,
function (success, msg) {
if (callback)
callback(success);
}
);
}
handleIntegrationFailed(req, author) {
let _this = this;
_this.logger.log(
`Received integration failure notification for cherry-picked change ${req.fullChangeID}`,
"info", req.uuid
);
req.change.fullChangeID = req.fullChangeID // Tack on the full change ID so it gets used
_this.doAddToAttentionSet(req, author, "Change author", (success) => {
if (!success) {
gerritTools.locateDefaultAttentionUser(req.uuid, req.change, req.change.owner.email,
(user, fallbackId) => {
if (user == "copyReviewers")
gerritTools.copyChangeReviewers(req.uuid, fallbackId, req.change.fullChangeID);
else {
gerritTools.setChangeReviewers(req.uuid, req.change.fullChangeID, [user], undefined,
function(){})
_this.doAddToAttentionSet(req, user, "Original reviewer");
}
});
}
});
}
handlePatchsetCreated(req, uploader) {
let _this = this;
_this.logger.log(
`Received patchset-created by ${uploader} for cherry-picked change ${req.change.project}`,
"info", req.uuid
);
// Patchset-created does not include a full change ID. Assemble one.
req.fullChangeID = encodeURIComponent(`${req.change.project}~${req.change.branch}~${req.change.id}`);
req.change.fullChangeID = req.fullChangeID;
gerritTools.locateDefaultAttentionUser(req.uuid, req.change, uploader, (user, fallbackId) => {
if (user == "copyReviewers")
gerritTools.copyChangeReviewers(req.uuid, fallbackId, req.change.fullChangeID);
else {
gerritTools.setChangeReviewers(req.uuid, req.change.fullChangeID, [user], undefined,
function(){})
_this.doAddToAttentionSet(req, user, "Original reviewer");
}
});
}
}
module.exports = integration_monitor;
|