mirror of
https://github.com/marocchino/sticky-pull-request-comment.git
synced 2025-12-13 04:01:14 +00:00
feat: actual logic
This commit is contained in:
parent
29d48cbb29
commit
cb9470fc12
9 changed files with 108 additions and 147 deletions
13
.github/workflows/comment_on_pull_request.yml
vendored
Normal file
13
.github/workflows/comment_on_pull_request.yml
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
name: Comment on Pull Request
|
||||||
|
on:
|
||||||
|
- pull_request
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: ./
|
||||||
|
with:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
message: |
|
||||||
|
Test ${{ github.sha }} is successfully ended.
|
||||||
14
.github/workflows/test.yml
vendored
14
.github/workflows/test.yml
vendored
|
|
@ -1,20 +1,16 @@
|
||||||
name: "Test typescript-action"
|
name: test
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
- 'releases/*'
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v1
|
||||||
|
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- run: npm run build
|
- run: npm run build
|
||||||
- run: npm test
|
- run: npm test
|
||||||
- uses: ./
|
|
||||||
with:
|
|
||||||
milliseconds: 1000
|
|
||||||
|
|
|
||||||
74
README.md
74
README.md
|
|
@ -1,28 +1,23 @@
|
||||||
# Create a JavaScript Action using TypeScript
|
# Sticky Pull Request Comment
|
||||||
|
|
||||||
Use this template to bootstrap the creation of a JavaScript action.:rocket:
|
Create comment on pull request, if exists update that comment.
|
||||||
|
|
||||||
This template includes compilication support, tests, a validation workflow, publishing, and versioning guidance.
|
## Development
|
||||||
|
|
||||||
If you are new, there's also a simpler introduction. See the [Hello World JavaScript Action](https://github.com/actions/hello-world-javascript-action)
|
Install the dependencies
|
||||||
|
|
||||||
## Create an action from this template
|
|
||||||
|
|
||||||
Click the `Use this Template` and provide the new repo details for your action
|
|
||||||
|
|
||||||
## Code in Master
|
|
||||||
|
|
||||||
Install the dependencies
|
|
||||||
```bash
|
```bash
|
||||||
$ npm install
|
$ npm install
|
||||||
```
|
```
|
||||||
|
|
||||||
Build the typescript
|
Build the typescript
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ npm run build
|
$ npm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
Run the tests :heavy_check_mark:
|
Run the tests :heavy_check_mark:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ npm test
|
$ npm test
|
||||||
|
|
||||||
|
|
@ -34,41 +29,12 @@ $ npm test
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
## Change action.yml
|
|
||||||
|
|
||||||
The action.yml contains defines the inputs and output for your action.
|
|
||||||
|
|
||||||
Update the action.yml with your name, description, inputs and outputs for your action.
|
|
||||||
|
|
||||||
See the [documentation](https://help.github.com/en/articles/metadata-syntax-for-github-actions)
|
|
||||||
|
|
||||||
## Change the Code
|
|
||||||
|
|
||||||
Most toolkit and CI/CD operations involve async operations so the action is run in an async function.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
import * as core from '@actions/core';
|
|
||||||
...
|
|
||||||
|
|
||||||
async function run() {
|
|
||||||
try {
|
|
||||||
...
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
core.setFailed(error.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
run()
|
|
||||||
```
|
|
||||||
|
|
||||||
See the [toolkit documentation](https://github.com/actions/toolkit/blob/master/README.md#packages) for the various packages.
|
|
||||||
|
|
||||||
## Publish to a distribution branch
|
## Publish to a distribution branch
|
||||||
|
|
||||||
Actions are run from GitHub repos. We will create a releases branch and only checkin production modules (core in this case).
|
Actions are run from GitHub repos. We will create a releases branch and only checkin production modules (core in this case).
|
||||||
|
|
||||||
Comment out node_modules in .gitignore and create a releases/v1 branch
|
Comment out node_modules in .gitignore and create a releases/v1 branch
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# comment out in distribution branches
|
# comment out in distribution branches
|
||||||
# node_modules/
|
# node_modules/
|
||||||
|
|
@ -86,28 +52,16 @@ $ git commit -a -m "prod dependencies"
|
||||||
$ git push origin releases/v1
|
$ git push origin releases/v1
|
||||||
```
|
```
|
||||||
|
|
||||||
Your action is now published! :rocket:
|
Your action is now published! :rocket:
|
||||||
|
|
||||||
See the [versioning documentation](https://github.com/actions/toolkit/blob/master/docs/action-versioning.md)
|
See the [versioning documentation](https://github.com/actions/toolkit/blob/master/docs/action-versioning.md)
|
||||||
|
|
||||||
## Validate
|
|
||||||
|
|
||||||
You can now validate the action by referencing the releases/v1 branch
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
uses: actions/typescript-action@releases/v1
|
|
||||||
with:
|
|
||||||
milliseconds: 1000
|
|
||||||
```
|
|
||||||
|
|
||||||
See the [actions tab](https://github.com/actions/javascript-action/actions) for runs of this action! :rocket:
|
|
||||||
|
|
||||||
## Usage:
|
## Usage:
|
||||||
|
|
||||||
After testing you can [create a v1 tag](https://github.com/actions/toolkit/blob/master/docs/action-versioning.md) to reference the stable and tested action
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
uses: actions/typescript-action@v1
|
uses: marocchino/sticky-pull-request-comment@v1
|
||||||
with:
|
with:
|
||||||
milliseconds: 1000
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
message: |
|
||||||
|
Release ${{ github.sha }} to <https://pr-${{ github.event.number }}.example.com>
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,2 @@
|
||||||
import {wait} from '../src/wait'
|
test("create a comment when no comment", async () => {});
|
||||||
import * as process from 'process'
|
test("update a comment when comment is exists", async () => {});
|
||||||
import * as cp from 'child_process'
|
|
||||||
import * as path from 'path'
|
|
||||||
|
|
||||||
test('throws invalid number', async() => {
|
|
||||||
const input = parseInt('foo', 10);
|
|
||||||
await expect(wait(input)).rejects.toThrow('milleseconds not a number');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('wait 500 ms', async() => {
|
|
||||||
const start = new Date();
|
|
||||||
await wait(500);
|
|
||||||
const end = new Date();
|
|
||||||
var delta = Math.abs(end.getTime() - start.getTime());
|
|
||||||
expect(delta).toBeGreaterThan(450);
|
|
||||||
});
|
|
||||||
|
|
||||||
// shows how the runner will run a javascript action with env / stdout protocol
|
|
||||||
test('test runs', () => {
|
|
||||||
process.env['INPUT_MILLISECONDS'] = '500';
|
|
||||||
const ip = path.join(__dirname, '..', 'lib', 'main.js');
|
|
||||||
const options: cp.ExecSyncOptions = {
|
|
||||||
env: process.env
|
|
||||||
};
|
|
||||||
console.log(cp.execSync(`node ${ip}`, options).toString());
|
|
||||||
});
|
|
||||||
|
|
|
||||||
17
action.yml
17
action.yml
|
|
@ -1,10 +1,11 @@
|
||||||
name: 'Your name here'
|
name: "Your name here"
|
||||||
description: 'Provide a description here'
|
description: "Provide a description here"
|
||||||
author: 'Your name or organization here'
|
author: "Your name or organization here"
|
||||||
inputs:
|
inputs:
|
||||||
myInput: # change this
|
message:
|
||||||
description: 'input description here'
|
description: "comment message"
|
||||||
default: 'default value if applicable'
|
GITHUB_TOKEN:
|
||||||
|
description: "set secrets.GITHUB_TOKEN here"
|
||||||
runs:
|
runs:
|
||||||
using: 'node12'
|
using: "node12"
|
||||||
main: 'lib/main.js'
|
main: "lib/main.js"
|
||||||
|
|
|
||||||
38
lib/main.js
38
lib/main.js
|
|
@ -1,9 +1,10 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
@ -16,19 +17,36 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
const core = __importStar(require("@actions/core"));
|
const core = __importStar(require("@actions/core"));
|
||||||
const wait_1 = require("./wait");
|
const github_1 = require("@actions/github");
|
||||||
function run() {
|
function run() {
|
||||||
|
var _a, _b, _c;
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
try {
|
try {
|
||||||
const ms = core.getInput('milliseconds');
|
const repo = github_1.context.repo;
|
||||||
console.log(`Waiting ${ms} milliseconds ...`);
|
const issue_number = (_c = (_b = (_a = github_1.context) === null || _a === void 0 ? void 0 : _a.payload) === null || _b === void 0 ? void 0 : _b.pull_request) === null || _c === void 0 ? void 0 : _c.number;
|
||||||
core.debug((new Date()).toTimeString());
|
if (!issue_number) {
|
||||||
wait_1.wait(parseInt(ms));
|
core.setFailed("This action only works for pull_request");
|
||||||
core.debug((new Date()).toTimeString());
|
return;
|
||||||
core.setOutput('time', new Date().toTimeString());
|
}
|
||||||
|
const body = core.getInput("message");
|
||||||
|
const githubToken = core.getInput("GITHUB_TOKEN");
|
||||||
|
if (!body || !githubToken) {
|
||||||
|
core.setFailed("invalid input: please check your workflow");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const octokit = new github_1.GitHub(githubToken);
|
||||||
|
const { data: comments } = yield octokit.issues.listComments(Object.assign(Object.assign({}, repo), { issue_number }));
|
||||||
|
const myComment = comments.find(comment => comment.user.login === "github-actions[bot]");
|
||||||
|
if (myComment) {
|
||||||
|
yield octokit.issues.updateComment(Object.assign(Object.assign({}, repo), { comment_id: myComment.id, body }));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
yield octokit.issues.createComment(Object.assign(Object.assign({}, repo), { issue_number,
|
||||||
|
body }));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch ({ message }) {
|
||||||
core.setFailed(error.message);
|
core.setFailed(message);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
11
lib/wait.js
11
lib/wait.js
|
|
@ -1,11 +0,0 @@
|
||||||
"use strict";
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
function wait(milliseconds) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (typeof (milliseconds) !== 'number') {
|
|
||||||
throw new Error('milleseconds not a number');
|
|
||||||
}
|
|
||||||
setTimeout(() => resolve("done!"), milliseconds);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
exports.wait = wait;
|
|
||||||
49
src/main.ts
49
src/main.ts
|
|
@ -1,18 +1,43 @@
|
||||||
import * as core from '@actions/core';
|
import * as core from "@actions/core";
|
||||||
import {wait} from './wait'
|
import { context, GitHub } from "@actions/github";
|
||||||
|
|
||||||
async function run() {
|
async function run() {
|
||||||
try {
|
try {
|
||||||
const ms = core.getInput('milliseconds');
|
const repo = context.repo;
|
||||||
console.log(`Waiting ${ms} milliseconds ...`)
|
const issue_number = context?.payload?.pull_request?.number;
|
||||||
|
if (!issue_number) {
|
||||||
core.debug((new Date()).toTimeString())
|
core.setFailed("This action only works for pull_request");
|
||||||
await wait(parseInt(ms, 10));
|
return;
|
||||||
core.debug((new Date()).toTimeString())
|
}
|
||||||
|
const body = core.getInput("message");
|
||||||
core.setOutput('time', new Date().toTimeString());
|
const githubToken = core.getInput("GITHUB_TOKEN");
|
||||||
} catch (error) {
|
if (!body || !githubToken) {
|
||||||
core.setFailed(error.message);
|
core.setFailed("invalid input: please check your workflow");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const octokit = new GitHub(githubToken);
|
||||||
|
const { data: comments } = await octokit.issues.listComments({
|
||||||
|
...repo,
|
||||||
|
issue_number
|
||||||
|
});
|
||||||
|
const myComment = comments.find(
|
||||||
|
comment => comment.user.login === "github-actions[bot]"
|
||||||
|
);
|
||||||
|
if (myComment) {
|
||||||
|
await octokit.issues.updateComment({
|
||||||
|
...repo,
|
||||||
|
comment_id: myComment.id,
|
||||||
|
body
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await octokit.issues.createComment({
|
||||||
|
...repo,
|
||||||
|
issue_number,
|
||||||
|
body
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch ({ message }) {
|
||||||
|
core.setFailed(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
10
src/wait.ts
10
src/wait.ts
|
|
@ -1,10 +0,0 @@
|
||||||
export function wait(milliseconds: number) {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
if (isNaN(milliseconds)) {
|
|
||||||
throw new Error('milleseconds not a number');
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(() => resolve("done!"), milliseconds)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Loading…
Reference in a new issue