Skip to content

Commit

Permalink
Merge pull request #94 from tiobe/31808-replace_post
Browse files Browse the repository at this point in the history
Replacing conversations previously posted by TICS
  • Loading branch information
wener-tiobe authored Jun 5, 2023
2 parents 1f75161 + b5aeb36 commit f3f3528
Show file tree
Hide file tree
Showing 25 changed files with 2,015 additions and 1,379 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ The following inputs are available for this action:
| `trustStrategy` | Check the validity of certificates. Options are `all`, `self-signed` or `strict`. [Documentation on Client-side SSL/TLS](https://portal.tiobe.com/2022.2/docs/#doc=admin/admin_11_viewer.html%23ssl-wrapper). | false |
| `installTics` | Boolean parameter to install TICS command-line tools on a runner before executing the analysis. If not specified, TICS should be installed manually on the machine that runs this job. | false |
| `mode` | Set the mode to run the action in. Options are `default` for a normal analysis run and `diagnostic` for a diagnostic testing of the setup. | false |
| `postAnnotations` | Show the latest TICS annotations directly in the GitHub Pull Request review. | false |
| `postAnnotations` | Show the latest TICS annotations directly in the GitHub Pull Request review. | false |
| `postToConversation` | Post the summary to the conversation page of the pull request. Options are `true` (default) or `false`. | false |
| `pullRequestApproval` | Set the plugin to approve or deny a pull request, by default this is false. Options are `true` or `false`. Note that once a run that added a reviewer has been completed, this reviewer cannot be deleted from that pull request. (Always the case on versions between 2.0.0 and 2.5.0). | false |
| `secretsFilter` | Comma-seperated list of extra secrets to mask in the console output. | false |
| `ticsAuthToken` | Authentication token to authorize the plugin when it connects to the TICS Viewer. | false |
Expand Down
4 changes: 4 additions & 0 deletions action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ inputs:
description: Show the latest TICS annotations directly in the GitHub Pull Request review.
required: false
default: true
postToConversation:
description: Post the summary to the conversation page of the pull request. Options are `true` (default) or `false`.
required: false
default: true
pullRequestApproval:
description: Set the plugin to approve or deny a pull request, by default this is false. Options are `true` or `false`. Note that once a run that added a reviewer has been completed, this reviewer cannot be deleted from that pull request. (Always the case on versions between 2.0.0 and 2.5.0).
required: false
Expand Down
2,715 changes: 1,441 additions & 1,274 deletions dist/index.js

Large diffs are not rendered by default.

24 changes: 16 additions & 8 deletions src/configuration.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import { getBooleanInput, getInput, isDebug } from '@actions/core';
import { getOctokit } from '@actions/github';
import { getBooleanInput, getInput, isDebug, warning } from '@actions/core';
import * as github from '@actions/github';
import { ProxyAgent } from 'proxy-agent';
import { readFileSync } from 'fs';
import { getTicsWebBaseUrlFromUrl } from './tics/api_helper';
import { EOL } from 'os';

const payload = process.env.GITHUB_EVENT_PATH ? JSON.parse(readFileSync(process.env.GITHUB_EVENT_PATH, 'utf8')) : '';
const pullRequestNumber: number = payload.pull_request ? payload.pull_request.number : '';

export const githubConfig = {
repo: process.env.GITHUB_REPOSITORY ? process.env.GITHUB_REPOSITORY : '',
owner: process.env.GITHUB_REPOSITORY ? process.env.GITHUB_REPOSITORY.split('/')[0] : '',
Expand All @@ -17,10 +13,21 @@ export const githubConfig = {
branchdir: process.env.GITHUB_WORKSPACE ? process.env.GITHUB_WORKSPACE : '',
eventName: process.env.GITHUB_EVENT_NAME ? process.env.GITHUB_EVENT_NAME : '',
runnerOS: process.env.RUNNER_OS ? process.env.RUNNER_OS : '',
pullRequestNumber: process.env.PULL_REQUEST_NUMBER ? parseInt(process.env.PULL_REQUEST_NUMBER) : pullRequestNumber,
pullRequestNumber: getPullRequestNumber(),
debugger: isDebug()
};

function getPullRequestNumber() {
if (github.context.payload.pull_request) {
return github.context.payload.pull_request.number;
} else if (process.env.PULL_REQUEST_NUMBER) {
return parseInt(process.env.PULL_REQUEST_NUMBER);
} else {
warning('Pull request number could not be found');
return 0;
}
}

function getSecretsFilter(secretsFilter: string | undefined) {
const defaults = ['TICSAUTHTOKEN', 'GITHUB_TOKEN', 'Authentication token'];
const keys = secretsFilter ? secretsFilter.split(',').filter(s => s !== '') : [];
Expand Down Expand Up @@ -48,6 +55,7 @@ export const ticsConfig = {
nocalc: getInput('nocalc'),
norecalc: getInput('norecalc'),
postAnnotations: getBooleanInput('postAnnotations'),
postToConversation: getBooleanInput('postToConversation'),
pullRequestApproval: getBooleanInput('pullRequestApproval'),
recalc: getInput('recalc'),
ticsAuthToken: getInput('ticsAuthToken'),
Expand All @@ -57,7 +65,7 @@ export const ticsConfig = {
viewerUrl: getInput('viewerUrl')
};

export const octokit = getOctokit(ticsConfig.githubToken);
export const octokit = github.getOctokit(ticsConfig.githubToken);
export const requestInit = { agent: new ProxyAgent(), headers: {} };
export const baseUrl = getTicsWebBaseUrlFromUrl(ticsConfig.ticsConfiguration);
export const viewerUrl = ticsConfig.viewerUrl ? ticsConfig.viewerUrl.replace(/\/+$/, '') : baseUrl;
13 changes: 9 additions & 4 deletions src/github/calling/annotations.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
import { logger } from '../../helper/logger';
import { githubConfig, octokit } from '../../configuration';
import { ReviewComment } from '../interfaces/interfaces';

/**
* Gets a list of all reviews posted on the pull request.
* @returns List of reviews posted on the pull request.
*/
export async function getPostedReviewComments() {
export async function getPostedReviewComments(): Promise<ReviewComment[]> {
let response: ReviewComment[] = [];
try {
logger.info('Retrieving posted review comments.');
const params = {
owner: githubConfig.owner,
repo: githubConfig.reponame,
pull_number: githubConfig.pullRequestNumber
};
return await octokit.paginate(octokit.rest.pulls.listReviewComments, params);
} catch (error: any) {
logger.error(`Could not retrieve the review comments: ${error.message}`);
response = await octokit.paginate(octokit.rest.pulls.listReviewComments, params);
} catch (error: unknown) {
let message = 'reason unkown';
if (error instanceof Error) message = error.message;
logger.error(`Could not retrieve the review comments: ${message}`);
}
return response;
}
25 changes: 25 additions & 0 deletions src/github/calling/comments.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { logger } from '../../helper/logger';
import { githubConfig, octokit } from '../../configuration';
import { Comment } from '../interfaces/interfaces';

/**
* Gets a list of all comments on the pull request.
* @returns List of comments on the pull request.
*/
export async function getPostedComments(): Promise<Comment[]> {
let response: Comment[] = [];
try {
logger.info('Retrieving posted review comments.');
const params = {
owner: githubConfig.owner,
repo: githubConfig.reponame,
issue_number: githubConfig.pullRequestNumber
};
response = await octokit.paginate(octokit.rest.issues.listComments, params);
} catch (error: unknown) {
let message = 'reason unkown';
if (error instanceof Error) message = error.message;
logger.error(`Could not retrieve the comments: ${message}`);
}
return response;
}
6 changes: 4 additions & 2 deletions src/github/calling/pulls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ export async function getChangedFiles(): Promise<ChangedFile[] | undefined> {
logger.info('Retrieved changed files.');
return response;
} catch (error: unknown) {
logger.exit(`Could not retrieve the changed files: ${error}`);
let message = 'error unknown';
if (error instanceof Error) message = error.message;
logger.exit(`Could not retrieve the changed files: ${message}`);
}
}

Expand All @@ -46,7 +48,7 @@ export async function getChangedFiles(): Promise<ChangedFile[] | undefined> {
* @param changedFiles List of changed files.
* @returns Location of the written file.
*/
export function changedFilesToFile(changedFiles: any[]): string {
export function changedFilesToFile(changedFiles: ChangedFile[]): string {
logger.header('Writing changedFiles to file');

let contents = '';
Expand Down
122 changes: 122 additions & 0 deletions src/github/interfaces/interfaces.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
type Side = 'LEFT' | 'RIGHT';
type AuthorAssociation = 'COLLABORATOR' | 'CONTRIBUTOR' | 'FIRST_TIMER' | 'FIRST_TIME_CONTRIBUTOR' | 'MANNEQUIN' | 'MEMBER' | 'NONE' | 'OWNER';

interface User {
name?: string | null;
email?: string | null;
login: string;
id: number;
node_id: string;
avatar_url: string;
gravatar_id: string | null;
url: string;
html_url: string;
followers_url: string;
following_url: string;
gists_url: string;
starred_url: string;
subscriptions_url: string;
organizations_url: string;
repos_url: string;
events_url: string;
received_events_url: string;
type: string;
site_admin: boolean;
starred_at?: string;
}

interface Reactions {
url: string;
total_count: number;
'+1': number;
'-1': number;
laugh: number;
confused: number;
heart: number;
hooray: number;
eyes: number;
rocket: number;
}

interface Link {
href: string;
}

interface Links {
self: Link;
html: Link;
pull_request: Link;
}

interface GitHubApp {
id: number;
slug?: string;
node_id: string;
owner: User | null;
name: string;
description?: string | null;
external_url: string;
html_url: string;
created_at: string;
updated_at: string;
permissions: {
issues?: string;
checks?: string;
metadata?: string;
contents?: string;
deployments?: string;
};
events: string[];
installations_count?: number;
client_id?: string;
client_secret?: string;
webhook_secret?: string | null;
pem?: string;
}

export interface ReviewComment {
url: string;
pull_request_review_id: number | null;
id: number;
node_id: string;
diff_hunk: string;
path: string;
position: number;
original_position: number;
commit_id: string;
original_commit_id: string;
in_reply_to_id?: number;
user: User;
body: string;
created_at: string;
updated_at: string;
html_url: string;
pull_request_url: string;
author_association: AuthorAssociation;
_links: Links;
start_line?: number | null;
original_start_line?: number | null;
start_side?: Side | null;
line?: number;
original_line?: number;
side?: Side;
reactions?: Reactions;
body_html?: string;
body_text?: string;
}

export interface Comment {
url: string;
html_url: string;
issue_url: string;
id: number;
node_id: string;
user: User | null;
created_at: string;
updated_at: string;
body?: string;
body_text?: string;
body_html?: string;
reactions?: Reactions;
performed_via_github_app?: GitHubApp | null;
}
11 changes: 7 additions & 4 deletions src/github/posting/annotations.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { logger } from '../../helper/logger';
import { githubConfig, octokit } from '../../configuration';
import { ReviewComments } from '../../helper/interfaces';
import { ReviewComment } from '../interfaces/interfaces';

/**
* Deletes the review comments of previous runs.
* @param postedReviewComments Previously posted review comments.
*/
export async function deletePreviousReviewComments(postedReviewComments: any[]) {
export function deletePreviousReviewComments(postedReviewComments: ReviewComment[]): void {
logger.header('Deleting review comments of previous runs.');
postedReviewComments.map(async reviewComment => {
if (reviewComment.body.substring(0, 17) === ':warning: **TICS:') {
Expand All @@ -17,15 +18,17 @@ export async function deletePreviousReviewComments(postedReviewComments: any[])
comment_id: reviewComment.id
};
await octokit.rest.pulls.deleteReviewComment(params);
} catch (error: any) {
logger.error(`Could not delete review comment: ${error.message}`);
} catch (error: unknown) {
let message = 'reason unkown';
if (error instanceof Error) message = error.message;
logger.error(`Could not delete review comment: ${message}`);
}
}
});
logger.info('Deleted review comments of previous runs.');
}

export async function postAnnotations(reviewComments: ReviewComments) {
export function postAnnotations(reviewComments: ReviewComments): void {
logger.header('Posting annotations.');
reviewComments.postable.forEach(reviewComment => {
logger.warning(reviewComment.body, {
Expand Down
38 changes: 37 additions & 1 deletion src/github/posting/comment.ts → src/github/posting/comments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Analysis } from '../../helper/interfaces';
import { createErrorSummary } from '../../helper/summary';
import { generateStatusMarkdown } from '../../helper/markdown';
import { Status } from '../../helper/enums';
import { Comment } from '../interfaces/interfaces';

/**
* Create error comment on the pull request from the analysis given.
Expand All @@ -20,7 +21,7 @@ export async function postErrorComment(analysis: Analysis): Promise<void> {
* @param message Message to display in the body of the comment.
*/
export async function postNothingAnalyzedComment(message: string): Promise<void> {
const body = `## TICS Analysis\n\n### ${generateStatusMarkdown(Status.PASSED, true)}\n\n${message}`;
const body = `<h1>TICS Quality Gate</h1>\n\n### ${generateStatusMarkdown(Status.PASSED, true)}\n\n${message}`;

await postComment(body);
}
Expand All @@ -47,3 +48,38 @@ export async function postComment(body: string): Promise<void> {
logger.error(`Posting the comment failed: ${message}`);
}
}

export function deletePreviousComments(comments: Comment[]): void {
logger.header('Deleting comments of previous runs.');
comments.map(async comment => {
if (commentIncludesTicsTitle(comment.body)) {
try {
const params = {
owner: githubConfig.owner,
repo: githubConfig.reponame,
comment_id: comment.id
};
await octokit.rest.issues.deleteComment(params);
} catch (error: unknown) {
let message = 'reason unkown';
if (error instanceof Error) message = error.message;
logger.error(`Removing a comment failed: ${message}`);
}
}
});
logger.info('Deleted review comments of previous runs.');
}

function commentIncludesTicsTitle(body?: string): boolean {
const titles = ['<h1>TICS Quality Gate</h1>', '## TICS Quality Gate', '## TICS Analysis'];

if (!body) return false;

let includesTitle = false;

titles.forEach(title => {
if (body.startsWith(title)) includesTitle = true;
});

return includesTitle;
}
Loading

0 comments on commit f3f3528

Please sign in to comment.