mirror of
https://github.com/mshick/add-pr-comment.git
synced 2025-12-31 14:20:32 +11:00
build(refactor): better project organization
This commit is contained in:
parent
5cd99bf9c1
commit
e2229d7f55
14 changed files with 9869 additions and 74 deletions
45
.eslintrc.js
Normal file
45
.eslintrc.js
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
module.exports = {
|
||||
root: true,
|
||||
extends: ['eslint:recommended', 'plugin:prettier/recommended', 'plugin:import/errors', 'plugin:import/warnings'],
|
||||
plugins: ['prettier'],
|
||||
env: {
|
||||
node: true,
|
||||
es6: true,
|
||||
},
|
||||
parserOptions: {
|
||||
ecmaVersion: 2018,
|
||||
},
|
||||
settings: {
|
||||
'import/parsers': {
|
||||
'@typescript-eslint/parser': ['.ts', '.tsx'],
|
||||
},
|
||||
'import/resolver': {
|
||||
typescript: {
|
||||
alwaysTryTypes: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ['**/*.ts'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: ['@typescript-eslint'],
|
||||
extends: [
|
||||
'plugin:import/typescript',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'prettier/@typescript-eslint',
|
||||
'plugin:prettier/recommended',
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 2018,
|
||||
project: ['tsconfig.json'],
|
||||
sourceType: 'module',
|
||||
tsconfigRootDir: __dirname,
|
||||
},
|
||||
env: {
|
||||
node: true,
|
||||
es6: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
{
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"plugins": ["@typescript-eslint", "prettier"],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"prettier/@typescript-eslint",
|
||||
"plugin:prettier/recommended"
|
||||
],
|
||||
"rules": {
|
||||
"prettier/prettier": [
|
||||
"error",
|
||||
{
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"bracketSpacing": false,
|
||||
"printWidth": 120,
|
||||
"tabWidth": 2,
|
||||
"semi": false
|
||||
}
|
||||
],
|
||||
"camelcase": "off",
|
||||
"@typescript-eslint/camelcase": "off",
|
||||
"@typescript-eslint/no-non-null-assertion": "off"
|
||||
},
|
||||
"env": {
|
||||
"node": true,
|
||||
"jest": true,
|
||||
"es6": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2018,
|
||||
"sourceType": "module"
|
||||
}
|
||||
}
|
||||
9
.prettierrc.js
Normal file
9
.prettierrc.js
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
module.exports = {
|
||||
arrowParens: 'avoid',
|
||||
bracketSpacing: false,
|
||||
printWidth: 100,
|
||||
semi: false,
|
||||
singleQuote: true,
|
||||
tabWidth: 2,
|
||||
trailingComma: 'es5',
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
{
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"bracketSpacing": false,
|
||||
"printWidth": 120,
|
||||
"tabWidth": 2,
|
||||
"semi": false
|
||||
}
|
||||
|
|
@ -4,18 +4,19 @@ import * as core from '@actions/core'
|
|||
import * as github from '@actions/github'
|
||||
import {WebhookPayload} from '@actions/github/lib/interfaces'
|
||||
import nock from 'nock'
|
||||
import run from '../add-pr-comment'
|
||||
import apiResponse from '../docs/sample-pulls-api-response.json'
|
||||
import run from '../src/main'
|
||||
import apiResponse from './sample-pulls-api-response.json'
|
||||
|
||||
const repoFullName = 'foo/bar'
|
||||
const repoToken = '12345'
|
||||
const userLogin = 'github-actions[bot]'
|
||||
const commitSha = 'abc123'
|
||||
let issueNumber = 1
|
||||
const simpleMessage = 'hello world'
|
||||
const multilineMessage = fs.readFileSync(path.resolve(__dirname, './message-windows.txt')).toString()
|
||||
const multilineMessageWindows = fs.readFileSync(path.resolve(__dirname, './message-windows.txt')).toString()
|
||||
|
||||
let issueNumber = 1
|
||||
|
||||
const inputs = {
|
||||
message: '',
|
||||
'repo-token': '',
|
||||
|
|
|
|||
9574
dist/index.js
vendored
9574
dist/index.js
vendored
File diff suppressed because one or more lines are too long
|
|
@ -1,16 +1,9 @@
|
|||
const processStdoutWrite = process.stdout.write.bind(process.stdout)
|
||||
process.stdout.write = (str, encoding, cb) => {
|
||||
if (!str.match(/^##/)) {
|
||||
return processStdoutWrite(str, encoding, cb)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
clearMocks: true,
|
||||
moduleFileExtensions: ['js', 'ts'],
|
||||
testEnvironment: 'node',
|
||||
testMatch: ['**/*.test.ts'],
|
||||
testRunner: 'jest-circus/runner',
|
||||
transform: {
|
||||
'^.+\\.ts$': 'ts-jest',
|
||||
},
|
||||
|
|
|
|||
139
lib/main.js
Normal file
139
lib/main.js
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const core = __importStar(require("@actions/core"));
|
||||
const github = __importStar(require("@actions/github"));
|
||||
const http_client_1 = require("@actions/http-client");
|
||||
const listCommitPulls = async (params) => {
|
||||
const { repoToken, owner, repo, commitSha } = params;
|
||||
const http = new http_client_1.HttpClient('http-client-add-pr-comment');
|
||||
const additionalHeaders = {
|
||||
accept: 'application/vnd.github.groot-preview+json',
|
||||
authorization: `token ${repoToken}`,
|
||||
};
|
||||
const body = await http.getJson(`https://api.github.com/repos/${owner}/${repo}/commits/${commitSha}/pulls`, additionalHeaders);
|
||||
return body.result;
|
||||
};
|
||||
const getIssueNumberFromCommitPullsList = (commitPullsList) => (commitPullsList.length ? commitPullsList[0].number : null);
|
||||
const createCommentProxy = async (params) => {
|
||||
const { repoToken, owner, repo, issueNumber, body, proxyUrl } = params;
|
||||
const http = new http_client_1.HttpClient('http-client-add-pr-comment');
|
||||
const response = await http.postJson(`${proxyUrl}/repos/${owner}/${repo}/issues/${issueNumber}/comments`, { body }, {
|
||||
['temporary-github-token']: repoToken,
|
||||
});
|
||||
return response.result;
|
||||
};
|
||||
const isMessagePresent = (message, comments, login) => {
|
||||
const cleanRe = new RegExp('\\R|\\s', 'g');
|
||||
const messageClean = message.replace(cleanRe, '');
|
||||
return comments.some(({ user, body }) => {
|
||||
// If a username is provided we can save on a bit of processing
|
||||
if (login && user.login !== login) {
|
||||
return false;
|
||||
}
|
||||
return body.replace(cleanRe, '') === messageClean;
|
||||
});
|
||||
};
|
||||
const getInputs = () => {
|
||||
return {
|
||||
allowRepeats: Boolean(core.getInput('allow-repeats') === 'true'),
|
||||
message: core.getInput('message'),
|
||||
proxyUrl: core.getInput('proxy-url').replace(/\/$/, ''),
|
||||
repoToken: core.getInput('repo-token') || process.env['GITHUB_TOKEN'],
|
||||
repoTokenUserLogin: core.getInput('repo-token-user-login'),
|
||||
};
|
||||
};
|
||||
const run = async () => {
|
||||
try {
|
||||
const { allowRepeats, message, repoToken, repoTokenUserLogin, proxyUrl } = getInputs();
|
||||
if (!repoToken) {
|
||||
throw new Error('no github token provided, set one with the repo-token input or GITHUB_TOKEN env variable');
|
||||
}
|
||||
const { payload: { pull_request: pullRequest, repository }, sha: commitSha, } = github.context;
|
||||
if (!repository) {
|
||||
core.info('unable to determine repository from request type');
|
||||
core.setOutput('comment-created', 'false');
|
||||
return;
|
||||
}
|
||||
const { full_name: repoFullName } = repository;
|
||||
const [owner, repo] = repoFullName.split('/');
|
||||
let issueNumber;
|
||||
if (pullRequest && pullRequest.number) {
|
||||
issueNumber = pullRequest.number;
|
||||
}
|
||||
else {
|
||||
// If this is not a pull request, attempt to find a PR matching the sha
|
||||
const commitPullsList = await listCommitPulls({ repoToken, owner, repo, commitSha });
|
||||
issueNumber = commitPullsList && getIssueNumberFromCommitPullsList(commitPullsList);
|
||||
}
|
||||
if (!issueNumber) {
|
||||
core.info('this action only works on pull_request events or other commits associated with a pull');
|
||||
core.setOutput('comment-created', 'false');
|
||||
return;
|
||||
}
|
||||
const octokit = github.getOctokit(repoToken);
|
||||
let shouldCreateComment = true;
|
||||
if (!allowRepeats) {
|
||||
core.debug('repeat comments are disallowed, checking for existing');
|
||||
const { data: comments } = await octokit.issues.listComments({
|
||||
owner,
|
||||
repo,
|
||||
issue_number: issueNumber,
|
||||
});
|
||||
if (isMessagePresent(message, comments, repoTokenUserLogin)) {
|
||||
core.info('the issue already contains an identical message');
|
||||
shouldCreateComment = false;
|
||||
}
|
||||
}
|
||||
if (shouldCreateComment) {
|
||||
if (proxyUrl) {
|
||||
await createCommentProxy({
|
||||
owner,
|
||||
repo,
|
||||
issueNumber,
|
||||
body: message,
|
||||
repoToken,
|
||||
proxyUrl,
|
||||
});
|
||||
}
|
||||
else {
|
||||
await octokit.issues.createComment({
|
||||
owner,
|
||||
repo,
|
||||
issue_number: issueNumber,
|
||||
body: message,
|
||||
});
|
||||
}
|
||||
core.setOutput('comment-created', 'true');
|
||||
}
|
||||
else {
|
||||
core.setOutput('comment-created', 'false');
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
core.setFailed(error.message);
|
||||
}
|
||||
};
|
||||
// Don't auto-execute in the test environment
|
||||
if (process.env['NODE_ENV'] !== 'test') {
|
||||
run();
|
||||
}
|
||||
exports.default = run;
|
||||
68
package-lock.json
generated
68
package-lock.json
generated
|
|
@ -1896,6 +1896,12 @@
|
|||
"integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
|
||||
"dev": true
|
||||
},
|
||||
"dedent": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
|
||||
"integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=",
|
||||
"dev": true
|
||||
},
|
||||
"deep-is": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
|
||||
|
|
@ -3342,6 +3348,68 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"jest-circus": {
|
||||
"version": "26.1.0",
|
||||
"resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-26.1.0.tgz",
|
||||
"integrity": "sha512-V5h5XJLPf0XXwP92GIOx8n0Q6vdPDcFPBuEVQ9/OPzpsx3gquL8fdxaJGZ5TsvkU3zWM7mDWULAKYJMRkA2e+g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/traverse": "^7.1.0",
|
||||
"@jest/environment": "^26.1.0",
|
||||
"@jest/test-result": "^26.1.0",
|
||||
"@jest/types": "^26.1.0",
|
||||
"chalk": "^4.0.0",
|
||||
"co": "^4.6.0",
|
||||
"dedent": "^0.7.0",
|
||||
"expect": "^26.1.0",
|
||||
"is-generator-fn": "^2.0.0",
|
||||
"jest-each": "^26.1.0",
|
||||
"jest-matcher-utils": "^26.1.0",
|
||||
"jest-message-util": "^26.1.0",
|
||||
"jest-runtime": "^26.1.0",
|
||||
"jest-snapshot": "^26.1.0",
|
||||
"jest-util": "^26.1.0",
|
||||
"pretty-format": "^26.1.0",
|
||||
"stack-utils": "^2.0.2",
|
||||
"throat": "^5.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@jest/types": {
|
||||
"version": "26.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@jest/types/-/types-26.1.0.tgz",
|
||||
"integrity": "sha512-GXigDDsp6ZlNMhXQDeuy/iYCDsRIHJabWtDzvnn36+aqFfG14JmFV0e/iXxY4SP9vbXSiPNOWdehU5MeqrYHBQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/istanbul-lib-coverage": "^2.0.0",
|
||||
"@types/istanbul-reports": "^1.1.1",
|
||||
"@types/yargs": "^15.0.0",
|
||||
"chalk": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
|
||||
"integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
}
|
||||
},
|
||||
"pretty-format": {
|
||||
"version": "26.1.0",
|
||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.1.0.tgz",
|
||||
"integrity": "sha512-GmeO1PEYdM+non4BKCj+XsPJjFOJIPnsLewqhDVoqY1xo0yNmDas7tC2XwpMrRAHR3MaE2hPo37deX5OisJ2Wg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@jest/types": "^26.1.0",
|
||||
"ansi-regex": "^5.0.0",
|
||||
"ansi-styles": "^4.0.0",
|
||||
"react-is": "^16.12.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"jest-config": {
|
||||
"version": "26.1.0",
|
||||
"resolved": "https://registry.npmjs.org/jest-config/-/jest-config-26.1.0.tgz",
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
"name": "@mshick/add-pr-comment",
|
||||
"version": "1.0.0",
|
||||
"description": "A GitHub Action which adds a comment to a Pull Request Issue.",
|
||||
"main": "dist/index.js",
|
||||
"main": "lib/main.js",
|
||||
"scripts": {
|
||||
"build": "tsc --noEmit && ncc build add-pr-comment.ts -o dist -m",
|
||||
"build": "tsc && ncc build lib/main.js",
|
||||
"lint": "eslint . --ext .ts",
|
||||
"test": "tsc --noEmit && jest",
|
||||
"test": "jest",
|
||||
"clean": "rm -rf node_modules dist package-lock.json __tests__/runner/**/*"
|
||||
},
|
||||
"repository": {
|
||||
|
|
@ -43,6 +43,7 @@
|
|||
"eslint-config-prettier": "^6.11.0",
|
||||
"eslint-plugin-prettier": "^3.1.4",
|
||||
"jest": "^26.1.0",
|
||||
"jest-circus": "^26.1.0",
|
||||
"nock": "^13.0.2",
|
||||
"prettier": "^2.0.5",
|
||||
"ts-jest": "^26.1.1",
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import * as github from '@actions/github'
|
|||
import {HttpClient} from '@actions/http-client'
|
||||
import {Endpoints, RequestHeaders, IssuesListCommentsResponseData} from '@octokit/types'
|
||||
|
||||
type ListCommitPullsResponse = Endpoints['GET /repos/:owner/:repo/commits/:commit_sha/pulls']['response']['data']
|
||||
type ListCommitPullsResponseData = Endpoints['GET /repos/:owner/:repo/commits/:commit_sha/pulls']['response']['data']
|
||||
type CreateIssueCommentResponseData = Endpoints['POST /repos/:owner/:repo/issues/:issue_number/comments']['response']['data']
|
||||
|
||||
interface ListCommitPullsParams {
|
||||
|
|
@ -13,7 +13,9 @@ interface ListCommitPullsParams {
|
|||
commitSha: string
|
||||
}
|
||||
|
||||
const listCommitPulls = async (params: ListCommitPullsParams): Promise<ListCommitPullsResponse | null> => {
|
||||
const listCommitPulls = async (
|
||||
params: ListCommitPullsParams
|
||||
): Promise<ListCommitPullsResponseData | null> => {
|
||||
const {repoToken, owner, repo, commitSha} = params
|
||||
|
||||
const http = new HttpClient('http-client-add-pr-comment')
|
||||
|
|
@ -23,16 +25,17 @@ const listCommitPulls = async (params: ListCommitPullsParams): Promise<ListCommi
|
|||
authorization: `token ${repoToken}`,
|
||||
}
|
||||
|
||||
const body = await http.getJson<ListCommitPullsResponse>(
|
||||
const body = await http.getJson<ListCommitPullsResponseData>(
|
||||
`https://api.github.com/repos/${owner}/${repo}/commits/${commitSha}/pulls`,
|
||||
additionalHeaders,
|
||||
additionalHeaders
|
||||
)
|
||||
|
||||
return body.result
|
||||
}
|
||||
|
||||
const getIssueNumberFromCommitPullsList = (commitPullsList: ListCommitPullsResponse): number | null =>
|
||||
commitPullsList.length ? commitPullsList[0].number : null
|
||||
const getIssueNumberFromCommitPullsList = (
|
||||
commitPullsList: ListCommitPullsResponseData
|
||||
): number | null => (commitPullsList.length ? commitPullsList[0].number : null)
|
||||
|
||||
interface CreateCommentProxyParams {
|
||||
repoToken: string
|
||||
|
|
@ -43,7 +46,9 @@ interface CreateCommentProxyParams {
|
|||
proxyUrl: string
|
||||
}
|
||||
|
||||
const createCommentProxy = async (params: CreateCommentProxyParams): Promise<CreateIssueCommentResponseData | null> => {
|
||||
const createCommentProxy = async (
|
||||
params: CreateCommentProxyParams
|
||||
): Promise<CreateIssueCommentResponseData | null> => {
|
||||
const {repoToken, owner, repo, issueNumber, body, proxyUrl} = params
|
||||
|
||||
const http = new HttpClient('http-client-add-pr-comment')
|
||||
|
|
@ -53,7 +58,7 @@ const createCommentProxy = async (params: CreateCommentProxyParams): Promise<Cre
|
|||
{body},
|
||||
{
|
||||
['temporary-github-token']: repoToken,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
return response.result
|
||||
|
|
@ -62,7 +67,7 @@ const createCommentProxy = async (params: CreateCommentProxyParams): Promise<Cre
|
|||
const isMessagePresent = (
|
||||
message: AddPrCommentInputs['message'],
|
||||
comments: IssuesListCommentsResponseData,
|
||||
login?: string,
|
||||
login?: string
|
||||
): boolean => {
|
||||
const cleanRe = new RegExp('\\R|\\s', 'g')
|
||||
const messageClean = message.replace(cleanRe, '')
|
||||
|
|
@ -100,7 +105,9 @@ const run = async (): Promise<void> => {
|
|||
const {allowRepeats, message, repoToken, repoTokenUserLogin, proxyUrl} = getInputs()
|
||||
|
||||
if (!repoToken) {
|
||||
throw new Error('no github token provided, set one with the repo-token input or GITHUB_TOKEN env variable')
|
||||
throw new Error(
|
||||
'no github token provided, set one with the repo-token input or GITHUB_TOKEN env variable'
|
||||
)
|
||||
}
|
||||
|
||||
const {
|
||||
|
|
@ -128,7 +135,9 @@ const run = async (): Promise<void> => {
|
|||
}
|
||||
|
||||
if (!issueNumber) {
|
||||
core.info('this action only works on pull_request events or other commits associated with a pull')
|
||||
core.info(
|
||||
'this action only works on pull_request events or other commits associated with a pull'
|
||||
)
|
||||
core.setOutput('comment-created', 'false')
|
||||
return
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "esnext",
|
||||
"lib": ["es2015", "es2017"],
|
||||
"target": "ES2018",
|
||||
"lib": ["ES2020"],
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
|
|
@ -11,8 +11,9 @@
|
|||
"noImplicitAny": true,
|
||||
"removeComments": false,
|
||||
"preserveConstEnums": true,
|
||||
"resolveJsonModule": true
|
||||
"resolveJsonModule": true,
|
||||
"rootDir": "./src",
|
||||
"outDir": "./lib"
|
||||
},
|
||||
"include": ["**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
"exclude": ["node_modules", "**/*.test.ts"]
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue