Refactoring of the Checks JavaScript plugin code
Remove `reboot`.
Rename `gr-checks.js` to `plugin.js`.
Move fetcher into `plugin.js`.
Move utility functions into separate `util.js` file.
Change-Id: I859baf98e7366e9b3297811142524e141d1bbaea
diff --git a/gr-checks/BUILD b/gr-checks/BUILD
index 8eee11e..7a1143b 100644
--- a/gr-checks/BUILD
+++ b/gr-checks/BUILD
@@ -10,5 +10,5 @@
gerrit_js_bundle(
name = "checks",
srcs = glob(["*.js"]),
- entry_point = "gr-checks.js",
+ entry_point = "plugin.js",
)
diff --git a/gr-checks/gr-checks-reboot.js b/gr-checks/gr-checks-reboot.js
deleted file mode 100644
index 1e7bdc2..0000000
--- a/gr-checks/gr-checks-reboot.js
+++ /dev/null
@@ -1,164 +0,0 @@
-/**
- * @license
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * Heads up! Everything in this file is still in flux. The new reboot checks API
- * is still in development. So everything in this file can change. And it is
- * expected that the amount of comments and tests is limited for the time being.
- */
-
-function pluralize(count, noun) {
- if (count === 0) return '';
- return `${count} ${noun}` + (count > 1 ? 's' : '');
-}
-
-function generateDurationString(startTime, endTime) {
- const secondsAgo = Math.round((endTime - startTime) / 1000);
-
- if (secondsAgo === 0) {
- return ZERO_SECONDS;
- }
-
- const durationSegments = [];
- if (secondsAgo % 60 !== 0) {
- durationSegments.push(`${secondsAgo % 60} sec`);
- }
- const minutesAgo = Math.floor(secondsAgo / 60);
- if (minutesAgo % 60 !== 0) {
- durationSegments.push(`${minutesAgo % 60} min`);
- }
- const hoursAgo = Math.floor(minutesAgo / 60);
- if (hoursAgo % 24 !== 0) {
- const hours = pluralize(hoursAgo % 24, 'hour', 'hours');
- durationSegments.push(`${hours}`);
- }
- const daysAgo = Math.floor(hoursAgo / 24);
- if (daysAgo % 30 !== 0) {
- const days = pluralize(daysAgo % 30, 'day', 'days');
- durationSegments.push(`${days}`);
- }
- const monthsAgo = Math.floor(daysAgo / 30);
- if (monthsAgo > 0) {
- const months = pluralize(monthsAgo, 'month', 'months');
- durationSegments.push(`${months}`);
- }
- return durationSegments.reverse().slice(0, 2).join(' ');
-}
-
-function computeDuration(check) {
- if (!check.started || !check.finished) {
- return '-';
- }
- const startTime = new Date(check.started);
- const finishTime = check.finished ? new Date(check.finished) : new Date();
- return generateDurationString(startTime, finishTime);
-}
-
-export class RebootFetcher {
- constructor(restApi) {
- this.restApi = restApi;
- }
-
- async fetchCurrent() {
- return this.fetch(this.changeNumber, this.patchsetNumber);
- }
-
- async fetch(changeData) {
- const {changeNumber, patchsetNumber} = changeData;
- this.changeNumber = changeNumber;
- this.patchsetNumber = patchsetNumber;
- const checks = await this.apiGet('?o=CHECKER');
- return {
- responseCode: 'OK',
- runs: checks.map(check => this.convert(check)),
- };
- }
-
- async apiGet(suffix) {
- return this.restApi.get(
- '/changes/' + this.changeNumber + '/revisions/' + this.patchsetNumber
- + '/checks' + suffix);
- }
-
- async apiPost(suffix) {
- return this.restApi.post(
- '/changes/' + this.changeNumber + '/revisions/' + this.patchsetNumber
- + '/checks' + suffix);
- }
-
- /**
- * Converts a Checks Plugin CheckInfo object into a Reboot Checks API Run
- * object.
- *
- * TODO(brohlfs): Refine this conversion and add tests.
- */
- convert(check) {
- let status = 'RUNNABLE';
- if (check.state === 'RUNNING' || check.state === 'SCHEDULED') {
- status = 'RUNNING';
- } else if (check.state === 'FAILED' || check.state === 'SUCCESSFUL') {
- status = 'COMPLETED';
- }
- const run = {
- checkName: check.checker_name,
- checkDescription: check.checker_description,
- externalId: check.checker_uuid,
- status,
- };
- if (check.started) run.startedTimestamp = new Date(check.started);
- if (check.finished) run.finishedTimestamp = new Date(check.finished);
- if (status === 'RUNNING') {
- run.statusDescription = check.message;
- if (check.url) {
- run.statusLink = check.url;
- }
- } else if (check.state === 'SUCCESSFUL') {
- run.statusDescription =
- check.message || `Passed (${computeDuration(check)})`;
- if (check.url) {
- run.statusLink = check.url;
- }
- } else if (check.state === 'FAILED') {
- run.results = [{
- category: 'ERROR',
- summary: check.message || `Failed (${computeDuration(check)})`,
- }];
- if (check.url) {
- run.results[0].links = [{
- url: check.url,
- primary: true,
- icon: 'EXTERNAL',
- }];
- }
- }
- if (status !== 'RUNNING') {
- run.actions = [{
- name: 'Run',
- primary: true,
- callback: () => this.run(check.checker_uuid),
- }];
- }
- return run;
- }
-
- run(uuid) {
- return this.apiPost('/' + uuid + '/rerun')
- .catch(e => {
- return {errorMessage: `Triggering the run failed: ${e.message}`};
- });
- }
-}
diff --git a/gr-checks/gr-checks.js b/gr-checks/gr-checks.js
deleted file mode 100644
index d72e920..0000000
--- a/gr-checks/gr-checks.js
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * @license
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import {RebootFetcher} from './gr-checks-reboot.js';
-
-Gerrit.install(plugin => {
- const checksApi = plugin.checks();
- const fetcher = new RebootFetcher(plugin.restApi());
- checksApi.register({
- fetch: data => fetcher.fetch(data),
- });
-});
diff --git a/gr-checks/plugin.js b/gr-checks/plugin.js
new file mode 100644
index 0000000..f8a0a35
--- /dev/null
+++ b/gr-checks/plugin.js
@@ -0,0 +1,117 @@
+/**
+ * @license
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import {computeDuration} from './util.js';
+
+class ChecksFetcher {
+ constructor(restApi) {
+ this.restApi = restApi;
+ }
+
+ async fetchCurrent() {
+ return this.fetch(this.changeNumber, this.patchsetNumber);
+ }
+
+ async fetch(changeData) {
+ const {changeNumber, patchsetNumber} = changeData;
+ this.changeNumber = changeNumber;
+ this.patchsetNumber = patchsetNumber;
+ const checks = await this.apiGet('?o=CHECKER');
+ return {
+ responseCode: 'OK',
+ runs: checks.map(check => this.convert(check)),
+ };
+ }
+
+ async apiGet(suffix) {
+ return this.restApi.get(
+ '/changes/' + this.changeNumber + '/revisions/' + this.patchsetNumber +
+ '/checks' + suffix);
+ }
+
+ async apiPost(suffix) {
+ return this.restApi.post(
+ '/changes/' + this.changeNumber + '/revisions/' + this.patchsetNumber +
+ '/checks' + suffix);
+ }
+
+ /**
+ * Converts a Checks Plugin CheckInfo object into a Checks API Run object.
+ */
+ convert(check) {
+ let status = 'RUNNABLE';
+ if (check.state === 'RUNNING' || check.state === 'SCHEDULED') {
+ status = 'RUNNING';
+ } else if (check.state === 'FAILED' || check.state === 'SUCCESSFUL') {
+ status = 'COMPLETED';
+ }
+ const run = {
+ checkName: check.checker_name,
+ checkDescription: check.checker_description,
+ externalId: check.checker_uuid,
+ status,
+ };
+ if (check.started) run.startedTimestamp = new Date(check.started);
+ if (check.finished) run.finishedTimestamp = new Date(check.finished);
+ if (status === 'RUNNING') {
+ run.statusDescription = check.message;
+ if (check.url) {
+ run.statusLink = check.url;
+ }
+ } else if (check.state === 'SUCCESSFUL') {
+ run.statusDescription =
+ check.message || `Passed (${computeDuration(check)})`;
+ if (check.url) {
+ run.statusLink = check.url;
+ }
+ } else if (check.state === 'FAILED') {
+ run.results = [{
+ category: 'ERROR',
+ summary: check.message || `Failed (${computeDuration(check)})`,
+ }];
+ if (check.url) {
+ run.results[0].links = [{
+ url: check.url,
+ primary: true,
+ icon: 'EXTERNAL',
+ }];
+ }
+ }
+ if (status !== 'RUNNING') {
+ run.actions = [{
+ name: 'Run',
+ primary: true,
+ callback: () => this.run(check.checker_uuid),
+ }];
+ }
+ return run;
+ }
+
+ run(uuid) {
+ return this.apiPost('/' + uuid + '/rerun')
+ .catch(e => {
+ return {errorMessage: `Triggering the run failed: ${e.message}`};
+ });
+ }
+}
+
+Gerrit.install(plugin => {
+ const checksApi = plugin.checks();
+ const fetcher = new ChecksFetcher(plugin.restApi());
+ checksApi.register({
+ fetch: data => fetcher.fetch(data),
+ });
+});
diff --git a/gr-checks/util.js b/gr-checks/util.js
new file mode 100644
index 0000000..478124c
--- /dev/null
+++ b/gr-checks/util.js
@@ -0,0 +1,60 @@
+/**
+ * @license
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+function pluralize(count, noun) {
+ if (count === 0) return '';
+ return `${count} ${noun}` + (count > 1 ? 's' : '');
+}
+
+function generateDurationString(startTime, endTime) {
+ const secondsAgo = Math.round((endTime - startTime) / 1000);
+ if (secondsAgo === 0) {
+ return '0 sec';
+ }
+ const durationSegments = [];
+ if (secondsAgo % 60 !== 0) {
+ durationSegments.push(`${secondsAgo % 60} sec`);
+ }
+ const minutesAgo = Math.floor(secondsAgo / 60);
+ if (minutesAgo % 60 !== 0) {
+ durationSegments.push(`${minutesAgo % 60} min`);
+ }
+ const hoursAgo = Math.floor(minutesAgo / 60);
+ if (hoursAgo % 24 !== 0) {
+ const hours = pluralize(hoursAgo % 24, 'hour', 'hours');
+ durationSegments.push(`${hours}`);
+ }
+ const daysAgo = Math.floor(hoursAgo / 24);
+ if (daysAgo % 30 !== 0) {
+ const days = pluralize(daysAgo % 30, 'day', 'days');
+ durationSegments.push(`${days}`);
+ }
+ const monthsAgo = Math.floor(daysAgo / 30);
+ if (monthsAgo > 0) {
+ const months = pluralize(monthsAgo, 'month', 'months');
+ durationSegments.push(`${months}`);
+ }
+ return durationSegments.reverse().slice(0, 2).join(' ');
+}
+
+export function computeDuration(check) {
+ if (!check.started || !check.finished) {
+ return '-';
+ }
+ const startTime = new Date(check.started);
+ const finishTime = check.finished ? new Date(check.finished) : new Date();
+ return generateDurationString(startTime, finishTime);
+}