From adc07d99c30b2ad465aaafe01bdde37ad6e5a789 Mon Sep 17 00:00:00 2001
From: janssen <118828444+janssen-tiobe@users.noreply.github.com>
Date: Wed, 4 Dec 2024 15:08:01 +0100
Subject: [PATCH 01/11] #34049: Added identifier to the summary body
---
dist/index.js | 792 +++++++++++-----------
src/action/decorate/summary.ts | 4 +
src/configuration/github.ts | 21 +-
src/github/comments.ts | 30 +-
test/.setup/mock.ts | 14 +-
test/integration/configuration.test.ts | 6 +
test/integration/httpclient.test.ts | 2 +
test/integration/octokit.test.ts | 2 +
test/unit/action/decorate/summary.test.ts | 2 +-
9 files changed, 472 insertions(+), 401 deletions(-)
diff --git a/dist/index.js b/dist/index.js
index e9f7393c..bd942abd 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -230,6 +230,7 @@ function createSummaryBody(analysisResult) {
core_1.summary.addRaw(createFilesSummary(projectResult.analyzedFiles));
}
});
+ core_1.summary.addRaw(`${config_1.githubConfig.getIdentifier()}`);
logger_1.logger.info('Created summary.');
return core_1.summary.stringify();
}
@@ -256,6 +257,7 @@ function createErrorSummaryBody(errorList, warningList) {
core_1.summary.addRaw(`:warning: ${warning}${os_1.EOL}${os_1.EOL}`);
}
}
+ core_1.summary.addRaw(`${config_1.githubConfig.getIdentifier()}`);
logger_1.logger.info('Created summary.');
return core_1.summary.stringify();
}
@@ -269,6 +271,7 @@ function createNothingAnalyzedSummaryBody(message) {
core_1.summary.addHeading('TICS Quality Gate');
core_1.summary.addHeading((0, markdown_1.generateStatusMarkdown)(enums_1.Status.PASSED, true), 3);
core_1.summary.addRaw(message);
+ core_1.summary.addRaw(`${config_1.githubConfig.getIdentifier()}`);
logger_1.logger.info('Created summary.');
return core_1.summary.stringify();
}
@@ -516,6 +519,7 @@ function findAnnotationInList(list, annotation) {
* @param unpostableReviewComments Review comments that could not be posted.
* @returns Summary of all the review comments that could not be posted.
*/
+// Exported for testing
function createUnpostableAnnotationsDetails(unpostableReviewComments) {
const label = 'Quality gate failures that cannot be annotated in Files Changed';
let body = '';
@@ -1018,17 +1022,25 @@ class GithubConfig {
event;
job;
action;
- id;
+ workflow;
+ runNumber;
+ runAttempt;
pullRequestNumber;
debugger;
+ id;
constructor() {
this.apiUrl = github_1.context.apiUrl;
this.owner = github_1.context.repo.owner;
this.reponame = github_1.context.repo.repo;
this.commitSha = github_1.context.sha;
this.event = this.getGithubEvent();
- this.job = github_1.context.job;
+ this.job = github_1.context.job.replace(/\s+/g, '-').replace(/_+/g, '-');
this.action = github_1.context.action.replace('__tiobe_', '');
+ this.workflow = github_1.context.workflow.replace(/\s+/g, '-').replace(/_+/g, '-');
+ this.runNumber = github_1.context.runNumber;
+ this.runAttempt = parseInt(process.env.GITHUB_RUN_ATTEMPT ?? '0', 10);
+ this.pullRequestNumber = this.getPullRequestNumber();
+ this.debugger = (0, core_1.isDebug)();
/**
* Construct the id to use for storing tmpdirs. The action name will
* be appended with a number if there are multiple runs within a job.
@@ -1039,10 +1051,7 @@ class GithubConfig {
* include a suffix that consists of the sequence number preceded by an underscore.
* https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables
*/
- const runAttempt = process.env.GITHUB_RUN_ATTEMPT ?? '0';
- this.id = `${github_1.context.runId.toString()}_${runAttempt}_${this.job}_${this.action}`;
- this.pullRequestNumber = this.getPullRequestNumber();
- this.debugger = (0, core_1.isDebug)();
+ this.id = `${github_1.context.runId.toString()}_${this.runAttempt.toString()}_${this.job}_${this.action}`;
this.removeWarningListener();
}
getPullRequestNumber() {
@@ -1074,6 +1083,9 @@ class GithubConfig {
return github_event_1.GithubEvent.PUSH;
}
}
+ getIdentifier() {
+ return [this.workflow, this.job, this.runNumber, this.runAttempt].join('_');
+ }
removeWarningListener() {
process.removeAllListeners('warning');
process.on('warning', warning => {
@@ -1621,7 +1633,7 @@ async function postComment(body) {
async function deletePreviousComments(comments) {
logger_1.logger.header('Deleting comments of previous runs.');
for (const comment of comments) {
- if (commentIncludesTicsTitle(comment.body)) {
+ if (shouldCommentBeDeleted(comment.body)) {
try {
const params = {
owner: config_1.githubConfig.owner,
@@ -1638,16 +1650,26 @@ async function deletePreviousComments(comments) {
}
logger_1.logger.info('Deleted review comments of previous runs.');
}
-function commentIncludesTicsTitle(body) {
- const titles = ['
TICS Quality Gate
', '## TICS Quality Gate', '## TICS Analysis'];
+function shouldCommentBeDeleted(body) {
if (!body)
return false;
+ const titles = ['TICS Quality Gate
', '## TICS Quality Gate', '## TICS Analysis'];
let includesTitle = false;
- titles.forEach(title => {
- if (body.startsWith(title))
+ for (const title of titles) {
+ if (body.startsWith(title)) {
includesTitle = true;
- });
- return includesTitle;
+ }
+ }
+ if (includesTitle) {
+ return containsIdentifier(body);
+ }
+ return false;
+}
+function containsIdentifier(body) {
+ const index = body.indexOf(`${config_1.githubConfig.workflow}_${config_1.githubConfig.job}`);
+ if (index === -1)
+ return true;
+ return body.substring(index, body.length - 4) !== config_1.githubConfig.getIdentifier();
}
@@ -41423,6 +41445,378 @@ function cleanEscapedString(input) {
}
+/***/ }),
+
+/***/ 93822:
+/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
+
+"use strict";
+
+exports.parseISO = parseISO;
+var _index = __nccwpck_require__(17818);
+
+/**
+ * The {@link parseISO} function options.
+ */
+
+/**
+ * @name parseISO
+ * @category Common Helpers
+ * @summary Parse ISO string
+ *
+ * @description
+ * Parse the given string in ISO 8601 format and return an instance of Date.
+ *
+ * Function accepts complete ISO 8601 formats as well as partial implementations.
+ * ISO 8601: http://en.wikipedia.org/wiki/ISO_8601
+ *
+ * If the argument isn't a string, the function cannot parse the string or
+ * the values are invalid, it returns Invalid Date.
+ *
+ * @typeParam DateType - The `Date` type, the function operates on. Gets inferred from passed arguments. Allows to use extensions like [`UTCDate`](https://github.com/date-fns/utc).
+ *
+ * @param argument - The value to convert
+ * @param options - An object with options
+ *
+ * @returns The parsed date in the local time zone
+ *
+ * @example
+ * // Convert string '2014-02-11T11:30:30' to date:
+ * const result = parseISO('2014-02-11T11:30:30')
+ * //=> Tue Feb 11 2014 11:30:30
+ *
+ * @example
+ * // Convert string '+02014101' to date,
+ * // if the additional number of digits in the extended year format is 1:
+ * const result = parseISO('+02014101', { additionalDigits: 1 })
+ * //=> Fri Apr 11 2014 00:00:00
+ */
+function parseISO(argument, options) {
+ const additionalDigits = options?.additionalDigits ?? 2;
+ const dateStrings = splitDateString(argument);
+
+ let date;
+ if (dateStrings.date) {
+ const parseYearResult = parseYear(dateStrings.date, additionalDigits);
+ date = parseDate(parseYearResult.restDateString, parseYearResult.year);
+ }
+
+ if (!date || isNaN(date.getTime())) {
+ return new Date(NaN);
+ }
+
+ const timestamp = date.getTime();
+ let time = 0;
+ let offset;
+
+ if (dateStrings.time) {
+ time = parseTime(dateStrings.time);
+ if (isNaN(time)) {
+ return new Date(NaN);
+ }
+ }
+
+ if (dateStrings.timezone) {
+ offset = parseTimezone(dateStrings.timezone);
+ if (isNaN(offset)) {
+ return new Date(NaN);
+ }
+ } else {
+ const dirtyDate = new Date(timestamp + time);
+ // JS parsed string assuming it's in UTC timezone
+ // but we need it to be parsed in our timezone
+ // so we use utc values to build date in our timezone.
+ // Year values from 0 to 99 map to the years 1900 to 1999
+ // so set year explicitly with setFullYear.
+ const result = new Date(0);
+ result.setFullYear(
+ dirtyDate.getUTCFullYear(),
+ dirtyDate.getUTCMonth(),
+ dirtyDate.getUTCDate(),
+ );
+ result.setHours(
+ dirtyDate.getUTCHours(),
+ dirtyDate.getUTCMinutes(),
+ dirtyDate.getUTCSeconds(),
+ dirtyDate.getUTCMilliseconds(),
+ );
+ return result;
+ }
+
+ return new Date(timestamp + time + offset);
+}
+
+const patterns = {
+ dateTimeDelimiter: /[T ]/,
+ timeZoneDelimiter: /[Z ]/i,
+ timezone: /([Z+-].*)$/,
+};
+
+const dateRegex =
+ /^-?(?:(\d{3})|(\d{2})(?:-?(\d{2}))?|W(\d{2})(?:-?(\d{1}))?|)$/;
+const timeRegex =
+ /^(\d{2}(?:[.,]\d*)?)(?::?(\d{2}(?:[.,]\d*)?))?(?::?(\d{2}(?:[.,]\d*)?))?$/;
+const timezoneRegex = /^([+-])(\d{2})(?::?(\d{2}))?$/;
+
+function splitDateString(dateString) {
+ const dateStrings = {};
+ const array = dateString.split(patterns.dateTimeDelimiter);
+ let timeString;
+
+ // The regex match should only return at maximum two array elements.
+ // [date], [time], or [date, time].
+ if (array.length > 2) {
+ return dateStrings;
+ }
+
+ if (/:/.test(array[0])) {
+ timeString = array[0];
+ } else {
+ dateStrings.date = array[0];
+ timeString = array[1];
+ if (patterns.timeZoneDelimiter.test(dateStrings.date)) {
+ dateStrings.date = dateString.split(patterns.timeZoneDelimiter)[0];
+ timeString = dateString.substr(
+ dateStrings.date.length,
+ dateString.length,
+ );
+ }
+ }
+
+ if (timeString) {
+ const token = patterns.timezone.exec(timeString);
+ if (token) {
+ dateStrings.time = timeString.replace(token[1], "");
+ dateStrings.timezone = token[1];
+ } else {
+ dateStrings.time = timeString;
+ }
+ }
+
+ return dateStrings;
+}
+
+function parseYear(dateString, additionalDigits) {
+ const regex = new RegExp(
+ "^(?:(\\d{4}|[+-]\\d{" +
+ (4 + additionalDigits) +
+ "})|(\\d{2}|[+-]\\d{" +
+ (2 + additionalDigits) +
+ "})$)",
+ );
+
+ const captures = dateString.match(regex);
+ // Invalid ISO-formatted year
+ if (!captures) return { year: NaN, restDateString: "" };
+
+ const year = captures[1] ? parseInt(captures[1]) : null;
+ const century = captures[2] ? parseInt(captures[2]) : null;
+
+ // either year or century is null, not both
+ return {
+ year: century === null ? year : century * 100,
+ restDateString: dateString.slice((captures[1] || captures[2]).length),
+ };
+}
+
+function parseDate(dateString, year) {
+ // Invalid ISO-formatted year
+ if (year === null) return new Date(NaN);
+
+ const captures = dateString.match(dateRegex);
+ // Invalid ISO-formatted string
+ if (!captures) return new Date(NaN);
+
+ const isWeekDate = !!captures[4];
+ const dayOfYear = parseDateUnit(captures[1]);
+ const month = parseDateUnit(captures[2]) - 1;
+ const day = parseDateUnit(captures[3]);
+ const week = parseDateUnit(captures[4]);
+ const dayOfWeek = parseDateUnit(captures[5]) - 1;
+
+ if (isWeekDate) {
+ if (!validateWeekDate(year, week, dayOfWeek)) {
+ return new Date(NaN);
+ }
+ return dayOfISOWeekYear(year, week, dayOfWeek);
+ } else {
+ const date = new Date(0);
+ if (
+ !validateDate(year, month, day) ||
+ !validateDayOfYearDate(year, dayOfYear)
+ ) {
+ return new Date(NaN);
+ }
+ date.setUTCFullYear(year, month, Math.max(dayOfYear, day));
+ return date;
+ }
+}
+
+function parseDateUnit(value) {
+ return value ? parseInt(value) : 1;
+}
+
+function parseTime(timeString) {
+ const captures = timeString.match(timeRegex);
+ if (!captures) return NaN; // Invalid ISO-formatted time
+
+ const hours = parseTimeUnit(captures[1]);
+ const minutes = parseTimeUnit(captures[2]);
+ const seconds = parseTimeUnit(captures[3]);
+
+ if (!validateTime(hours, minutes, seconds)) {
+ return NaN;
+ }
+
+ return (
+ hours * _index.millisecondsInHour +
+ minutes * _index.millisecondsInMinute +
+ seconds * 1000
+ );
+}
+
+function parseTimeUnit(value) {
+ return (value && parseFloat(value.replace(",", "."))) || 0;
+}
+
+function parseTimezone(timezoneString) {
+ if (timezoneString === "Z") return 0;
+
+ const captures = timezoneString.match(timezoneRegex);
+ if (!captures) return 0;
+
+ const sign = captures[1] === "+" ? -1 : 1;
+ const hours = parseInt(captures[2]);
+ const minutes = (captures[3] && parseInt(captures[3])) || 0;
+
+ if (!validateTimezone(hours, minutes)) {
+ return NaN;
+ }
+
+ return (
+ sign *
+ (hours * _index.millisecondsInHour + minutes * _index.millisecondsInMinute)
+ );
+}
+
+function dayOfISOWeekYear(isoWeekYear, week, day) {
+ const date = new Date(0);
+ date.setUTCFullYear(isoWeekYear, 0, 4);
+ const fourthOfJanuaryDay = date.getUTCDay() || 7;
+ const diff = (week - 1) * 7 + day + 1 - fourthOfJanuaryDay;
+ date.setUTCDate(date.getUTCDate() + diff);
+ return date;
+}
+
+// Validation functions
+
+// February is null to handle the leap year (using ||)
+const daysInMonths = [31, null, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
+
+function isLeapYearIndex(year) {
+ return year % 400 === 0 || (year % 4 === 0 && year % 100 !== 0);
+}
+
+function validateDate(year, month, date) {
+ return (
+ month >= 0 &&
+ month <= 11 &&
+ date >= 1 &&
+ date <= (daysInMonths[month] || (isLeapYearIndex(year) ? 29 : 28))
+ );
+}
+
+function validateDayOfYearDate(year, dayOfYear) {
+ return dayOfYear >= 1 && dayOfYear <= (isLeapYearIndex(year) ? 366 : 365);
+}
+
+function validateWeekDate(_year, week, day) {
+ return week >= 1 && week <= 53 && day >= 0 && day <= 6;
+}
+
+function validateTime(hours, minutes, seconds) {
+ if (hours === 24) {
+ return minutes === 0 && seconds === 0;
+ }
+
+ return (
+ seconds >= 0 &&
+ seconds < 60 &&
+ minutes >= 0 &&
+ minutes < 60 &&
+ hours >= 0 &&
+ hours < 25
+ );
+}
+
+function validateTimezone(_hours, minutes) {
+ return minutes >= 0 && minutes <= 59;
+}
+
+
+/***/ }),
+
+/***/ 50135:
+/***/ ((__unused_webpack_module, exports) => {
+
+"use strict";
+
+exports.parseJSON = parseJSON; /**
+ * @name parseJSON
+ * @category Common Helpers
+ * @summary Parse a JSON date string
+ *
+ * @description
+ * Converts a complete ISO date string in UTC time, the typical format for transmitting
+ * a date in JSON, to a JavaScript `Date` instance.
+ *
+ * This is a minimal implementation for converting dates retrieved from a JSON API to
+ * a `Date` instance which can be used with other functions in the `date-fns` library.
+ * The following formats are supported:
+ *
+ * - `2000-03-15T05:20:10.123Z`: The output of `.toISOString()` and `JSON.stringify(new Date())`
+ * - `2000-03-15T05:20:10Z`: Without milliseconds
+ * - `2000-03-15T05:20:10+00:00`: With a zero offset, the default JSON encoded format in some other languages
+ * - `2000-03-15T05:20:10+05:45`: With a positive or negative offset, the default JSON encoded format in some other languages
+ * - `2000-03-15T05:20:10+0000`: With a zero offset without a colon
+ * - `2000-03-15T05:20:10`: Without a trailing 'Z' symbol
+ * - `2000-03-15T05:20:10.1234567`: Up to 7 digits in milliseconds field. Only first 3 are taken into account since JS does not allow fractional milliseconds
+ * - `2000-03-15 05:20:10`: With a space instead of a 'T' separator for APIs returning a SQL date without reformatting
+ *
+ * For convenience and ease of use these other input types are also supported
+ * via [toDate](https://date-fns.org/docs/toDate):
+ *
+ * - A `Date` instance will be cloned
+ * - A `number` will be treated as a timestamp
+ *
+ * Any other input type or invalid date strings will return an `Invalid Date`.
+ *
+ * @param dateStr - A fully formed ISO8601 date string to convert
+ *
+ * @returns The parsed date in the local time zone
+ */
+function parseJSON(dateStr) {
+ const parts = dateStr.match(
+ /(\d{4})-(\d{2})-(\d{2})[T ](\d{2}):(\d{2}):(\d{2})(?:\.(\d{0,7}))?(?:Z|(.)(\d{2}):?(\d{2})?)?/,
+ );
+ if (parts) {
+ // Group 8 matches the sign
+ return new Date(
+ Date.UTC(
+ +parts[1],
+ +parts[2] - 1,
+ +parts[3],
+ +parts[4] - (+parts[9] || 0) * (parts[8] == "-" ? -1 : 1),
+ +parts[5] - (+parts[10] || 0) * (parts[8] == "-" ? -1 : 1),
+ +parts[6],
+ +((parts[7] || "0") + "00").substring(0, 3),
+ ),
+ );
+ }
+ return new Date(NaN);
+}
+
+
/***/ }),
/***/ 5619:
@@ -43949,378 +44343,6 @@ function isLeapYearIndex(year) {
}
-/***/ }),
-
-/***/ 93822:
-/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
-
-"use strict";
-
-exports.parseISO = parseISO;
-var _index = __nccwpck_require__(17818);
-
-/**
- * The {@link parseISO} function options.
- */
-
-/**
- * @name parseISO
- * @category Common Helpers
- * @summary Parse ISO string
- *
- * @description
- * Parse the given string in ISO 8601 format and return an instance of Date.
- *
- * Function accepts complete ISO 8601 formats as well as partial implementations.
- * ISO 8601: http://en.wikipedia.org/wiki/ISO_8601
- *
- * If the argument isn't a string, the function cannot parse the string or
- * the values are invalid, it returns Invalid Date.
- *
- * @typeParam DateType - The `Date` type, the function operates on. Gets inferred from passed arguments. Allows to use extensions like [`UTCDate`](https://github.com/date-fns/utc).
- *
- * @param argument - The value to convert
- * @param options - An object with options
- *
- * @returns The parsed date in the local time zone
- *
- * @example
- * // Convert string '2014-02-11T11:30:30' to date:
- * const result = parseISO('2014-02-11T11:30:30')
- * //=> Tue Feb 11 2014 11:30:30
- *
- * @example
- * // Convert string '+02014101' to date,
- * // if the additional number of digits in the extended year format is 1:
- * const result = parseISO('+02014101', { additionalDigits: 1 })
- * //=> Fri Apr 11 2014 00:00:00
- */
-function parseISO(argument, options) {
- const additionalDigits = options?.additionalDigits ?? 2;
- const dateStrings = splitDateString(argument);
-
- let date;
- if (dateStrings.date) {
- const parseYearResult = parseYear(dateStrings.date, additionalDigits);
- date = parseDate(parseYearResult.restDateString, parseYearResult.year);
- }
-
- if (!date || isNaN(date.getTime())) {
- return new Date(NaN);
- }
-
- const timestamp = date.getTime();
- let time = 0;
- let offset;
-
- if (dateStrings.time) {
- time = parseTime(dateStrings.time);
- if (isNaN(time)) {
- return new Date(NaN);
- }
- }
-
- if (dateStrings.timezone) {
- offset = parseTimezone(dateStrings.timezone);
- if (isNaN(offset)) {
- return new Date(NaN);
- }
- } else {
- const dirtyDate = new Date(timestamp + time);
- // JS parsed string assuming it's in UTC timezone
- // but we need it to be parsed in our timezone
- // so we use utc values to build date in our timezone.
- // Year values from 0 to 99 map to the years 1900 to 1999
- // so set year explicitly with setFullYear.
- const result = new Date(0);
- result.setFullYear(
- dirtyDate.getUTCFullYear(),
- dirtyDate.getUTCMonth(),
- dirtyDate.getUTCDate(),
- );
- result.setHours(
- dirtyDate.getUTCHours(),
- dirtyDate.getUTCMinutes(),
- dirtyDate.getUTCSeconds(),
- dirtyDate.getUTCMilliseconds(),
- );
- return result;
- }
-
- return new Date(timestamp + time + offset);
-}
-
-const patterns = {
- dateTimeDelimiter: /[T ]/,
- timeZoneDelimiter: /[Z ]/i,
- timezone: /([Z+-].*)$/,
-};
-
-const dateRegex =
- /^-?(?:(\d{3})|(\d{2})(?:-?(\d{2}))?|W(\d{2})(?:-?(\d{1}))?|)$/;
-const timeRegex =
- /^(\d{2}(?:[.,]\d*)?)(?::?(\d{2}(?:[.,]\d*)?))?(?::?(\d{2}(?:[.,]\d*)?))?$/;
-const timezoneRegex = /^([+-])(\d{2})(?::?(\d{2}))?$/;
-
-function splitDateString(dateString) {
- const dateStrings = {};
- const array = dateString.split(patterns.dateTimeDelimiter);
- let timeString;
-
- // The regex match should only return at maximum two array elements.
- // [date], [time], or [date, time].
- if (array.length > 2) {
- return dateStrings;
- }
-
- if (/:/.test(array[0])) {
- timeString = array[0];
- } else {
- dateStrings.date = array[0];
- timeString = array[1];
- if (patterns.timeZoneDelimiter.test(dateStrings.date)) {
- dateStrings.date = dateString.split(patterns.timeZoneDelimiter)[0];
- timeString = dateString.substr(
- dateStrings.date.length,
- dateString.length,
- );
- }
- }
-
- if (timeString) {
- const token = patterns.timezone.exec(timeString);
- if (token) {
- dateStrings.time = timeString.replace(token[1], "");
- dateStrings.timezone = token[1];
- } else {
- dateStrings.time = timeString;
- }
- }
-
- return dateStrings;
-}
-
-function parseYear(dateString, additionalDigits) {
- const regex = new RegExp(
- "^(?:(\\d{4}|[+-]\\d{" +
- (4 + additionalDigits) +
- "})|(\\d{2}|[+-]\\d{" +
- (2 + additionalDigits) +
- "})$)",
- );
-
- const captures = dateString.match(regex);
- // Invalid ISO-formatted year
- if (!captures) return { year: NaN, restDateString: "" };
-
- const year = captures[1] ? parseInt(captures[1]) : null;
- const century = captures[2] ? parseInt(captures[2]) : null;
-
- // either year or century is null, not both
- return {
- year: century === null ? year : century * 100,
- restDateString: dateString.slice((captures[1] || captures[2]).length),
- };
-}
-
-function parseDate(dateString, year) {
- // Invalid ISO-formatted year
- if (year === null) return new Date(NaN);
-
- const captures = dateString.match(dateRegex);
- // Invalid ISO-formatted string
- if (!captures) return new Date(NaN);
-
- const isWeekDate = !!captures[4];
- const dayOfYear = parseDateUnit(captures[1]);
- const month = parseDateUnit(captures[2]) - 1;
- const day = parseDateUnit(captures[3]);
- const week = parseDateUnit(captures[4]);
- const dayOfWeek = parseDateUnit(captures[5]) - 1;
-
- if (isWeekDate) {
- if (!validateWeekDate(year, week, dayOfWeek)) {
- return new Date(NaN);
- }
- return dayOfISOWeekYear(year, week, dayOfWeek);
- } else {
- const date = new Date(0);
- if (
- !validateDate(year, month, day) ||
- !validateDayOfYearDate(year, dayOfYear)
- ) {
- return new Date(NaN);
- }
- date.setUTCFullYear(year, month, Math.max(dayOfYear, day));
- return date;
- }
-}
-
-function parseDateUnit(value) {
- return value ? parseInt(value) : 1;
-}
-
-function parseTime(timeString) {
- const captures = timeString.match(timeRegex);
- if (!captures) return NaN; // Invalid ISO-formatted time
-
- const hours = parseTimeUnit(captures[1]);
- const minutes = parseTimeUnit(captures[2]);
- const seconds = parseTimeUnit(captures[3]);
-
- if (!validateTime(hours, minutes, seconds)) {
- return NaN;
- }
-
- return (
- hours * _index.millisecondsInHour +
- minutes * _index.millisecondsInMinute +
- seconds * 1000
- );
-}
-
-function parseTimeUnit(value) {
- return (value && parseFloat(value.replace(",", "."))) || 0;
-}
-
-function parseTimezone(timezoneString) {
- if (timezoneString === "Z") return 0;
-
- const captures = timezoneString.match(timezoneRegex);
- if (!captures) return 0;
-
- const sign = captures[1] === "+" ? -1 : 1;
- const hours = parseInt(captures[2]);
- const minutes = (captures[3] && parseInt(captures[3])) || 0;
-
- if (!validateTimezone(hours, minutes)) {
- return NaN;
- }
-
- return (
- sign *
- (hours * _index.millisecondsInHour + minutes * _index.millisecondsInMinute)
- );
-}
-
-function dayOfISOWeekYear(isoWeekYear, week, day) {
- const date = new Date(0);
- date.setUTCFullYear(isoWeekYear, 0, 4);
- const fourthOfJanuaryDay = date.getUTCDay() || 7;
- const diff = (week - 1) * 7 + day + 1 - fourthOfJanuaryDay;
- date.setUTCDate(date.getUTCDate() + diff);
- return date;
-}
-
-// Validation functions
-
-// February is null to handle the leap year (using ||)
-const daysInMonths = [31, null, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
-
-function isLeapYearIndex(year) {
- return year % 400 === 0 || (year % 4 === 0 && year % 100 !== 0);
-}
-
-function validateDate(year, month, date) {
- return (
- month >= 0 &&
- month <= 11 &&
- date >= 1 &&
- date <= (daysInMonths[month] || (isLeapYearIndex(year) ? 29 : 28))
- );
-}
-
-function validateDayOfYearDate(year, dayOfYear) {
- return dayOfYear >= 1 && dayOfYear <= (isLeapYearIndex(year) ? 366 : 365);
-}
-
-function validateWeekDate(_year, week, day) {
- return week >= 1 && week <= 53 && day >= 0 && day <= 6;
-}
-
-function validateTime(hours, minutes, seconds) {
- if (hours === 24) {
- return minutes === 0 && seconds === 0;
- }
-
- return (
- seconds >= 0 &&
- seconds < 60 &&
- minutes >= 0 &&
- minutes < 60 &&
- hours >= 0 &&
- hours < 25
- );
-}
-
-function validateTimezone(_hours, minutes) {
- return minutes >= 0 && minutes <= 59;
-}
-
-
-/***/ }),
-
-/***/ 50135:
-/***/ ((__unused_webpack_module, exports) => {
-
-"use strict";
-
-exports.parseJSON = parseJSON; /**
- * @name parseJSON
- * @category Common Helpers
- * @summary Parse a JSON date string
- *
- * @description
- * Converts a complete ISO date string in UTC time, the typical format for transmitting
- * a date in JSON, to a JavaScript `Date` instance.
- *
- * This is a minimal implementation for converting dates retrieved from a JSON API to
- * a `Date` instance which can be used with other functions in the `date-fns` library.
- * The following formats are supported:
- *
- * - `2000-03-15T05:20:10.123Z`: The output of `.toISOString()` and `JSON.stringify(new Date())`
- * - `2000-03-15T05:20:10Z`: Without milliseconds
- * - `2000-03-15T05:20:10+00:00`: With a zero offset, the default JSON encoded format in some other languages
- * - `2000-03-15T05:20:10+05:45`: With a positive or negative offset, the default JSON encoded format in some other languages
- * - `2000-03-15T05:20:10+0000`: With a zero offset without a colon
- * - `2000-03-15T05:20:10`: Without a trailing 'Z' symbol
- * - `2000-03-15T05:20:10.1234567`: Up to 7 digits in milliseconds field. Only first 3 are taken into account since JS does not allow fractional milliseconds
- * - `2000-03-15 05:20:10`: With a space instead of a 'T' separator for APIs returning a SQL date without reformatting
- *
- * For convenience and ease of use these other input types are also supported
- * via [toDate](https://date-fns.org/docs/toDate):
- *
- * - A `Date` instance will be cloned
- * - A `number` will be treated as a timestamp
- *
- * Any other input type or invalid date strings will return an `Invalid Date`.
- *
- * @param dateStr - A fully formed ISO8601 date string to convert
- *
- * @returns The parsed date in the local time zone
- */
-function parseJSON(dateStr) {
- const parts = dateStr.match(
- /(\d{4})-(\d{2})-(\d{2})[T ](\d{2}):(\d{2}):(\d{2})(?:\.(\d{0,7}))?(?:Z|(.)(\d{2}):?(\d{2})?)?/,
- );
- if (parts) {
- // Group 8 matches the sign
- return new Date(
- Date.UTC(
- +parts[1],
- +parts[2] - 1,
- +parts[3],
- +parts[4] - (+parts[9] || 0) * (parts[8] == "-" ? -1 : 1),
- +parts[5] - (+parts[10] || 0) * (parts[8] == "-" ? -1 : 1),
- +parts[6],
- +((parts[7] || "0") + "00").substring(0, 3),
- ),
- );
- }
- return new Date(NaN);
-}
-
-
/***/ }),
/***/ 456:
diff --git a/src/action/decorate/summary.ts b/src/action/decorate/summary.ts
index 95ba7181..a2e27a6e 100644
--- a/src/action/decorate/summary.ts
+++ b/src/action/decorate/summary.ts
@@ -54,6 +54,7 @@ export function createSummaryBody(analysisResult: AnalysisResult): string {
summary.addRaw(createFilesSummary(projectResult.analyzedFiles));
}
});
+ summary.addRaw(`${githubConfig.getIdentifier()}`);
logger.info('Created summary.');
@@ -88,6 +89,7 @@ export function createErrorSummaryBody(errorList: string[], warningList: string[
summary.addRaw(`:warning: ${warning}${EOL}${EOL}`);
}
}
+ summary.addRaw(`${githubConfig.getIdentifier()}`);
logger.info('Created summary.');
return summary.stringify();
@@ -105,6 +107,7 @@ export function createNothingAnalyzedSummaryBody(message: string): string {
summary.addHeading(generateStatusMarkdown(Status.PASSED, true), 3);
summary.addRaw(message);
+ summary.addRaw(`${githubConfig.getIdentifier()}`);
logger.info('Created summary.');
return summary.stringify();
@@ -374,6 +377,7 @@ function findAnnotationInList(list: ExtendedAnnotation[], annotation: ExtendedAn
* @param unpostableReviewComments Review comments that could not be posted.
* @returns Summary of all the review comments that could not be posted.
*/
+// Exported for testing
export function createUnpostableAnnotationsDetails(unpostableReviewComments: ExtendedAnnotation[]): string {
const label = 'Quality gate failures that cannot be annotated in Files Changed';
let body = '';
diff --git a/src/configuration/github.ts b/src/configuration/github.ts
index 2c39449c..1805d632 100644
--- a/src/configuration/github.ts
+++ b/src/configuration/github.ts
@@ -11,9 +11,12 @@ export class GithubConfig {
readonly event: GithubEvent;
readonly job: string;
readonly action: string;
- readonly id: string;
+ readonly workflow: string;
+ readonly runNumber: number;
+ readonly runAttempt: number;
readonly pullRequestNumber: number | undefined;
readonly debugger: boolean;
+ readonly id: string;
constructor() {
this.apiUrl = context.apiUrl;
@@ -21,8 +24,13 @@ export class GithubConfig {
this.reponame = context.repo.repo;
this.commitSha = context.sha;
this.event = this.getGithubEvent();
- this.job = context.job;
+ this.job = context.job.replace(/\s+/g, '-').replace(/_+/g, '-');
this.action = context.action.replace('__tiobe_', '');
+ this.workflow = context.workflow.replace(/\s+/g, '-').replace(/_+/g, '-');
+ this.runNumber = context.runNumber;
+ this.runAttempt = parseInt(process.env.GITHUB_RUN_ATTEMPT ?? '0', 10);
+ this.pullRequestNumber = this.getPullRequestNumber();
+ this.debugger = isDebug();
/**
* Construct the id to use for storing tmpdirs. The action name will
@@ -34,10 +42,7 @@ export class GithubConfig {
* include a suffix that consists of the sequence number preceded by an underscore.
* https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables
*/
- const runAttempt = process.env.GITHUB_RUN_ATTEMPT ?? '0';
- this.id = `${context.runId.toString()}_${runAttempt}_${this.job}_${this.action}`;
- this.pullRequestNumber = this.getPullRequestNumber();
- this.debugger = isDebug();
+ this.id = `${context.runId.toString()}_${this.runAttempt.toString()}_${this.job}_${this.action}`;
this.removeWarningListener();
}
@@ -71,6 +76,10 @@ export class GithubConfig {
}
}
+ getIdentifier(): string {
+ return [this.workflow, this.job, this.runNumber, this.runAttempt].join('_');
+ }
+
removeWarningListener(): void {
process.removeAllListeners('warning');
process.on('warning', warning => {
diff --git a/src/github/comments.ts b/src/github/comments.ts
index 41320a27..a716cbc7 100644
--- a/src/github/comments.ts
+++ b/src/github/comments.ts
@@ -59,7 +59,7 @@ export async function postComment(body: string): Promise {
export async function deletePreviousComments(comments: Comment[]): Promise {
logger.header('Deleting comments of previous runs.');
for (const comment of comments) {
- if (commentIncludesTicsTitle(comment.body)) {
+ if (shouldCommentBeDeleted(comment.body)) {
try {
const params = {
owner: githubConfig.owner,
@@ -76,16 +76,30 @@ export async function deletePreviousComments(comments: Comment[]): Promise
logger.info('Deleted review comments of previous runs.');
}
-function commentIncludesTicsTitle(body?: string): boolean {
- const titles = ['TICS Quality Gate
', '## TICS Quality Gate', '## TICS Analysis'];
-
+function shouldCommentBeDeleted(body?: string): boolean {
if (!body) return false;
+ const titles = ['TICS Quality Gate
', '## TICS Quality Gate', '## TICS Analysis'];
+
let includesTitle = false;
- titles.forEach(title => {
- if (body.startsWith(title)) includesTitle = true;
- });
+ for (const title of titles) {
+ if (body.startsWith(title)) {
+ includesTitle = true;
+ }
+ }
+
+ if (includesTitle) {
+ return containsIdentifier(body);
+ }
+
+ return false;
+}
+
+function containsIdentifier(body: string): boolean {
+ const index = body.indexOf(`${githubConfig.workflow}_${githubConfig.job}`);
+
+ if (index === -1) return true;
- return includesTitle;
+ return body.substring(index, body.length - 4) !== githubConfig.getIdentifier();
}
diff --git a/test/.setup/mock.ts b/test/.setup/mock.ts
index 482ea806..60b9b501 100644
--- a/test/.setup/mock.ts
+++ b/test/.setup/mock.ts
@@ -13,6 +13,10 @@ export const githubConfigMock: {
id: string;
pullRequestNumber: number | undefined;
debugger: boolean;
+ workflow: string;
+ runNumber: number;
+ runAttempt: number;
+ getIdentifier(): string;
} = {
apiUrl: 'github.com/api/v1/',
owner: 'tester',
@@ -23,7 +27,13 @@ export const githubConfigMock: {
action: 'tics-github-action',
id: '123_TICS_1_tics-github-action',
pullRequestNumber: 1,
- debugger: false
+ debugger: false,
+ workflow: 'tics-client',
+ runNumber: 1,
+ runAttempt: 2,
+ getIdentifier(): string {
+ return [this.workflow, this.job, this.runNumber, this.runAttempt].join('_');
+ }
};
export const ticsConfigMock = {
@@ -121,6 +131,7 @@ export const contextMock: {
job: string;
runId: number;
runNumber: number;
+ workflow: string;
payload: {
pull_request:
| {
@@ -140,6 +151,7 @@ export const contextMock: {
job: 'TICS',
runId: 123,
runNumber: 1,
+ workflow: 'tics_client',
payload: {
pull_request: {
number: 1
diff --git a/test/integration/configuration.test.ts b/test/integration/configuration.test.ts
index 07b21e51..7a62fc87 100644
--- a/test/integration/configuration.test.ts
+++ b/test/integration/configuration.test.ts
@@ -28,6 +28,8 @@ describe('pullRequestNumber', () => {
eventName: 'pull_request',
runId: 1,
runNumber: 1,
+ job: 'TICS',
+ workflow: 'tics_client',
repo: {
owner: 'owner',
repo: 'repo'
@@ -53,6 +55,8 @@ describe('pullRequestNumber', () => {
eventName: 'pull_request',
runId: 1,
runNumber: 1,
+ job: 'TICS',
+ workflow: 'tics_client',
repo: {
owner: 'owner',
repo: 'repo'
@@ -80,6 +84,8 @@ describe('pullRequestNumber', () => {
eventName: 'pull_request',
runId: 1,
runNumber: 1,
+ job: 'TICS',
+ workflow: 'tics_client',
repo: {
owner: 'owner',
repo: 'repo'
diff --git a/test/integration/httpclient.test.ts b/test/integration/httpclient.test.ts
index f329337a..96d7b733 100644
--- a/test/integration/httpclient.test.ts
+++ b/test/integration/httpclient.test.ts
@@ -10,6 +10,8 @@ process.env['http_proxy'] = proxyUrl;
// set required inputs
process.env.GITHUB_REPOSITORY = 'owner/repo';
process.env.GITHUB_ACTION = '_tics-github-action';
+process.env.GITHUB_JOB = 'tics_client';
+process.env.GITHUB_WORKFLOW = 'tics client';
process.env.INPUT_GITHUBTOKEN = 'token';
process.env.INPUT_MODE = 'client';
process.env.INPUT_PROJECTNAME = 'tics-github-action';
diff --git a/test/integration/octokit.test.ts b/test/integration/octokit.test.ts
index 0f850a67..0b9b8a8f 100644
--- a/test/integration/octokit.test.ts
+++ b/test/integration/octokit.test.ts
@@ -13,6 +13,8 @@ process.env['http_proxy'] = proxyUrl;
process.env.GITHUB_REPOSITORY = 'owner/repo';
process.env.GITHUB_API_URL = 'https://api.github.com';
process.env.GITHUB_ACTION = '_tics-github-action';
+process.env.GITHUB_JOB = 'tics_client';
+process.env.GITHUB_WORKFLOW = 'tics client';
process.env.INPUT_MODE = 'client';
process.env.INPUT_PROJECTNAME = 'tics-github-action';
process.env.INPUT_VIEWERURL = 'http://localhost/tiobeweb/TICS/api/cfg?name=default';
diff --git a/test/unit/action/decorate/summary.test.ts b/test/unit/action/decorate/summary.test.ts
index d5440bc8..a449ab31 100644
--- a/test/unit/action/decorate/summary.test.ts
+++ b/test/unit/action/decorate/summary.test.ts
@@ -145,7 +145,7 @@ describe('createErrorSummary', () => {
describe('createNothingAnalyzedSummaryBody', () => {
test('Should return summary with the message given', async () => {
const body = createNothingAnalyzedSummaryBody('message');
- expect(body).toEqual('TICS Quality Gate
\n:heavy_check_mark: Passed
\nmessage');
+ expect(body).toEqual('TICS Quality Gate
\n:heavy_check_mark: Passed
\nmessagetics-client_TICS_1_2');
});
});
From 3360c0b35c75cccd9f35e9a07b0e4f5d80096c11 Mon Sep 17 00:00:00 2001
From: janssen <118828444+janssen-tiobe@users.noreply.github.com>
Date: Wed, 4 Dec 2024 16:07:45 +0100
Subject: [PATCH 02/11] #34049: Created tests, fixed check when to delete a
comment
---
dist/index.js | 31 ++++++++++++---
src/github/comments.ts | 35 ++++++++++++++---
test/unit/github/comments.test.ts | 63 ++++++++++++++++++++++++++-----
3 files changed, 109 insertions(+), 20 deletions(-)
diff --git a/dist/index.js b/dist/index.js
index bd942abd..ae1706f1 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -1661,15 +1661,36 @@ function shouldCommentBeDeleted(body) {
}
}
if (includesTitle) {
- return containsIdentifier(body);
+ return isWorkflowAndJobInAnotherRun(body);
}
return false;
}
-function containsIdentifier(body) {
- const index = body.indexOf(`${config_1.githubConfig.workflow}_${config_1.githubConfig.job}`);
- if (index === -1)
+function isWorkflowAndJobInAnotherRun(body) {
+ const regex = /([^\s]+)<\/i>/g;
+ let identifier = '';
+ // Get the last match of the tag.
+ let match = null;
+ while ((match = regex.exec(body))) {
+ if (match[1] !== '') {
+ identifier = match[1];
+ }
+ }
+ // If no identifier is found, the comment is
+ // of the old format and should be replaced.
+ if (identifier === '')
return true;
- return body.substring(index, body.length - 4) !== config_1.githubConfig.getIdentifier();
+ const split = identifier.split('_');
+ // If the identifier does not match the correct format, do not replace.
+ if (split.length !== 4) {
+ logger_1.logger.debug(`Identifier is not of the correct format: ${identifier}`);
+ return false;
+ }
+ // If the workflow or job are different, do not replace.
+ if (split[0] !== config_1.githubConfig.workflow || split[1] !== config_1.githubConfig.job) {
+ return false;
+ }
+ // Only replace if the run number or run attempt are different.
+ return parseInt(split[2], 10) !== config_1.githubConfig.runNumber || parseInt(split[3], 10) !== config_1.githubConfig.runAttempt;
}
diff --git a/src/github/comments.ts b/src/github/comments.ts
index a716cbc7..62e0dd0a 100644
--- a/src/github/comments.ts
+++ b/src/github/comments.ts
@@ -90,16 +90,41 @@ function shouldCommentBeDeleted(body?: string): boolean {
}
if (includesTitle) {
- return containsIdentifier(body);
+ return isWorkflowAndJobInAnotherRun(body);
}
return false;
}
-function containsIdentifier(body: string): boolean {
- const index = body.indexOf(`${githubConfig.workflow}_${githubConfig.job}`);
+function isWorkflowAndJobInAnotherRun(body: string): boolean {
+ const regex = /([^\s]+)<\/i>/g;
- if (index === -1) return true;
+ let identifier = '';
+ // Get the last match of the tag.
+ let match: RegExpExecArray | null = null;
+ while ((match = regex.exec(body))) {
+ if (match[1] !== '') {
+ identifier = match[1];
+ }
+ }
+
+ // If no identifier is found, the comment is
+ // of the old format and should be replaced.
+ if (identifier === '') return true;
+
+ const split = identifier.split('_');
+
+ // If the identifier does not match the correct format, do not replace.
+ if (split.length !== 4) {
+ logger.debug(`Identifier is not of the correct format: ${identifier}`);
+ return false;
+ }
+
+ // If the workflow or job are different, do not replace.
+ if (split[0] !== githubConfig.workflow || split[1] !== githubConfig.job) {
+ return false;
+ }
- return body.substring(index, body.length - 4) !== githubConfig.getIdentifier();
+ // Only replace if the run number or run attempt are different.
+ return parseInt(split[2], 10) !== githubConfig.runNumber || parseInt(split[3], 10) !== githubConfig.runAttempt;
}
diff --git a/test/unit/github/comments.test.ts b/test/unit/github/comments.test.ts
index 5c614d67..dc95b274 100644
--- a/test/unit/github/comments.test.ts
+++ b/test/unit/github/comments.test.ts
@@ -130,7 +130,7 @@ describe('deletePreviousComments', () => {
});
test('Should call deleteComment with values', async () => {
- deletePreviousComments([commentWithBody]);
+ await deletePreviousComments([commentWithBody]);
const calledWith = {
owner: githubConfig.owner,
repo: githubConfig.reponame,
@@ -139,11 +139,41 @@ describe('deletePreviousComments', () => {
expect(deleteCommentSpy).toHaveBeenCalledWith(calledWith);
});
- test('Should call deleteComment with values', async () => {
+ test('Should not call deleteComment if body is not TICS', async () => {
await deletePreviousComments([commentWithoutBody]);
expect(deleteCommentSpy).toHaveBeenCalledTimes(0);
});
+ test('Should call deleteComment if identifier workflow and job match', async () => {
+ await deletePreviousComments([commentWithIdentifierSameJob]);
+ const calledWith = {
+ owner: githubConfig.owner,
+ repo: githubConfig.reponame,
+ comment_id: 0
+ };
+ expect(deleteCommentSpy).toHaveBeenCalledWith(calledWith);
+ });
+
+ test('Should not call deleteComment if identifier workflow and job match, but they are in the same run', async () => {
+ await deletePreviousComments([commentWithIdentifierSameJobAndRun]);
+ expect(deleteCommentSpy).toHaveBeenCalledTimes(0);
+ });
+
+ test('Should not call deleteComment if identifier workflow and job do not match', async () => {
+ await deletePreviousComments([commentWithIdentifierOtherJob]);
+ expect(deleteCommentSpy).toHaveBeenCalledTimes(0);
+ });
+
+ test('Should not call deleteComment if identifier is of the wrong format', async () => {
+ const debugSpy = jest.spyOn(logger, 'debug');
+
+ await deletePreviousComments([commentWithIdentifierWrongFormat]);
+
+ expect(deleteCommentSpy).toHaveBeenCalledTimes(0);
+ expect(debugSpy).toHaveBeenCalledTimes(1);
+ expect(debugSpy).toHaveBeenCalledWith('Identifier is not of the correct format: tics-client_OTHER_1');
+ });
+
test('Should post a notice when deleteComment throws', async () => {
deleteCommentSpy.mockRejectedValue(Error());
const noticeSpy = jest.spyOn(logger, 'notice');
@@ -167,13 +197,26 @@ const commentWithBody: Comment = {
};
const commentWithoutBody: Comment = {
- url: '',
- html_url: '',
- issue_url: '',
- id: 0,
- node_id: '',
- user: null,
- created_at: '',
- updated_at: '',
+ ...commentWithBody,
body: undefined
};
+
+const commentWithIdentifierSameJob: Comment = {
+ ...commentWithBody,
+ body: 'TICS Quality Gate
This distractsMessage Heretics-client_TICS_1_1'
+};
+
+const commentWithIdentifierSameJobAndRun: Comment = {
+ ...commentWithBody,
+ body: 'TICS Quality Gate
Message Heretics-client_TICS_1_2'
+};
+
+const commentWithIdentifierOtherJob: Comment = {
+ ...commentWithBody,
+ body: 'TICS Quality Gate
Message Heretics-client_OTHER_1_1'
+};
+
+const commentWithIdentifierWrongFormat: Comment = {
+ ...commentWithBody,
+ body: 'TICS Quality Gate
Message Heretics-client_OTHER_1'
+};
From 21bd5f3267529ac222b8c2fd1b0216723b7a3435 Mon Sep 17 00:00:00 2001
From: janssen <118828444+janssen-tiobe@users.noreply.github.com>
Date: Wed, 4 Dec 2024 17:40:39 +0100
Subject: [PATCH 03/11] #34049: Using a comment instead of shown text for
identifier
Also fixed comments of review
---
dist/index.js | 14 +++++++-------
src/action/decorate/summary.ts | 6 +++---
src/configuration/github.ts | 6 +++---
src/github/comments.ts | 2 +-
test/.setup/mock.ts | 4 ++--
test/unit/action/decorate/summary.test.ts | 2 +-
test/unit/github/comments.test.ts | 8 ++++----
7 files changed, 21 insertions(+), 21 deletions(-)
diff --git a/dist/index.js b/dist/index.js
index ae1706f1..719f7439 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -230,7 +230,7 @@ function createSummaryBody(analysisResult) {
core_1.summary.addRaw(createFilesSummary(projectResult.analyzedFiles));
}
});
- core_1.summary.addRaw(`${config_1.githubConfig.getIdentifier()}`);
+ core_1.summary.addRaw(``);
logger_1.logger.info('Created summary.');
return core_1.summary.stringify();
}
@@ -257,7 +257,7 @@ function createErrorSummaryBody(errorList, warningList) {
core_1.summary.addRaw(`:warning: ${warning}${os_1.EOL}${os_1.EOL}`);
}
}
- core_1.summary.addRaw(`${config_1.githubConfig.getIdentifier()}`);
+ core_1.summary.addRaw(``);
logger_1.logger.info('Created summary.');
return core_1.summary.stringify();
}
@@ -271,7 +271,7 @@ function createNothingAnalyzedSummaryBody(message) {
core_1.summary.addHeading('TICS Quality Gate');
core_1.summary.addHeading((0, markdown_1.generateStatusMarkdown)(enums_1.Status.PASSED, true), 3);
core_1.summary.addRaw(message);
- core_1.summary.addRaw(`${config_1.githubConfig.getIdentifier()}`);
+ core_1.summary.addRaw(``);
logger_1.logger.info('Created summary.');
return core_1.summary.stringify();
}
@@ -1034,9 +1034,9 @@ class GithubConfig {
this.reponame = github_1.context.repo.repo;
this.commitSha = github_1.context.sha;
this.event = this.getGithubEvent();
- this.job = github_1.context.job.replace(/\s+/g, '-').replace(/_+/g, '-');
+ this.job = github_1.context.job.replace(/[\s|_]+/g, '-');
this.action = github_1.context.action.replace('__tiobe_', '');
- this.workflow = github_1.context.workflow.replace(/\s+/g, '-').replace(/_+/g, '-');
+ this.workflow = github_1.context.workflow.replace(/[\s|_]+/g, '-');
this.runNumber = github_1.context.runNumber;
this.runAttempt = parseInt(process.env.GITHUB_RUN_ATTEMPT ?? '0', 10);
this.pullRequestNumber = this.getPullRequestNumber();
@@ -1083,7 +1083,7 @@ class GithubConfig {
return github_event_1.GithubEvent.PUSH;
}
}
- getIdentifier() {
+ getCommentIdentifier() {
return [this.workflow, this.job, this.runNumber, this.runAttempt].join('_');
}
removeWarningListener() {
@@ -1666,7 +1666,7 @@ function shouldCommentBeDeleted(body) {
return false;
}
function isWorkflowAndJobInAnotherRun(body) {
- const regex = /([^\s]+)<\/i>/g;
+ const regex = //g;
let identifier = '';
// Get the last match of the tag.
let match = null;
diff --git a/src/action/decorate/summary.ts b/src/action/decorate/summary.ts
index a2e27a6e..e3de689e 100644
--- a/src/action/decorate/summary.ts
+++ b/src/action/decorate/summary.ts
@@ -54,7 +54,7 @@ export function createSummaryBody(analysisResult: AnalysisResult): string {
summary.addRaw(createFilesSummary(projectResult.analyzedFiles));
}
});
- summary.addRaw(`${githubConfig.getIdentifier()}`);
+ summary.addRaw(``);
logger.info('Created summary.');
@@ -89,7 +89,7 @@ export function createErrorSummaryBody(errorList: string[], warningList: string[
summary.addRaw(`:warning: ${warning}${EOL}${EOL}`);
}
}
- summary.addRaw(`${githubConfig.getIdentifier()}`);
+ summary.addRaw(``);
logger.info('Created summary.');
return summary.stringify();
@@ -107,7 +107,7 @@ export function createNothingAnalyzedSummaryBody(message: string): string {
summary.addHeading(generateStatusMarkdown(Status.PASSED, true), 3);
summary.addRaw(message);
- summary.addRaw(`${githubConfig.getIdentifier()}`);
+ summary.addRaw(``);
logger.info('Created summary.');
return summary.stringify();
diff --git a/src/configuration/github.ts b/src/configuration/github.ts
index 1805d632..f538a0e6 100644
--- a/src/configuration/github.ts
+++ b/src/configuration/github.ts
@@ -24,9 +24,9 @@ export class GithubConfig {
this.reponame = context.repo.repo;
this.commitSha = context.sha;
this.event = this.getGithubEvent();
- this.job = context.job.replace(/\s+/g, '-').replace(/_+/g, '-');
+ this.job = context.job.replace(/[\s|_]+/g, '-');
this.action = context.action.replace('__tiobe_', '');
- this.workflow = context.workflow.replace(/\s+/g, '-').replace(/_+/g, '-');
+ this.workflow = context.workflow.replace(/[\s|_]+/g, '-');
this.runNumber = context.runNumber;
this.runAttempt = parseInt(process.env.GITHUB_RUN_ATTEMPT ?? '0', 10);
this.pullRequestNumber = this.getPullRequestNumber();
@@ -76,7 +76,7 @@ export class GithubConfig {
}
}
- getIdentifier(): string {
+ getCommentIdentifier(): string {
return [this.workflow, this.job, this.runNumber, this.runAttempt].join('_');
}
diff --git a/src/github/comments.ts b/src/github/comments.ts
index 62e0dd0a..c05a8c81 100644
--- a/src/github/comments.ts
+++ b/src/github/comments.ts
@@ -97,7 +97,7 @@ function shouldCommentBeDeleted(body?: string): boolean {
}
function isWorkflowAndJobInAnotherRun(body: string): boolean {
- const regex = /([^\s]+)<\/i>/g;
+ const regex = //g;
let identifier = '';
// Get the last match of the tag.
diff --git a/test/.setup/mock.ts b/test/.setup/mock.ts
index 60b9b501..d1d7c830 100644
--- a/test/.setup/mock.ts
+++ b/test/.setup/mock.ts
@@ -16,7 +16,7 @@ export const githubConfigMock: {
workflow: string;
runNumber: number;
runAttempt: number;
- getIdentifier(): string;
+ getCommentIdentifier(): string;
} = {
apiUrl: 'github.com/api/v1/',
owner: 'tester',
@@ -31,7 +31,7 @@ export const githubConfigMock: {
workflow: 'tics-client',
runNumber: 1,
runAttempt: 2,
- getIdentifier(): string {
+ getCommentIdentifier(): string {
return [this.workflow, this.job, this.runNumber, this.runAttempt].join('_');
}
};
diff --git a/test/unit/action/decorate/summary.test.ts b/test/unit/action/decorate/summary.test.ts
index a449ab31..7af2dcb9 100644
--- a/test/unit/action/decorate/summary.test.ts
+++ b/test/unit/action/decorate/summary.test.ts
@@ -145,7 +145,7 @@ describe('createErrorSummary', () => {
describe('createNothingAnalyzedSummaryBody', () => {
test('Should return summary with the message given', async () => {
const body = createNothingAnalyzedSummaryBody('message');
- expect(body).toEqual('TICS Quality Gate
\n:heavy_check_mark: Passed
\nmessagetics-client_TICS_1_2');
+ expect(body).toEqual('TICS Quality Gate
\n:heavy_check_mark: Passed
\nmessage');
});
});
diff --git a/test/unit/github/comments.test.ts b/test/unit/github/comments.test.ts
index dc95b274..5f5f42c3 100644
--- a/test/unit/github/comments.test.ts
+++ b/test/unit/github/comments.test.ts
@@ -203,20 +203,20 @@ const commentWithoutBody: Comment = {
const commentWithIdentifierSameJob: Comment = {
...commentWithBody,
- body: 'TICS Quality Gate
This distractsMessage Heretics-client_TICS_1_1'
+ body: 'TICS Quality Gate
Message Here'
};
const commentWithIdentifierSameJobAndRun: Comment = {
...commentWithBody,
- body: 'TICS Quality Gate
Message Heretics-client_TICS_1_2'
+ body: 'TICS Quality Gate
Message Here'
};
const commentWithIdentifierOtherJob: Comment = {
...commentWithBody,
- body: 'TICS Quality Gate
Message Heretics-client_OTHER_1_1'
+ body: 'TICS Quality Gate
Message Here'
};
const commentWithIdentifierWrongFormat: Comment = {
...commentWithBody,
- body: 'TICS Quality Gate
Message Heretics-client_OTHER_1'
+ body: 'TICS Quality Gate
Message Here'
};
From eb7ae26c84dd33202354daa0c37db85be3b56f9c Mon Sep 17 00:00:00 2001
From: janssen <118828444+janssen-tiobe@users.noreply.github.com>
Date: Thu, 5 Dec 2024 12:56:10 +0100
Subject: [PATCH 04/11] #34049: Added some more tests
---
test/unit/configuration/github.test.ts | 23 ++++++++
test/unit/github/comments.test.ts | 12 +++-
test/unit/helper/logger.test.ts | 76 +++++++++++++++++++-------
3 files changed, 89 insertions(+), 22 deletions(-)
diff --git a/test/unit/configuration/github.test.ts b/test/unit/configuration/github.test.ts
index b95e7895..6d4c7d8a 100644
--- a/test/unit/configuration/github.test.ts
+++ b/test/unit/configuration/github.test.ts
@@ -1,6 +1,7 @@
import * as core from '@actions/core';
import { GithubConfig } from '../../../src/configuration/github';
import { contextMock } from '../../.setup/mock';
+import { GithubEvent } from '../../../src/configuration/github-event';
describe('GitHub Configuration', () => {
let githubConfig: GithubConfig;
@@ -92,4 +93,26 @@ describe('GitHub Configuration', () => {
githubConfig = new GithubConfig();
githubConfig.removeWarningListener();
});
+
+ test('getCommentIdentifier', () => {
+ githubConfig = new GithubConfig();
+ expect(githubConfig.getCommentIdentifier()).toEqual('tics-client_TICS_1_1');
+ });
+
+ test('getGithubEvent', () => {
+ contextMock.eventName = 'undefined';
+ expect(new GithubConfig().event).toEqual(GithubEvent.PUSH);
+ contextMock.eventName = GithubEvent.PUSH.name;
+ expect(new GithubConfig().event).toEqual(GithubEvent.PUSH);
+ contextMock.eventName = GithubEvent.PULL_REQUEST.name;
+ expect(new GithubConfig().event).toEqual(GithubEvent.PULL_REQUEST);
+ contextMock.eventName = GithubEvent.PULL_REQUEST_TARGET.name;
+ expect(new GithubConfig().event).toEqual(GithubEvent.PULL_REQUEST_TARGET);
+ contextMock.eventName = GithubEvent.WORKFLOW_CALL.name;
+ expect(new GithubConfig().event).toEqual(GithubEvent.WORKFLOW_CALL);
+ contextMock.eventName = GithubEvent.WORKFLOW_DISPATCH.name;
+ expect(new GithubConfig().event).toEqual(GithubEvent.WORKFLOW_DISPATCH);
+ contextMock.eventName = GithubEvent.WORKFLOW_RUN.name;
+ expect(new GithubConfig().event).toEqual(GithubEvent.WORKFLOW_RUN);
+ });
});
diff --git a/test/unit/github/comments.test.ts b/test/unit/github/comments.test.ts
index 5f5f42c3..a0e25378 100644
--- a/test/unit/github/comments.test.ts
+++ b/test/unit/github/comments.test.ts
@@ -139,11 +139,16 @@ describe('deletePreviousComments', () => {
expect(deleteCommentSpy).toHaveBeenCalledWith(calledWith);
});
- test('Should not call deleteComment if body is not TICS', async () => {
+ test('Should not call deleteComment if body is undefined', async () => {
await deletePreviousComments([commentWithoutBody]);
expect(deleteCommentSpy).toHaveBeenCalledTimes(0);
});
+ test('Should not call deleteComment if body is not TICS', async () => {
+ await deletePreviousComments([commentWithoutTics]);
+ expect(deleteCommentSpy).toHaveBeenCalledTimes(0);
+ });
+
test('Should call deleteComment if identifier workflow and job match', async () => {
await deletePreviousComments([commentWithIdentifierSameJob]);
const calledWith = {
@@ -201,6 +206,11 @@ const commentWithoutBody: Comment = {
body: undefined
};
+const commentWithoutTics: Comment = {
+ ...commentWithBody,
+ body: 'Other action content'
+};
+
const commentWithIdentifierSameJob: Comment = {
...commentWithBody,
body: 'TICS Quality Gate
Message Here'
diff --git a/test/unit/helper/logger.test.ts b/test/unit/helper/logger.test.ts
index 0b4124ac..e007b077 100644
--- a/test/unit/helper/logger.test.ts
+++ b/test/unit/helper/logger.test.ts
@@ -1,27 +1,46 @@
import * as core from '@actions/core';
import { logger } from '../../../src/helper/logger';
+let infoSpy: jest.SpyInstance;
+let debugSpy: jest.SpyInstance;
+let noticeSpy: jest.SpyInstance;
+let errorSpy: jest.SpyInstance;
+let warningSpy: jest.SpyInstance;
+let setFailedSpy: jest.SpyInstance;
+
+beforeEach(() => {
+ infoSpy = jest.spyOn(core, 'info');
+ debugSpy = jest.spyOn(core, 'debug');
+ noticeSpy = jest.spyOn(core, 'notice');
+ errorSpy = jest.spyOn(core, 'error');
+ warningSpy = jest.spyOn(core, 'warning');
+ setFailedSpy = jest.spyOn(core, 'setFailed');
+});
+
+afterEach(() => {
+ jest.resetAllMocks();
+});
+
describe('info', () => {
test('Should call core.info on info', () => {
- const info = jest.spyOn(core, 'info');
const addNewline = jest.spyOn(logger, 'addNewline');
logger.info('string');
- expect(info).toHaveBeenCalledTimes(1);
- expect(info).toHaveBeenCalledWith('string');
+ expect(infoSpy).toHaveBeenCalledTimes(1);
+ expect(infoSpy).toHaveBeenCalledWith('string');
expect(addNewline).toHaveBeenCalledTimes(0);
expect(logger.called).toEqual('info');
});
test('Should call core.info on header', () => {
- const info = jest.spyOn(core, 'info');
const addNewline = jest.spyOn(logger, 'addNewline');
+ logger.info('error');
logger.header('string');
- expect(info).toHaveBeenCalledTimes(2); // once for header, once for newline
- expect(info).toHaveBeenCalledWith(expect.stringContaining('string'));
+ expect(infoSpy).toHaveBeenCalledTimes(2); // once for header, once for newline
+ expect(infoSpy).toHaveBeenCalledWith(expect.stringContaining('string'));
expect(addNewline).toHaveBeenCalledTimes(1);
expect(addNewline).toHaveBeenCalledWith('header');
expect(logger.called).toEqual('header');
@@ -30,14 +49,13 @@ describe('info', () => {
describe('debug', () => {
test('Should call core.debug on debug', () => {
- const debug = jest.spyOn(core, 'debug');
const addNewline = jest.spyOn(logger, 'addNewline');
logger.setSecretsFilter(['token']);
logger.debug('string token secret');
- expect(debug).toHaveBeenCalledTimes(1);
- expect(debug).toHaveBeenCalledWith('string token ***');
+ expect(debugSpy).toHaveBeenCalledTimes(1);
+ expect(debugSpy).toHaveBeenCalledWith('string token ***');
expect(addNewline).toHaveBeenCalledTimes(0);
expect(logger.called).toEqual('debug');
});
@@ -45,13 +63,12 @@ describe('debug', () => {
describe('notice', () => {
test('Should call core.notice on notice', () => {
- const debug = jest.spyOn(core, 'notice');
const addNewline = jest.spyOn(logger, 'addNewline');
logger.notice('string');
- expect(debug).toHaveBeenCalledTimes(1);
- expect(debug).toHaveBeenCalledWith('string', undefined);
+ expect(noticeSpy).toHaveBeenCalledTimes(1);
+ expect(noticeSpy).toHaveBeenCalledWith('string', undefined);
expect(addNewline).toHaveBeenCalledTimes(0);
expect(logger.called).toEqual('notice');
});
@@ -59,13 +76,12 @@ describe('notice', () => {
describe('warning', () => {
test('Should call core.warning on warning', () => {
- const debug = jest.spyOn(core, 'warning');
const addNewline = jest.spyOn(logger, 'addNewline');
logger.warning('string');
- expect(debug).toHaveBeenCalledTimes(1);
- expect(debug).toHaveBeenCalledWith('\u001b[33mstring', undefined);
+ expect(warningSpy).toHaveBeenCalledTimes(1);
+ expect(warningSpy).toHaveBeenCalledWith('\u001b[33mstring', undefined);
expect(addNewline).toHaveBeenCalledTimes(0);
expect(logger.called).toEqual('warning');
});
@@ -73,13 +89,12 @@ describe('warning', () => {
describe('error', () => {
test('Should call core.error on error', () => {
- const error = jest.spyOn(core, 'error');
const addNewline = jest.spyOn(logger, 'addNewline');
logger.error('error');
- expect(error).toHaveBeenCalledTimes(1);
- expect(error).toHaveBeenCalledWith(expect.stringContaining('error'), undefined);
+ expect(errorSpy).toHaveBeenCalledTimes(1);
+ expect(errorSpy).toHaveBeenCalledWith(expect.stringContaining('error'), undefined);
expect(addNewline).toHaveBeenCalledTimes(1);
expect(addNewline).toHaveBeenCalledWith('error');
expect(logger.called).toEqual('error');
@@ -88,15 +103,34 @@ describe('error', () => {
describe('setFailed', () => {
test('Should call core.setFailed on setFailed', () => {
- const setFailed = jest.spyOn(core, 'setFailed');
const addNewline = jest.spyOn(logger, 'addNewline');
logger.setFailed('error');
- expect(setFailed).toHaveBeenCalledTimes(1);
- expect(setFailed).toHaveBeenCalledWith(expect.stringContaining('error'));
+ expect(setFailedSpy).toHaveBeenCalledTimes(1);
+ expect(setFailedSpy).toHaveBeenCalledWith(expect.stringContaining('error'));
expect(addNewline).toHaveBeenCalledTimes(1);
expect(addNewline).toHaveBeenCalledWith('error');
expect(logger.called).toEqual('error');
});
});
+
+describe('maskOutput', () => {
+ test('Should filter out JAVA options', () => {
+ const message = 'Picked up JAVA_OPTIONS testing once';
+
+ logger.info(message);
+ logger.notice(message);
+ logger.debug(message);
+ logger.warning(message);
+ logger.error(message);
+ logger.setFailed(message);
+
+ expect(infoSpy).toHaveBeenCalledTimes(0);
+ expect(noticeSpy).toHaveBeenCalledTimes(0);
+ expect(debugSpy).toHaveBeenCalledTimes(0);
+ expect(warningSpy).toHaveBeenCalledTimes(0);
+ expect(errorSpy).toHaveBeenCalledTimes(0);
+ expect(setFailedSpy).toHaveBeenCalledTimes(0);
+ });
+});
From c3e9c627a1f41c52ecaac7df60a0b2b556793392 Mon Sep 17 00:00:00 2001
From: janssen <118828444+janssen-tiobe@users.noreply.github.com>
Date: Fri, 6 Dec 2024 14:49:04 +0100
Subject: [PATCH 05/11] #34049: Add step name to the summary
---
dist/index.js | 107 ++++++++++++++++++----
src/action/decorate/action.ts | 4 +-
src/action/decorate/markdown.ts | 16 ++++
src/action/decorate/summary.ts | 36 +++++---
src/analysis/client/process-analysis.ts | 6 +-
src/analysis/qserver.ts | 4 +-
src/configuration/github.ts | 4 +-
src/github/runs.ts | 32 +++++++
test/unit/action/decorate/action.test.ts | 4 +-
test/unit/action/decorate/summary.test.ts | 46 ++++++----
test/unit/analysis/qserver.test.ts | 2 +-
11 files changed, 196 insertions(+), 65 deletions(-)
create mode 100644 src/github/runs.ts
diff --git a/dist/index.js b/dist/index.js
index f4bb7249..db9ae634 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -47,10 +47,10 @@ const annotations_1 = __nccwpck_require__(31058);
async function decorateAction(analysisResult, analysis) {
let summaryBody;
if (analysisResult) {
- summaryBody = (0, summary_1.createSummaryBody)(analysisResult);
+ summaryBody = await (0, summary_1.createSummaryBody)(analysisResult);
}
else {
- summaryBody = (0, summary_1.createErrorSummaryBody)(analysis.errorList, analysis.warningList);
+ summaryBody = await (0, summary_1.createErrorSummaryBody)(analysis.errorList, analysis.warningList);
}
if (config_1.githubConfig.event.isPullRequest) {
await (0, pull_request_1.decoratePullRequest)(analysisResult?.passed ?? false, summaryBody);
@@ -71,6 +71,8 @@ async function decorateAction(analysisResult, analysis) {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.generateStatusMarkdown = generateStatusMarkdown;
exports.generateExpandableAreaMarkdown = generateExpandableAreaMarkdown;
+exports.generateItalic = generateItalic;
+exports.generateComment = generateComment;
const os_1 = __nccwpck_require__(22037);
const enums_1 = __nccwpck_require__(31655);
/**
@@ -101,6 +103,20 @@ function generateStatusMarkdown(status, hasSuffix = false) {
function generateExpandableAreaMarkdown(header, body) {
return `${header}
${os_1.EOL}${body} ${os_1.EOL}${os_1.EOL}`;
}
+/**
+ * Generates italic text for markdown.
+ * @param text The text to make italic.
+ */
+function generateItalic(text) {
+ return `${text}`;
+}
+/**
+ * Generates a hidden comment for markdown.
+ * @param comment The text of the comment.
+ */
+function generateComment(comment) {
+ return ``;
+}
/***/ }),
@@ -201,10 +217,10 @@ const logger_1 = __nccwpck_require__(26440);
const url_1 = __nccwpck_require__(76259);
const markdown_1 = __nccwpck_require__(60517);
const config_1 = __nccwpck_require__(86444);
-function createSummaryBody(analysisResult) {
+const runs_1 = __nccwpck_require__(50046);
+async function createSummaryBody(analysisResult) {
logger_1.logger.header('Creating summary.');
- core_1.summary.addHeading('TICS Quality Gate');
- core_1.summary.addHeading((0, markdown_1.generateStatusMarkdown)(getStatus(analysisResult.passed, analysisResult.passedWithWarning), true), 3);
+ setSummaryHeader(getStatus(analysisResult.passed, analysisResult.passedWithWarning));
analysisResult.projectResults.forEach(projectResult => {
if (projectResult.qualityGate) {
const failedOrWarnConditions = extractFailedOrWarningConditions(projectResult.qualityGate.gates);
@@ -230,7 +246,7 @@ function createSummaryBody(analysisResult) {
core_1.summary.addRaw(createFilesSummary(projectResult.analyzedFiles));
}
});
- core_1.summary.addRaw(``);
+ await setSummaryFooter();
logger_1.logger.info('Created summary.');
return core_1.summary.stringify();
}
@@ -240,10 +256,9 @@ function createSummaryBody(analysisResult) {
* @param warningList list containing all the warnings found in the TICS run.
* @returns string containing the error summary.
*/
-function createErrorSummaryBody(errorList, warningList) {
+async function createErrorSummaryBody(errorList, warningList) {
logger_1.logger.header('Creating summary.');
- core_1.summary.addHeading('TICS Quality Gate');
- core_1.summary.addHeading((0, markdown_1.generateStatusMarkdown)(enums_1.Status.FAILED, true), 3);
+ setSummaryHeader(enums_1.Status.FAILED);
if (errorList.length > 0) {
core_1.summary.addHeading('The following errors have occurred during analysis:', 2);
for (const error of errorList) {
@@ -257,7 +272,7 @@ function createErrorSummaryBody(errorList, warningList) {
core_1.summary.addRaw(`:warning: ${warning}${os_1.EOL}${os_1.EOL}`);
}
}
- core_1.summary.addRaw(``);
+ await setSummaryFooter();
logger_1.logger.info('Created summary.');
return core_1.summary.stringify();
}
@@ -266,15 +281,23 @@ function createErrorSummaryBody(errorList, warningList) {
* @param message Message to display in the body of the comment.
* @returns string containing the error summary.
*/
-function createNothingAnalyzedSummaryBody(message) {
+async function createNothingAnalyzedSummaryBody(message) {
logger_1.logger.header('Creating summary.');
- core_1.summary.addHeading('TICS Quality Gate');
- core_1.summary.addHeading((0, markdown_1.generateStatusMarkdown)(enums_1.Status.PASSED, true), 3);
+ setSummaryHeader(enums_1.Status.PASSED);
core_1.summary.addRaw(message);
- core_1.summary.addRaw(``);
+ await setSummaryFooter();
logger_1.logger.info('Created summary.');
return core_1.summary.stringify();
}
+function setSummaryHeader(status) {
+ core_1.summary.addHeading('TICS Quality Gate');
+ core_1.summary.addHeading((0, markdown_1.generateStatusMarkdown)(status, true), 3);
+}
+async function setSummaryFooter() {
+ core_1.summary.addEOL();
+ core_1.summary.addRaw((0, markdown_1.generateItalic)(`Step: ${await (0, runs_1.getCurrentStepName)()}`), true);
+ core_1.summary.addRaw((0, markdown_1.generateComment)(config_1.githubConfig.getCommentIdentifier()));
+}
function getConditionHeading(failedOrWarnConditions) {
const countFailedConditions = failedOrWarnConditions.filter(c => !c.passed).length;
const countWarnConditions = failedOrWarnConditions.filter(c => c.passed && c.passedWithWarning).length;
@@ -672,14 +695,14 @@ async function processIncompleteAnalysis(analysis) {
let summaryBody;
if (!analysis.completed) {
failedMessage = 'Failed to complete TICS analysis.';
- summaryBody = (0, summary_1.createErrorSummaryBody)(analysis.errorList, analysis.warningList);
+ summaryBody = await (0, summary_1.createErrorSummaryBody)(analysis.errorList, analysis.warningList);
}
else if (analysis.warningList.find(w => w.includes('[WARNING 5057]'))) {
- summaryBody = (0, summary_1.createNothingAnalyzedSummaryBody)('No changed files applicable for TICS analysis quality gating.');
+ summaryBody = await (0, summary_1.createNothingAnalyzedSummaryBody)('No changed files applicable for TICS analysis quality gating.');
}
else {
failedMessage = 'Explorer URL not returned from TICS analysis.';
- summaryBody = (0, summary_1.createErrorSummaryBody)(analysis.errorList, analysis.warningList);
+ summaryBody = await (0, summary_1.createErrorSummaryBody)(analysis.errorList, analysis.warningList);
}
if (config_1.githubConfig.event.isPullRequest) {
await (0, pull_request_1.postToConversation)(false, summaryBody);
@@ -806,13 +829,13 @@ async function qServerAnalysis() {
};
if (!verdict.passed) {
verdict.message = 'Failed to complete TICSQServer analysis.';
- const summaryBody = (0, summary_1.createErrorSummaryBody)(analysis.errorList, analysis.warningList);
+ const summaryBody = await (0, summary_1.createErrorSummaryBody)(analysis.errorList, analysis.warningList);
if (config_1.githubConfig.event.isPullRequest) {
await (0, pull_request_1.postToConversation)(false, summaryBody);
}
}
else if (analysis.warningList.find(w => w.includes('[WARNING 5057]'))) {
- const summaryBody = (0, summary_1.createNothingAnalyzedSummaryBody)('No changed files applicable for TICS analysis quality gating.');
+ const summaryBody = await (0, summary_1.createNothingAnalyzedSummaryBody)('No changed files applicable for TICS analysis quality gating.');
if (config_1.githubConfig.event.isPullRequest) {
await (0, pull_request_1.postToConversation)(false, summaryBody);
}
@@ -1023,6 +1046,7 @@ class GithubConfig {
job;
action;
workflow;
+ runId;
runNumber;
runAttempt;
pullRequestNumber;
@@ -1037,6 +1061,7 @@ class GithubConfig {
this.job = github_1.context.job.replace(/[\s|_]+/g, '-');
this.action = github_1.context.action.replace('__tiobe_', '');
this.workflow = github_1.context.workflow.replace(/[\s|_]+/g, '-');
+ this.runId = github_1.context.runId;
this.runNumber = github_1.context.runNumber;
this.runAttempt = parseInt(process.env.GITHUB_RUN_ATTEMPT ?? '0', 10);
this.pullRequestNumber = this.getPullRequestNumber();
@@ -1051,7 +1076,7 @@ class GithubConfig {
* include a suffix that consists of the sequence number preceded by an underscore.
* https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables
*/
- this.id = `${github_1.context.runId.toString()}_${this.runAttempt.toString()}_${this.job}_${this.action}`;
+ this.id = `${this.runId.toString()}_${this.runAttempt.toString()}_${this.job}_${this.action}`;
this.removeWarningListener();
}
getPullRequestNumber() {
@@ -1919,6 +1944,48 @@ async function postReview(body, event) {
}
+/***/ }),
+
+/***/ 50046:
+/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.getCurrentStepName = getCurrentStepName;
+const logger_1 = __nccwpck_require__(26440);
+const response_1 = __nccwpck_require__(81934);
+const config_1 = __nccwpck_require__(86444);
+const octokit_1 = __nccwpck_require__(10775);
+/**
+ * Create review on the pull request from the analysis given.
+ * @param body Body containing the summary of the review
+ * @param event Either approve or request changes in the review.
+ */
+async function getCurrentStepName() {
+ const params = {
+ owner: config_1.githubConfig.owner,
+ repo: config_1.githubConfig.reponame,
+ run_id: config_1.githubConfig.runId,
+ attempt_number: config_1.githubConfig.runAttempt
+ };
+ let stepname = config_1.githubConfig.action;
+ try {
+ logger_1.logger.debug('Retrieving step name for current step...');
+ const response = await octokit_1.octokit.rest.actions.listJobsForWorkflowRunAttempt(params);
+ const jobs = response.data.jobs.filter(j => j.status === 'in_progress');
+ if (jobs.length === 1) {
+ stepname = jobs[0].name;
+ }
+ }
+ catch (error) {
+ const message = (0, response_1.handleOctokitError)(error);
+ logger_1.logger.notice(`Posting the review failed: ${message}`);
+ }
+ return stepname;
+}
+
+
/***/ }),
/***/ 31655:
diff --git a/src/action/decorate/action.ts b/src/action/decorate/action.ts
index d39be771..8a09f8eb 100644
--- a/src/action/decorate/action.ts
+++ b/src/action/decorate/action.ts
@@ -12,9 +12,9 @@ import { Analysis, AnalysisResult } from '../../helper/interfaces';
export async function decorateAction(analysisResult: AnalysisResult | undefined, analysis: Analysis): Promise {
let summaryBody;
if (analysisResult) {
- summaryBody = createSummaryBody(analysisResult);
+ summaryBody = await createSummaryBody(analysisResult);
} else {
- summaryBody = createErrorSummaryBody(analysis.errorList, analysis.warningList);
+ summaryBody = await createErrorSummaryBody(analysis.errorList, analysis.warningList);
}
if (githubConfig.event.isPullRequest) {
diff --git a/src/action/decorate/markdown.ts b/src/action/decorate/markdown.ts
index ac08af29..195da8a6 100644
--- a/src/action/decorate/markdown.ts
+++ b/src/action/decorate/markdown.ts
@@ -30,3 +30,19 @@ export function generateStatusMarkdown(status: Status, hasSuffix = false): strin
export function generateExpandableAreaMarkdown(header: string, body: string): string {
return `${header}
${EOL}${body} ${EOL}${EOL}`;
}
+
+/**
+ * Generates italic text for markdown.
+ * @param text The text to make italic.
+ */
+export function generateItalic(text: string): string {
+ return `${text}`;
+}
+
+/**
+ * Generates a hidden comment for markdown.
+ * @param comment The text of the comment.
+ */
+export function generateComment(comment: string): string {
+ return ``;
+}
diff --git a/src/action/decorate/summary.ts b/src/action/decorate/summary.ts
index e3de689e..09461f2b 100644
--- a/src/action/decorate/summary.ts
+++ b/src/action/decorate/summary.ts
@@ -3,7 +3,6 @@ import { format } from 'date-fns';
import { range } from 'underscore';
import { summary } from '@actions/core';
import { SummaryTableRow } from '@actions/core/lib/summary';
-
import { ChangedFile } from '../../github/interfaces';
import { Status } from '../../helper/enums';
import { logger } from '../../helper/logger';
@@ -17,13 +16,13 @@ import {
TicsReviewComment,
TicsReviewComments
} from '../../helper/interfaces';
-import { generateExpandableAreaMarkdown, generateStatusMarkdown } from './markdown';
+import { generateComment, generateExpandableAreaMarkdown, generateItalic, generateStatusMarkdown } from './markdown';
import { githubConfig, ticsConfig } from '../../configuration/config';
+import { getCurrentStepName } from '../../github/runs';
-export function createSummaryBody(analysisResult: AnalysisResult): string {
+export async function createSummaryBody(analysisResult: AnalysisResult): Promise {
logger.header('Creating summary.');
- summary.addHeading('TICS Quality Gate');
- summary.addHeading(generateStatusMarkdown(getStatus(analysisResult.passed, analysisResult.passedWithWarning), true), 3);
+ setSummaryHeader(getStatus(analysisResult.passed, analysisResult.passedWithWarning));
analysisResult.projectResults.forEach(projectResult => {
if (projectResult.qualityGate) {
@@ -54,7 +53,7 @@ export function createSummaryBody(analysisResult: AnalysisResult): string {
summary.addRaw(createFilesSummary(projectResult.analyzedFiles));
}
});
- summary.addRaw(``);
+ await setSummaryFooter();
logger.info('Created summary.');
@@ -67,11 +66,10 @@ export function createSummaryBody(analysisResult: AnalysisResult): string {
* @param warningList list containing all the warnings found in the TICS run.
* @returns string containing the error summary.
*/
-export function createErrorSummaryBody(errorList: string[], warningList: string[]): string {
+export async function createErrorSummaryBody(errorList: string[], warningList: string[]): Promise {
logger.header('Creating summary.');
- summary.addHeading('TICS Quality Gate');
- summary.addHeading(generateStatusMarkdown(Status.FAILED, true), 3);
+ setSummaryHeader(Status.FAILED);
if (errorList.length > 0) {
summary.addHeading('The following errors have occurred during analysis:', 2);
@@ -89,7 +87,7 @@ export function createErrorSummaryBody(errorList: string[], warningList: string[
summary.addRaw(`:warning: ${warning}${EOL}${EOL}`);
}
}
- summary.addRaw(``);
+ await setSummaryFooter();
logger.info('Created summary.');
return summary.stringify();
@@ -100,19 +98,29 @@ export function createErrorSummaryBody(errorList: string[], warningList: string[
* @param message Message to display in the body of the comment.
* @returns string containing the error summary.
*/
-export function createNothingAnalyzedSummaryBody(message: string): string {
+export async function createNothingAnalyzedSummaryBody(message: string): Promise {
logger.header('Creating summary.');
- summary.addHeading('TICS Quality Gate');
- summary.addHeading(generateStatusMarkdown(Status.PASSED, true), 3);
+ setSummaryHeader(Status.PASSED);
summary.addRaw(message);
- summary.addRaw(``);
+ await setSummaryFooter();
logger.info('Created summary.');
return summary.stringify();
}
+function setSummaryHeader(status: Status) {
+ summary.addHeading('TICS Quality Gate');
+ summary.addHeading(generateStatusMarkdown(status, true), 3);
+}
+
+async function setSummaryFooter() {
+ summary.addEOL();
+ summary.addRaw(generateItalic(`Step: ${await getCurrentStepName()}`), true);
+ summary.addRaw(generateComment(githubConfig.getCommentIdentifier()));
+}
+
function getConditionHeading(failedOrWarnConditions: Condition[]): string {
const countFailedConditions = failedOrWarnConditions.filter(c => !c.passed).length;
const countWarnConditions = failedOrWarnConditions.filter(c => c.passed && c.passedWithWarning).length;
diff --git a/src/analysis/client/process-analysis.ts b/src/analysis/client/process-analysis.ts
index 4e858572..ca340a25 100644
--- a/src/analysis/client/process-analysis.ts
+++ b/src/analysis/client/process-analysis.ts
@@ -19,12 +19,12 @@ export async function processIncompleteAnalysis(analysis: Analysis): Promise w.includes('[WARNING 5057]'))) {
- summaryBody = createNothingAnalyzedSummaryBody('No changed files applicable for TICS analysis quality gating.');
+ summaryBody = await createNothingAnalyzedSummaryBody('No changed files applicable for TICS analysis quality gating.');
} else {
failedMessage = 'Explorer URL not returned from TICS analysis.';
- summaryBody = createErrorSummaryBody(analysis.errorList, analysis.warningList);
+ summaryBody = await createErrorSummaryBody(analysis.errorList, analysis.warningList);
}
if (githubConfig.event.isPullRequest) {
diff --git a/src/analysis/qserver.ts b/src/analysis/qserver.ts
index b1818745..c7d5e3f7 100644
--- a/src/analysis/qserver.ts
+++ b/src/analysis/qserver.ts
@@ -28,12 +28,12 @@ export async function qServerAnalysis(): Promise {
if (!verdict.passed) {
verdict.message = 'Failed to complete TICSQServer analysis.';
- const summaryBody = createErrorSummaryBody(analysis.errorList, analysis.warningList);
+ const summaryBody = await createErrorSummaryBody(analysis.errorList, analysis.warningList);
if (githubConfig.event.isPullRequest) {
await postToConversation(false, summaryBody);
}
} else if (analysis.warningList.find(w => w.includes('[WARNING 5057]'))) {
- const summaryBody = createNothingAnalyzedSummaryBody('No changed files applicable for TICS analysis quality gating.');
+ const summaryBody = await createNothingAnalyzedSummaryBody('No changed files applicable for TICS analysis quality gating.');
if (githubConfig.event.isPullRequest) {
await postToConversation(false, summaryBody);
}
diff --git a/src/configuration/github.ts b/src/configuration/github.ts
index f538a0e6..873abc4a 100644
--- a/src/configuration/github.ts
+++ b/src/configuration/github.ts
@@ -12,6 +12,7 @@ export class GithubConfig {
readonly job: string;
readonly action: string;
readonly workflow: string;
+ readonly runId: number;
readonly runNumber: number;
readonly runAttempt: number;
readonly pullRequestNumber: number | undefined;
@@ -27,6 +28,7 @@ export class GithubConfig {
this.job = context.job.replace(/[\s|_]+/g, '-');
this.action = context.action.replace('__tiobe_', '');
this.workflow = context.workflow.replace(/[\s|_]+/g, '-');
+ this.runId = context.runId;
this.runNumber = context.runNumber;
this.runAttempt = parseInt(process.env.GITHUB_RUN_ATTEMPT ?? '0', 10);
this.pullRequestNumber = this.getPullRequestNumber();
@@ -42,7 +44,7 @@ export class GithubConfig {
* include a suffix that consists of the sequence number preceded by an underscore.
* https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables
*/
- this.id = `${context.runId.toString()}_${this.runAttempt.toString()}_${this.job}_${this.action}`;
+ this.id = `${this.runId.toString()}_${this.runAttempt.toString()}_${this.job}_${this.action}`;
this.removeWarningListener();
}
diff --git a/src/github/runs.ts b/src/github/runs.ts
new file mode 100644
index 00000000..c91a6287
--- /dev/null
+++ b/src/github/runs.ts
@@ -0,0 +1,32 @@
+import { logger } from '../helper/logger';
+import { handleOctokitError } from '../helper/response';
+import { githubConfig } from '../configuration/config';
+import { octokit } from './octokit';
+
+/**
+ * Create review on the pull request from the analysis given.
+ * @param body Body containing the summary of the review
+ * @param event Either approve or request changes in the review.
+ */
+export async function getCurrentStepName(): Promise {
+ const params = {
+ owner: githubConfig.owner,
+ repo: githubConfig.reponame,
+ run_id: githubConfig.runId,
+ attempt_number: githubConfig.runAttempt
+ };
+
+ let stepname = githubConfig.action;
+ try {
+ logger.debug('Retrieving step name for current step...');
+ const response = await octokit.rest.actions.listJobsForWorkflowRunAttempt(params);
+ const jobs = response.data.jobs.filter(j => j.status === 'in_progress');
+ if (jobs.length === 1) {
+ stepname = jobs[0].name;
+ }
+ } catch (error: unknown) {
+ const message = handleOctokitError(error);
+ logger.notice(`Posting the review failed: ${message}`);
+ }
+ return stepname;
+}
diff --git a/test/unit/action/decorate/action.test.ts b/test/unit/action/decorate/action.test.ts
index e1e5deed..61d8d671 100644
--- a/test/unit/action/decorate/action.test.ts
+++ b/test/unit/action/decorate/action.test.ts
@@ -14,8 +14,8 @@ describe('decorateAction', () => {
let spyPostAnnotations: jest.SpyInstance;
beforeEach(() => {
- spyCreateSummaryBody = jest.spyOn(summary, 'createSummaryBody').mockReturnValue('body');
- spyCreateErrorSummaryBody = jest.spyOn(summary, 'createErrorSummaryBody').mockReturnValue('body');
+ spyCreateSummaryBody = jest.spyOn(summary, 'createSummaryBody').mockResolvedValue('body');
+ spyCreateErrorSummaryBody = jest.spyOn(summary, 'createErrorSummaryBody').mockResolvedValue('body');
spyDecoratePullRequest = jest.spyOn(pullRequest, 'decoratePullRequest').mockImplementation();
spyPostAnnotations = jest.spyOn(annotations, 'postAnnotations').mockImplementation();
});
diff --git a/test/unit/action/decorate/summary.test.ts b/test/unit/action/decorate/summary.test.ts
index 7af2dcb9..2223a8c8 100644
--- a/test/unit/action/decorate/summary.test.ts
+++ b/test/unit/action/decorate/summary.test.ts
@@ -26,8 +26,8 @@ describe('createSummaryBody', () => {
ticsConfigMock.displayUrl = 'http://viewer.url/';
});
- test('Should contain blocking after if there are soaked violations', () => {
- const string = createSummaryBody(analysisResultsSoaked);
+ test('Should contain blocking after if there are soaked violations', async () => {
+ const string = await createSummaryBody(analysisResultsSoaked);
expect(string).toContain(':x: Failed
');
expect(string).toContain('1 Condition(s) failed
');
@@ -40,8 +40,8 @@ describe('createSummaryBody', () => {
summary.clear();
});
- test('Should not contain blocking after if there are no soaked violations', () => {
- const string = createSummaryBody(analysisResultsNotSoaked);
+ test('Should not contain blocking after if there are no soaked violations', async () => {
+ const string = await createSummaryBody(analysisResultsNotSoaked);
expect(string).toContain(':x: Failed
');
expect(string).toContain('1 Condition(s) failed
');
@@ -54,8 +54,8 @@ describe('createSummaryBody', () => {
summary.clear();
});
- test('Should contain blocking after if there are partly violations', () => {
- const string = createSummaryBody(analysisResultsPartlySoakedPassed);
+ test('Should contain blocking after if there are partly violations', async () => {
+ const string = await createSummaryBody(analysisResultsPartlySoakedPassed);
expect(string).toContain(':warning: Passed with warnings
');
expect(string).toContain('1 Condition(s) passed with warning
');
@@ -67,8 +67,8 @@ describe('createSummaryBody', () => {
summary.clear();
});
- test('Should contain blocking after for one of the two conditions', () => {
- const string = createSummaryBody(analysisResultsPartlySoakedFailed);
+ test('Should contain blocking after for one of the two conditions', async () => {
+ const string = await createSummaryBody(analysisResultsPartlySoakedFailed);
expect(string).toContain(':x: Failed
');
expect(string).toContain('1 Condition(s) failed, 1 Condition(s) passed with warning
');
@@ -82,8 +82,8 @@ describe('createSummaryBody', () => {
summary.clear();
});
- test('Should pass with no conditions that passed with warnings', () => {
- const string = createSummaryBody(analysisResultsNoSoakedPassed);
+ test('Should pass with no conditions that passed with warnings', async () => {
+ const string = await createSummaryBody(analysisResultsNoSoakedPassed);
expect(string).toContain(':heavy_check_mark: Passed
');
expect(string).toContain('All conditions passed
');
@@ -93,10 +93,10 @@ describe('createSummaryBody', () => {
});
describe('createErrorSummary', () => {
- test('Should return summary of two errors', () => {
+ test('Should return summary of two errors', async () => {
githubConfigMock.debugger = false;
- const body = createErrorSummaryBody(['Error', 'Error'], []);
+ const body = await createErrorSummaryBody(['Error', 'Error'], []);
summary.clear();
expect(body).toContainTimes('The following errors have occurred during analysis:
', 1);
@@ -105,10 +105,10 @@ describe('createErrorSummary', () => {
expect(body).toContainTimes(':warning: Warning', 0);
});
- test('Should return summary of zero warnings on logLevel default', () => {
+ test('Should return summary of zero warnings on logLevel default', async () => {
githubConfigMock.debugger = false;
- const body = createErrorSummaryBody([], ['Warning', 'Warning']);
+ const body = await createErrorSummaryBody([], ['Warning', 'Warning']);
summary.clear();
expect(body).toContainTimes('The following errors have occurred during analysis:
', 0);
@@ -117,35 +117,41 @@ describe('createErrorSummary', () => {
expect(body).toContainTimes(':warning: Warning', 0);
});
- test('Should return summary of two warnings on logLevel debug', () => {
+ test('Should return summary of two warnings on logLevel debug', async () => {
githubConfigMock.debugger = true;
- const body = createErrorSummaryBody([], ['Warning', 'Warning']);
+ const body = await createErrorSummaryBody([], ['Warning', 'Warning']);
summary.clear();
expect(body).toContainTimes('The following errors have occurred during analysis:
', 0);
expect(body).toContainTimes('The following warnings have occurred during analysis:
', 1);
expect(body).toContainTimes(':x: Error', 0);
expect(body).toContainTimes(':warning: Warning', 2);
+ expect(body).toContainTimes('\ntics-github-action', 1);
+ expect(body).toContain('\n');
});
- test('Should return summary of one error and two warnings', () => {
+ test('Should return summary of one error and two warnings', async () => {
githubConfigMock.debugger = true;
- const body = createErrorSummaryBody(['Error'], ['Warning', 'Warning']);
+ const body = await createErrorSummaryBody(['Error'], ['Warning', 'Warning']);
summary.clear();
expect(body).toContainTimes('The following errors have occurred during analysis:
', 1);
expect(body).toContainTimes('The following warnings have occurred during analysis:
', 1);
expect(body).toContainTimes(':x: Error', 1);
expect(body).toContainTimes(':warning: Warning', 2);
+ expect(body).toContainTimes('\ntics-github-action', 1);
+ expect(body).toContainTimes('\n', 1);
});
});
describe('createNothingAnalyzedSummaryBody', () => {
test('Should return summary with the message given', async () => {
- const body = createNothingAnalyzedSummaryBody('message');
- expect(body).toEqual('TICS Quality Gate
\n:heavy_check_mark: Passed
\nmessage');
+ const body = await createNothingAnalyzedSummaryBody('message');
+ expect(body).toEqual(
+ 'TICS Quality Gate
\n:heavy_check_mark: Passed
\nmessage\ntics-github-action\n'
+ );
});
});
diff --git a/test/unit/analysis/qserver.test.ts b/test/unit/analysis/qserver.test.ts
index d33015c6..f011c223 100644
--- a/test/unit/analysis/qserver.test.ts
+++ b/test/unit/analysis/qserver.test.ts
@@ -33,7 +33,7 @@ describe('SetFailed checks (QServer)', () => {
spyGetLastQServerRunDate = jest.spyOn(viewer, 'getLastQServerRunDate');
jest.spyOn(action, 'decorateAction');
- jest.spyOn(summary, 'createNothingAnalyzedSummaryBody').mockReturnValue('body');
+ jest.spyOn(summary, 'createNothingAnalyzedSummaryBody').mockResolvedValue('body');
});
afterEach(() => {
From 05cfbf4c7cad8663ce6fd275c600d172a39a4977 Mon Sep 17 00:00:00 2001
From: janssen <118828444+janssen-tiobe@users.noreply.github.com>
Date: Fri, 6 Dec 2024 14:56:04 +0100
Subject: [PATCH 06/11] #34049: Fix failing tests + add runs test
---
test/.setup/mock.ts | 3 ++
test/unit/action/decorate/summary.test.ts | 6 +--
test/unit/github/runs.test.ts | 61 +++++++++++++++++++++++
3 files changed, 67 insertions(+), 3 deletions(-)
create mode 100644 test/unit/github/runs.test.ts
diff --git a/test/.setup/mock.ts b/test/.setup/mock.ts
index d1d7c830..911ae437 100644
--- a/test/.setup/mock.ts
+++ b/test/.setup/mock.ts
@@ -112,6 +112,9 @@ jest.mock('../../src/github/octokit', () => {
},
repos: {
getCommit: jest.fn()
+ },
+ actions: {
+ listJobsForWorkflowRunAttempt: jest.fn()
}
},
graphql: jest.fn()
diff --git a/test/unit/action/decorate/summary.test.ts b/test/unit/action/decorate/summary.test.ts
index 2223a8c8..7971c06c 100644
--- a/test/unit/action/decorate/summary.test.ts
+++ b/test/unit/action/decorate/summary.test.ts
@@ -127,7 +127,7 @@ describe('createErrorSummary', () => {
expect(body).toContainTimes('The following warnings have occurred during analysis:
', 1);
expect(body).toContainTimes(':x: Error', 0);
expect(body).toContainTimes(':warning: Warning', 2);
- expect(body).toContainTimes('\ntics-github-action', 1);
+ expect(body).toContainTimes('\nStep: tics-github-action', 1);
expect(body).toContain('\n');
});
@@ -141,7 +141,7 @@ describe('createErrorSummary', () => {
expect(body).toContainTimes('The following warnings have occurred during analysis:
', 1);
expect(body).toContainTimes(':x: Error', 1);
expect(body).toContainTimes(':warning: Warning', 2);
- expect(body).toContainTimes('\ntics-github-action', 1);
+ expect(body).toContainTimes('\nStep: tics-github-action', 1);
expect(body).toContainTimes('\n', 1);
});
});
@@ -150,7 +150,7 @@ describe('createNothingAnalyzedSummaryBody', () => {
test('Should return summary with the message given', async () => {
const body = await createNothingAnalyzedSummaryBody('message');
expect(body).toEqual(
- 'TICS Quality Gate
\n:heavy_check_mark: Passed
\nmessage\ntics-github-action\n'
+ 'TICS Quality Gate
\n:heavy_check_mark: Passed
\nmessage\nStep: tics-github-action\n'
);
});
});
diff --git a/test/unit/github/runs.test.ts b/test/unit/github/runs.test.ts
new file mode 100644
index 00000000..58215ca5
--- /dev/null
+++ b/test/unit/github/runs.test.ts
@@ -0,0 +1,61 @@
+import { getCurrentStepName } from '../../../src/github/runs';
+import { octokit } from '../../../src/github/octokit';
+import { githubConfigMock } from '../../.setup/mock';
+
+describe('postReview', () => {
+ let listJobsSpy: jest.SpyInstance;
+
+ beforeEach(() => {
+ listJobsSpy = jest.spyOn(octokit.rest.actions, 'listJobsForWorkflowRunAttempt');
+ });
+
+ test('Should return name when only one step is in progress', async () => {
+ listJobsSpy.mockResolvedValue({
+ data: {
+ jobs: [
+ {
+ name: 'Step 1',
+ status: 'completed'
+ },
+ {
+ name: 'Step 2',
+ status: 'in_progress'
+ }
+ ]
+ }
+ });
+
+ const name = await getCurrentStepName();
+
+ expect(name).toStrictEqual('Step 2');
+ });
+
+ test('Should not return name when only one step is in progress', async () => {
+ listJobsSpy.mockResolvedValue({
+ data: {
+ jobs: [
+ {
+ name: 'Step 1',
+ status: 'in_progress'
+ },
+ {
+ name: 'Step 2',
+ status: 'in_progress'
+ }
+ ]
+ }
+ });
+
+ const name = await getCurrentStepName();
+
+ expect(name).toStrictEqual(githubConfigMock.action);
+ });
+
+ test('Should post a notice on createReview', async () => {
+ listJobsSpy.mockRejectedValue(new Error());
+
+ const name = await getCurrentStepName();
+
+ expect(name).toStrictEqual(githubConfigMock.action);
+ });
+});
From 6e08353b6722105473ed1bae75bcdbf3e3eb3782 Mon Sep 17 00:00:00 2001
From: janssen <118828444+janssen-tiobe@users.noreply.github.com>
Date: Fri, 6 Dec 2024 16:36:49 +0100
Subject: [PATCH 07/11] #34049: Corrected data usage of
listJobsForWorkflowRunAttempt api call
---
dist/index.js | 7 +++--
src/github/runs.ts | 8 ++++--
test/unit/github/runs.test.ts | 54 +++++++++++++++++++++++++++++------
3 files changed, 56 insertions(+), 13 deletions(-)
diff --git a/dist/index.js b/dist/index.js
index a3cb78a1..b0662bcc 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -1979,9 +1979,12 @@ async function getCurrentStepName() {
try {
logger_1.logger.debug('Retrieving step name for current step...');
const response = await octokit_1.octokit.rest.actions.listJobsForWorkflowRunAttempt(params);
- const jobs = response.data.jobs.filter(j => j.status === 'in_progress');
+ const jobs = response.data.jobs.filter(j => j.name.replace(/[\s|_]+/g, '-') === config_1.githubConfig.job);
if (jobs.length === 1) {
- stepname = jobs[0].name;
+ const steps = jobs[0].steps?.filter(s => s.status === 'in_progress');
+ if (steps?.length === 1) {
+ stepname = steps[0].name;
+ }
}
}
catch (error) {
diff --git a/src/github/runs.ts b/src/github/runs.ts
index c91a6287..045d93a7 100644
--- a/src/github/runs.ts
+++ b/src/github/runs.ts
@@ -20,9 +20,13 @@ export async function getCurrentStepName(): Promise {
try {
logger.debug('Retrieving step name for current step...');
const response = await octokit.rest.actions.listJobsForWorkflowRunAttempt(params);
- const jobs = response.data.jobs.filter(j => j.status === 'in_progress');
+ const jobs = response.data.jobs.filter(j => j.name.replace(/[\s|_]+/g, '-') === githubConfig.job);
+
if (jobs.length === 1) {
- stepname = jobs[0].name;
+ const steps = jobs[0].steps?.filter(s => s.status === 'in_progress');
+ if (steps?.length === 1) {
+ stepname = steps[0].name;
+ }
}
} catch (error: unknown) {
const message = handleOctokitError(error);
diff --git a/test/unit/github/runs.test.ts b/test/unit/github/runs.test.ts
index 58215ca5..bf63d636 100644
--- a/test/unit/github/runs.test.ts
+++ b/test/unit/github/runs.test.ts
@@ -14,12 +14,30 @@ describe('postReview', () => {
data: {
jobs: [
{
- name: 'Step 1',
- status: 'completed'
+ name: 'TICS',
+ steps: [
+ {
+ name: 'Step 1',
+ status: 'completed'
+ },
+ {
+ name: 'Step 2',
+ status: 'in_progress'
+ }
+ ]
},
{
- name: 'Step 2',
- status: 'in_progress'
+ name: 'TICS2',
+ steps: [
+ {
+ name: 'Step 1',
+ status: 'in_progress'
+ },
+ {
+ name: 'Step 2',
+ status: 'in_progress'
+ }
+ ]
}
]
}
@@ -30,17 +48,35 @@ describe('postReview', () => {
expect(name).toStrictEqual('Step 2');
});
- test('Should not return name when only one step is in progress', async () => {
+ test('Should not return name when multiple steps are in progress', async () => {
listJobsSpy.mockResolvedValue({
data: {
jobs: [
{
- name: 'Step 1',
- status: 'in_progress'
+ name: 'TICS',
+ steps: [
+ {
+ name: 'Step 1',
+ status: 'in_progress'
+ },
+ {
+ name: 'Step 2',
+ status: 'in_progress'
+ }
+ ]
},
{
- name: 'Step 2',
- status: 'in_progress'
+ name: 'TICS2',
+ steps: [
+ {
+ name: 'Step 1',
+ status: 'completed'
+ },
+ {
+ name: 'Step 2',
+ status: 'completed'
+ }
+ ]
}
]
}
From 441b76b71bacff81dd3aef2ff21fb743bd674e0b Mon Sep 17 00:00:00 2001
From: janssen <118828444+janssen-tiobe@users.noreply.github.com>
Date: Fri, 6 Dec 2024 16:50:04 +0100
Subject: [PATCH 08/11] #34049: Added more debug info
---
dist/index.js | 1 +
src/github/runs.ts | 1 +
2 files changed, 2 insertions(+)
diff --git a/dist/index.js b/dist/index.js
index b0662bcc..66c55a95 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -1979,6 +1979,7 @@ async function getCurrentStepName() {
try {
logger_1.logger.debug('Retrieving step name for current step...');
const response = await octokit_1.octokit.rest.actions.listJobsForWorkflowRunAttempt(params);
+ logger_1.logger.debug(JSON.stringify(response.data));
const jobs = response.data.jobs.filter(j => j.name.replace(/[\s|_]+/g, '-') === config_1.githubConfig.job);
if (jobs.length === 1) {
const steps = jobs[0].steps?.filter(s => s.status === 'in_progress');
diff --git a/src/github/runs.ts b/src/github/runs.ts
index 045d93a7..11b4a14e 100644
--- a/src/github/runs.ts
+++ b/src/github/runs.ts
@@ -20,6 +20,7 @@ export async function getCurrentStepName(): Promise {
try {
logger.debug('Retrieving step name for current step...');
const response = await octokit.rest.actions.listJobsForWorkflowRunAttempt(params);
+ logger.debug(JSON.stringify(response.data));
const jobs = response.data.jobs.filter(j => j.name.replace(/[\s|_]+/g, '-') === githubConfig.job);
if (jobs.length === 1) {
From 85550a6cf08989454a48e03569274230a400e962 Mon Sep 17 00:00:00 2001
From: janssen <118828444+janssen-tiobe@users.noreply.github.com>
Date: Mon, 9 Dec 2024 10:07:44 +0100
Subject: [PATCH 09/11] #34049: Added more information in the summary, step
retrieval changed
---
dist/index.js | 8 +++++---
src/action/decorate/summary.ts | 2 +-
src/configuration/github.ts | 2 ++
src/github/runs.ts | 4 ++--
test/.setup/mock.ts | 2 ++
test/unit/action/decorate/summary.test.ts | 6 +++---
test/unit/github/runs.test.ts | 12 ++++++++----
7 files changed, 23 insertions(+), 13 deletions(-)
diff --git a/dist/index.js b/dist/index.js
index 66c55a95..525a3a5b 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -296,7 +296,7 @@ function setSummaryHeader(status) {
}
async function setSummaryFooter() {
core_1.summary.addEOL();
- core_1.summary.addRaw((0, markdown_1.generateItalic)(`Step: ${await (0, runs_1.getCurrentStepName)()}`), true);
+ core_1.summary.addRaw((0, markdown_1.generateItalic)(`Workflow: ${config_1.githubConfig.workflow}, Job: ${config_1.githubConfig.job}, Step: ${await (0, runs_1.getCurrentStepName)()}`), true);
core_1.summary.addRaw((0, markdown_1.generateComment)(config_1.githubConfig.getCommentIdentifier()));
}
function getConditionHeading(failedOrWarnConditions) {
@@ -1057,6 +1057,7 @@ class GithubConfig {
runAttempt;
pullRequestNumber;
debugger;
+ runnerName;
id;
constructor() {
this.apiUrl = github_1.context.apiUrl;
@@ -1072,6 +1073,7 @@ class GithubConfig {
this.runAttempt = parseInt(process.env.GITHUB_RUN_ATTEMPT ?? '0', 10);
this.pullRequestNumber = this.getPullRequestNumber();
this.debugger = (0, core_1.isDebug)();
+ this.runnerName = process.env.RUNNER_NAME ?? '';
/**
* Construct the id to use for storing tmpdirs. The action name will
* be appended with a number if there are multiple runs within a job.
@@ -1980,7 +1982,7 @@ async function getCurrentStepName() {
logger_1.logger.debug('Retrieving step name for current step...');
const response = await octokit_1.octokit.rest.actions.listJobsForWorkflowRunAttempt(params);
logger_1.logger.debug(JSON.stringify(response.data));
- const jobs = response.data.jobs.filter(j => j.name.replace(/[\s|_]+/g, '-') === config_1.githubConfig.job);
+ const jobs = response.data.jobs.filter(j => j.status === 'in_progress' && j.runner_name === config_1.githubConfig.runnerName);
if (jobs.length === 1) {
const steps = jobs[0].steps?.filter(s => s.status === 'in_progress');
if (steps?.length === 1) {
@@ -1990,7 +1992,7 @@ async function getCurrentStepName() {
}
catch (error) {
const message = (0, response_1.handleOctokitError)(error);
- logger_1.logger.notice(`Posting the review failed: ${message}`);
+ logger_1.logger.notice(`Retrieving the step name failed: ${message}`);
}
return stepname;
}
diff --git a/src/action/decorate/summary.ts b/src/action/decorate/summary.ts
index a8b52d5d..7083f22e 100644
--- a/src/action/decorate/summary.ts
+++ b/src/action/decorate/summary.ts
@@ -119,7 +119,7 @@ function setSummaryHeader(status: Status) {
async function setSummaryFooter() {
summary.addEOL();
- summary.addRaw(generateItalic(`Step: ${await getCurrentStepName()}`), true);
+ summary.addRaw(generateItalic(`Workflow: ${githubConfig.workflow}, Job: ${githubConfig.job}, Step: ${await getCurrentStepName()}`), true);
summary.addRaw(generateComment(githubConfig.getCommentIdentifier()));
}
diff --git a/src/configuration/github.ts b/src/configuration/github.ts
index 873abc4a..f303e858 100644
--- a/src/configuration/github.ts
+++ b/src/configuration/github.ts
@@ -17,6 +17,7 @@ export class GithubConfig {
readonly runAttempt: number;
readonly pullRequestNumber: number | undefined;
readonly debugger: boolean;
+ readonly runnerName: string;
readonly id: string;
constructor() {
@@ -33,6 +34,7 @@ export class GithubConfig {
this.runAttempt = parseInt(process.env.GITHUB_RUN_ATTEMPT ?? '0', 10);
this.pullRequestNumber = this.getPullRequestNumber();
this.debugger = isDebug();
+ this.runnerName = process.env.RUNNER_NAME ?? '';
/**
* Construct the id to use for storing tmpdirs. The action name will
diff --git a/src/github/runs.ts b/src/github/runs.ts
index 11b4a14e..0a850ef6 100644
--- a/src/github/runs.ts
+++ b/src/github/runs.ts
@@ -21,7 +21,7 @@ export async function getCurrentStepName(): Promise {
logger.debug('Retrieving step name for current step...');
const response = await octokit.rest.actions.listJobsForWorkflowRunAttempt(params);
logger.debug(JSON.stringify(response.data));
- const jobs = response.data.jobs.filter(j => j.name.replace(/[\s|_]+/g, '-') === githubConfig.job);
+ const jobs = response.data.jobs.filter(j => j.status === 'in_progress' && j.runner_name === githubConfig.runnerName);
if (jobs.length === 1) {
const steps = jobs[0].steps?.filter(s => s.status === 'in_progress');
@@ -31,7 +31,7 @@ export async function getCurrentStepName(): Promise {
}
} catch (error: unknown) {
const message = handleOctokitError(error);
- logger.notice(`Posting the review failed: ${message}`);
+ logger.notice(`Retrieving the step name failed: ${message}`);
}
return stepname;
}
diff --git a/test/.setup/mock.ts b/test/.setup/mock.ts
index 911ae437..b6e99d0f 100644
--- a/test/.setup/mock.ts
+++ b/test/.setup/mock.ts
@@ -16,6 +16,7 @@ export const githubConfigMock: {
workflow: string;
runNumber: number;
runAttempt: number;
+ runnerName: string;
getCommentIdentifier(): string;
} = {
apiUrl: 'github.com/api/v1/',
@@ -31,6 +32,7 @@ export const githubConfigMock: {
workflow: 'tics-client',
runNumber: 1,
runAttempt: 2,
+ runnerName: 'Github Actions 1',
getCommentIdentifier(): string {
return [this.workflow, this.job, this.runNumber, this.runAttempt].join('_');
}
diff --git a/test/unit/action/decorate/summary.test.ts b/test/unit/action/decorate/summary.test.ts
index a06f1a73..5a7e0bb3 100644
--- a/test/unit/action/decorate/summary.test.ts
+++ b/test/unit/action/decorate/summary.test.ts
@@ -129,7 +129,7 @@ describe('createErrorSummary', () => {
expect(body).toContainTimes('The following warnings have occurred during analysis:
', 1);
expect(body).toContainTimes(':x: Error', 0);
expect(body).toContainTimes(':warning: Warning', 2);
- expect(body).toContainTimes('\nStep: tics-github-action', 1);
+ expect(body).toContainTimes('\nWorkflow: tics-client, Job: TICS, Step: tics-github-action', 1);
expect(body).toContain('\n');
});
@@ -143,7 +143,7 @@ describe('createErrorSummary', () => {
expect(body).toContainTimes('The following warnings have occurred during analysis:
', 1);
expect(body).toContainTimes(':x: Error', 1);
expect(body).toContainTimes(':warning: Warning', 2);
- expect(body).toContainTimes('\nStep: tics-github-action', 1);
+ expect(body).toContainTimes('\nWorkflow: tics-client, Job: TICS, Step: tics-github-action', 1);
expect(body).toContainTimes('\n', 1);
});
});
@@ -152,7 +152,7 @@ describe('createNothingAnalyzedSummaryBody', () => {
test('Should return summary with the message given', async () => {
const body = await createNothingAnalyzedSummaryBody('message');
expect(body).toEqual(
- 'TICS Quality Gate
\n:heavy_check_mark: Passed
\nmessage\nStep: tics-github-action\n'
+ 'TICS Quality Gate
\n:heavy_check_mark: Passed
\nmessage\nWorkflow: tics-client, Job: TICS, Step: tics-github-action\n'
);
});
});
diff --git a/test/unit/github/runs.test.ts b/test/unit/github/runs.test.ts
index bf63d636..e8e72631 100644
--- a/test/unit/github/runs.test.ts
+++ b/test/unit/github/runs.test.ts
@@ -14,7 +14,8 @@ describe('postReview', () => {
data: {
jobs: [
{
- name: 'TICS',
+ runner_name: 'Github Actions 1',
+ status: 'in_progress',
steps: [
{
name: 'Step 1',
@@ -27,7 +28,8 @@ describe('postReview', () => {
]
},
{
- name: 'TICS2',
+ name: 'Github Actions 2',
+ status: 'completed',
steps: [
{
name: 'Step 1',
@@ -53,7 +55,8 @@ describe('postReview', () => {
data: {
jobs: [
{
- name: 'TICS',
+ runner_name: 'Github Actions 1',
+ status: 'in_progress',
steps: [
{
name: 'Step 1',
@@ -66,7 +69,8 @@ describe('postReview', () => {
]
},
{
- name: 'TICS2',
+ name: 'Github Actions 1',
+ status: 'completed',
steps: [
{
name: 'Step 1',
From d7c1bfb63cf9f7fa28fcbcad37a8198a71c1db17 Mon Sep 17 00:00:00 2001
From: janssen <118828444+janssen-tiobe@users.noreply.github.com>
Date: Mon, 9 Dec 2024 13:08:02 +0100
Subject: [PATCH 10/11] #34049: Formatting the step name differently
---
dist/index.js | 16 +++++++++-------
src/action/decorate/summary.ts | 4 ++--
src/github/runs.ts | 12 +++++++-----
test/unit/action/decorate/summary.test.ts | 6 +++---
test/unit/github/runs.test.ts | 22 +++++++++++++---------
5 files changed, 34 insertions(+), 26 deletions(-)
diff --git a/dist/index.js b/dist/index.js
index 525a3a5b..75c1c290 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -296,7 +296,7 @@ function setSummaryHeader(status) {
}
async function setSummaryFooter() {
core_1.summary.addEOL();
- core_1.summary.addRaw((0, markdown_1.generateItalic)(`Workflow: ${config_1.githubConfig.workflow}, Job: ${config_1.githubConfig.job}, Step: ${await (0, runs_1.getCurrentStepName)()}`), true);
+ core_1.summary.addRaw((0, markdown_1.generateItalic)(await (0, runs_1.getCurrentStepPath)()), true);
core_1.summary.addRaw((0, markdown_1.generateComment)(config_1.githubConfig.getCommentIdentifier()));
}
function getConditionHeading(failedOrWarnConditions) {
@@ -1960,7 +1960,7 @@ async function postReview(body, event) {
"use strict";
Object.defineProperty(exports, "__esModule", ({ value: true }));
-exports.getCurrentStepName = getCurrentStepName;
+exports.getCurrentStepPath = getCurrentStepPath;
const logger_1 = __nccwpck_require__(26440);
const response_1 = __nccwpck_require__(81934);
const config_1 = __nccwpck_require__(86444);
@@ -1970,23 +1970,25 @@ const octokit_1 = __nccwpck_require__(10775);
* @param body Body containing the summary of the review
* @param event Either approve or request changes in the review.
*/
-async function getCurrentStepName() {
+async function getCurrentStepPath() {
const params = {
owner: config_1.githubConfig.owner,
repo: config_1.githubConfig.reponame,
run_id: config_1.githubConfig.runId,
attempt_number: config_1.githubConfig.runAttempt
};
- let stepname = config_1.githubConfig.action;
+ const stepname = [config_1.githubConfig.workflow, config_1.githubConfig.job, config_1.githubConfig.action];
try {
logger_1.logger.debug('Retrieving step name for current step...');
const response = await octokit_1.octokit.rest.actions.listJobsForWorkflowRunAttempt(params);
logger_1.logger.debug(JSON.stringify(response.data));
const jobs = response.data.jobs.filter(j => j.status === 'in_progress' && j.runner_name === config_1.githubConfig.runnerName);
if (jobs.length === 1) {
- const steps = jobs[0].steps?.filter(s => s.status === 'in_progress');
+ const job = jobs[0];
+ stepname[1] = job.name;
+ const steps = job.steps?.filter(s => s.status === 'in_progress');
if (steps?.length === 1) {
- stepname = steps[0].name;
+ stepname[2] = steps[0].name;
}
}
}
@@ -1994,7 +1996,7 @@ async function getCurrentStepName() {
const message = (0, response_1.handleOctokitError)(error);
logger_1.logger.notice(`Retrieving the step name failed: ${message}`);
}
- return stepname;
+ return stepname.join(' / ');
}
diff --git a/src/action/decorate/summary.ts b/src/action/decorate/summary.ts
index 7083f22e..f360f315 100644
--- a/src/action/decorate/summary.ts
+++ b/src/action/decorate/summary.ts
@@ -18,7 +18,7 @@ import {
} from '../../helper/interfaces';
import { generateComment, generateExpandableAreaMarkdown, generateItalic, generateStatusMarkdown } from './markdown';
import { githubConfig, ticsConfig } from '../../configuration/config';
-import { getCurrentStepName } from '../../github/runs';
+import { getCurrentStepPath } from '../../github/runs';
const capitalize = (s: string): string => s && String(s[0]).toUpperCase() + String(s).slice(1);
@@ -119,7 +119,7 @@ function setSummaryHeader(status: Status) {
async function setSummaryFooter() {
summary.addEOL();
- summary.addRaw(generateItalic(`Workflow: ${githubConfig.workflow}, Job: ${githubConfig.job}, Step: ${await getCurrentStepName()}`), true);
+ summary.addRaw(generateItalic(await getCurrentStepPath()), true);
summary.addRaw(generateComment(githubConfig.getCommentIdentifier()));
}
diff --git a/src/github/runs.ts b/src/github/runs.ts
index 0a850ef6..619b97b4 100644
--- a/src/github/runs.ts
+++ b/src/github/runs.ts
@@ -8,7 +8,7 @@ import { octokit } from './octokit';
* @param body Body containing the summary of the review
* @param event Either approve or request changes in the review.
*/
-export async function getCurrentStepName(): Promise {
+export async function getCurrentStepPath(): Promise {
const params = {
owner: githubConfig.owner,
repo: githubConfig.reponame,
@@ -16,7 +16,7 @@ export async function getCurrentStepName(): Promise {
attempt_number: githubConfig.runAttempt
};
- let stepname = githubConfig.action;
+ const stepname = [githubConfig.workflow, githubConfig.job, githubConfig.action];
try {
logger.debug('Retrieving step name for current step...');
const response = await octokit.rest.actions.listJobsForWorkflowRunAttempt(params);
@@ -24,14 +24,16 @@ export async function getCurrentStepName(): Promise {
const jobs = response.data.jobs.filter(j => j.status === 'in_progress' && j.runner_name === githubConfig.runnerName);
if (jobs.length === 1) {
- const steps = jobs[0].steps?.filter(s => s.status === 'in_progress');
+ const job = jobs[0];
+ stepname[1] = job.name;
+ const steps = job.steps?.filter(s => s.status === 'in_progress');
if (steps?.length === 1) {
- stepname = steps[0].name;
+ stepname[2] = steps[0].name;
}
}
} catch (error: unknown) {
const message = handleOctokitError(error);
logger.notice(`Retrieving the step name failed: ${message}`);
}
- return stepname;
+ return stepname.join(' / ');
}
diff --git a/test/unit/action/decorate/summary.test.ts b/test/unit/action/decorate/summary.test.ts
index 5a7e0bb3..2f9bb9de 100644
--- a/test/unit/action/decorate/summary.test.ts
+++ b/test/unit/action/decorate/summary.test.ts
@@ -129,7 +129,7 @@ describe('createErrorSummary', () => {
expect(body).toContainTimes('The following warnings have occurred during analysis:
', 1);
expect(body).toContainTimes(':x: Error', 0);
expect(body).toContainTimes(':warning: Warning', 2);
- expect(body).toContainTimes('\nWorkflow: tics-client, Job: TICS, Step: tics-github-action', 1);
+ expect(body).toContainTimes('\ntics-client / TICS / tics-github-action', 1);
expect(body).toContain('\n');
});
@@ -143,7 +143,7 @@ describe('createErrorSummary', () => {
expect(body).toContainTimes('The following warnings have occurred during analysis:
', 1);
expect(body).toContainTimes(':x: Error', 1);
expect(body).toContainTimes(':warning: Warning', 2);
- expect(body).toContainTimes('\nWorkflow: tics-client, Job: TICS, Step: tics-github-action', 1);
+ expect(body).toContainTimes('\ntics-client / TICS / tics-github-action', 1);
expect(body).toContainTimes('\n', 1);
});
});
@@ -152,7 +152,7 @@ describe('createNothingAnalyzedSummaryBody', () => {
test('Should return summary with the message given', async () => {
const body = await createNothingAnalyzedSummaryBody('message');
expect(body).toEqual(
- 'TICS Quality Gate
\n:heavy_check_mark: Passed
\nmessage\nWorkflow: tics-client, Job: TICS, Step: tics-github-action\n'
+ 'TICS Quality Gate
\n:heavy_check_mark: Passed
\nmessage\ntics-client / TICS / tics-github-action\n'
);
});
});
diff --git a/test/unit/github/runs.test.ts b/test/unit/github/runs.test.ts
index e8e72631..8bbe7cdc 100644
--- a/test/unit/github/runs.test.ts
+++ b/test/unit/github/runs.test.ts
@@ -1,4 +1,4 @@
-import { getCurrentStepName } from '../../../src/github/runs';
+import { getCurrentStepPath } from '../../../src/github/runs';
import { octokit } from '../../../src/github/octokit';
import { githubConfigMock } from '../../.setup/mock';
@@ -14,6 +14,7 @@ describe('postReview', () => {
data: {
jobs: [
{
+ name: 'TICS Client',
runner_name: 'Github Actions 1',
status: 'in_progress',
steps: [
@@ -28,7 +29,8 @@ describe('postReview', () => {
]
},
{
- name: 'Github Actions 2',
+ name: 'TICS Client',
+ runner_name: 'Github Actions 2',
status: 'completed',
steps: [
{
@@ -45,9 +47,9 @@ describe('postReview', () => {
}
});
- const name = await getCurrentStepName();
+ const name = await getCurrentStepPath();
- expect(name).toStrictEqual('Step 2');
+ expect(name).toStrictEqual('tics-client / TICS Client / Step 2');
});
test('Should not return name when multiple steps are in progress', async () => {
@@ -55,6 +57,7 @@ describe('postReview', () => {
data: {
jobs: [
{
+ name: 'TICS',
runner_name: 'Github Actions 1',
status: 'in_progress',
steps: [
@@ -69,7 +72,8 @@ describe('postReview', () => {
]
},
{
- name: 'Github Actions 1',
+ name: 'TICS',
+ runner_name: 'Github Actions 1',
status: 'completed',
steps: [
{
@@ -86,16 +90,16 @@ describe('postReview', () => {
}
});
- const name = await getCurrentStepName();
+ const name = await getCurrentStepPath();
- expect(name).toStrictEqual(githubConfigMock.action);
+ expect(name).toStrictEqual('tics-client / TICS / tics-github-action');
});
test('Should post a notice on createReview', async () => {
listJobsSpy.mockRejectedValue(new Error());
- const name = await getCurrentStepName();
+ const name = await getCurrentStepPath();
- expect(name).toStrictEqual(githubConfigMock.action);
+ expect(name).toStrictEqual('tics-client / TICS / tics-github-action');
});
});
From 6f2512dccd9375c0e94fe9c51c39e01fbb9f8593 Mon Sep 17 00:00:00 2001
From: janssen <118828444+janssen-tiobe@users.noreply.github.com>
Date: Mon, 9 Dec 2024 13:36:34 +0100
Subject: [PATCH 11/11] #34049: Added title to italic tag
---
dist/index.js | 7 ++++---
src/action/decorate/markdown.ts | 4 ++--
src/action/decorate/summary.ts | 3 ++-
test/unit/action/decorate/summary.test.ts | 6 +++---
4 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/dist/index.js b/dist/index.js
index 75c1c290..fb2f2b16 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -107,8 +107,8 @@ function generateExpandableAreaMarkdown(header, body) {
* Generates italic text for markdown.
* @param text The text to make italic.
*/
-function generateItalic(text) {
- return `${text}`;
+function generateItalic(text, title) {
+ return `${text}`;
}
/**
* Generates a hidden comment for markdown.
@@ -296,7 +296,8 @@ function setSummaryHeader(status) {
}
async function setSummaryFooter() {
core_1.summary.addEOL();
- core_1.summary.addRaw((0, markdown_1.generateItalic)(await (0, runs_1.getCurrentStepPath)()), true);
+ core_1.summary.addRaw('');
+ core_1.summary.addRaw((0, markdown_1.generateItalic)(await (0, runs_1.getCurrentStepPath)(), 'Workflow / Job / Step'), true);
core_1.summary.addRaw((0, markdown_1.generateComment)(config_1.githubConfig.getCommentIdentifier()));
}
function getConditionHeading(failedOrWarnConditions) {
diff --git a/src/action/decorate/markdown.ts b/src/action/decorate/markdown.ts
index 195da8a6..68c8a9e8 100644
--- a/src/action/decorate/markdown.ts
+++ b/src/action/decorate/markdown.ts
@@ -35,8 +35,8 @@ export function generateExpandableAreaMarkdown(header: string, body: string): st
* Generates italic text for markdown.
* @param text The text to make italic.
*/
-export function generateItalic(text: string): string {
- return `${text}`;
+export function generateItalic(text: string, title?: string): string {
+ return `${text}`;
}
/**
diff --git a/src/action/decorate/summary.ts b/src/action/decorate/summary.ts
index f360f315..b99d69b4 100644
--- a/src/action/decorate/summary.ts
+++ b/src/action/decorate/summary.ts
@@ -119,7 +119,8 @@ function setSummaryHeader(status: Status) {
async function setSummaryFooter() {
summary.addEOL();
- summary.addRaw(generateItalic(await getCurrentStepPath()), true);
+ summary.addRaw('');
+ summary.addRaw(generateItalic(await getCurrentStepPath(), 'Workflow / Job / Step'), true);
summary.addRaw(generateComment(githubConfig.getCommentIdentifier()));
}
diff --git a/test/unit/action/decorate/summary.test.ts b/test/unit/action/decorate/summary.test.ts
index 2f9bb9de..db0ae2f7 100644
--- a/test/unit/action/decorate/summary.test.ts
+++ b/test/unit/action/decorate/summary.test.ts
@@ -129,7 +129,7 @@ describe('createErrorSummary', () => {
expect(body).toContainTimes('The following warnings have occurred during analysis:
', 1);
expect(body).toContainTimes(':x: Error', 0);
expect(body).toContainTimes(':warning: Warning', 2);
- expect(body).toContainTimes('\ntics-client / TICS / tics-github-action', 1);
+ expect(body).toContainTimes('\ntics-client / TICS / tics-github-action', 1);
expect(body).toContain('\n');
});
@@ -143,7 +143,7 @@ describe('createErrorSummary', () => {
expect(body).toContainTimes('The following warnings have occurred during analysis:
', 1);
expect(body).toContainTimes(':x: Error', 1);
expect(body).toContainTimes(':warning: Warning', 2);
- expect(body).toContainTimes('\ntics-client / TICS / tics-github-action', 1);
+ expect(body).toContainTimes('\ntics-client / TICS / tics-github-action', 1);
expect(body).toContainTimes('\n', 1);
});
});
@@ -152,7 +152,7 @@ describe('createNothingAnalyzedSummaryBody', () => {
test('Should return summary with the message given', async () => {
const body = await createNothingAnalyzedSummaryBody('message');
expect(body).toEqual(
- 'TICS Quality Gate
\n:heavy_check_mark: Passed
\nmessage\ntics-client / TICS / tics-github-action\n'
+ 'TICS Quality Gate
\n:heavy_check_mark: Passed
\nmessage\ntics-client / TICS / tics-github-action\n'
);
});
});