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
|
/* eslint-disable no-unused-vars */
// Copyright (C) 2024 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 = "plugin_template";
// Cherry-pick bot requires using the "require()" function to load any modules,
// rather than the "import" statement.
const config = require("./config.json");
// Non-instanced modules can be loaded directly.
const gerritTools = require("../../gerritRESTTools");
// Set default values with the config file, but prefer environment variable.
function envOrConfig(ID) {
return process.env[ID] || config[ID];
}
// If you need to use a custom username/password for gerrit, you can set them
// here. Otherwise, the default cherry-pick-bot credentials will be used.
const customAuth = {
username: envOrConfig("MY_BOT_USER"),
password: envOrConfig("MY_BOT_PASS")
}
// This defines the class that will be instantiated by the notifier.
// The notifier will pass itself as the only argument to the constructor.
// This allows the plugin to access the notifier's properties and methods.
class plugin_template {
constructor(notifier) {
this.notifier = notifier; // /notifier.js
this.logger = notifier.logger; // /logger.js
this.retryProcessor = notifier.retryProcessor; // /retryProcessor.js
this.requestProcessor = notifier.requestProcessor; // /requestProcessor.js
// This line binds our local processPatch function to the
// the `this` context of this class. This is necessary because we will
// be passing this function to the server as a callback, and we want
// to be able to access the class's properties and methods from within
// the callback.
this.processPatch = this.processPatch.bind(this);
// This call to registerCustomListener binds our local processPatch
// function to the "integration_monitor_process_patch" event, emitted by
// 'server'. When the event is emitted, our function will be called with
// any arguments passed by the "emit()" call.
notifier.registerCustomListener(notifier.server, "integration_monitor_process_patch",
this.processPatch);
// This call to registerCustomEvent tells the server to call the inline
// callback when it receives a "patchset-created" event. The callback will
// always be called with the request object (incoming change data from
// codereview as its only argument).
notifier.server.registerCustomEvent("integration_monitor_entryPoint", "patchset-created",
(req) => { // Use an arrow function to preserve the "this" context.
// Do some trivial checks to see if we should do anything.
if (req.change.status == "MERGED")
return; // The CI created a new patchset upon change merge. Don't do anything.
// Check to see if a real person uploaded the last patchset.
let uploader = req.uploader.email;
let pickbotIsUploader = (uploader == "cherrypick_bot@qt-project.org");
if (req.change.owner.email != "cherrypick_bot@qt-project.org" && !pickbotIsUploader) {
// A real user is the uploader.
// Emit the internal event we registered above. This will call our
// processPatch function with the req and uploader arguments.
notifier.server.emit("integration_monitor_process_patch", req, uploader);
}
}
);
}
// This is the callback function that will be called when the
// "integration_monitor_process_patch" event is emitted in the event handling above.
processPatch(req, uploader) {
this.logger.log(
`Received patchset-created by ${uploader} for cherry-picked change in ${req.change.project}`,
"info", req.uuid
);
// Patchset-created does not include a full change ID. Assemble one. This is needed
// for avoiding conflicts in gerrit where the same change ID exists on multiple branches.
req.fullChangeID = encodeURIComponent(`${req.change.project}~${req.change.branch}~${req.change.id}`);
req.change.fullChangeID = req.fullChangeID;
// Dip into gerritTools to get some change details.
gerritTools.getChangeReviewers(req.uuid, req.change.fullChangeID, customAuth,
(success, reviewers) => {
if (success)
this.logger.log(`Reviewers: ${reviewers}`, "info", req.uuid);
else
this.logger.log(`Failed to get reviewers for ${req.change.fullChangeID}`,
"error", req.uuid);
}
);
}
}
module.exports = plugin_template;
|