diff --git a/.github/workflows/comment_on_pull_request.yml b/.github/workflows/comment_on_pull_request.yml new file mode 100644 index 0000000..4f3386a --- /dev/null +++ b/.github/workflows/comment_on_pull_request.yml @@ -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. diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1cb570c..eb4e76a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,20 +1,16 @@ -name: "Test typescript-action" +name: test on: pull_request: push: branches: - master - - 'releases/*' jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v1 - - run: npm ci - - run: npm run build - - run: npm test - - uses: ./ - with: - milliseconds: 1000 + - run: npm ci + - run: npm run build + - run: npm test diff --git a/README.md b/README.md index 792067e..e79c659 100644 --- a/README.md +++ b/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 $ npm install ``` Build the typescript + ```bash $ npm run build ``` -Run the tests :heavy_check_mark: +Run the tests :heavy_check_mark: + ```bash $ 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 -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 + ```bash # comment out in distribution branches # node_modules/ @@ -86,28 +52,16 @@ $ git commit -a -m "prod dependencies" $ 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) -## 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: -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 -uses: actions/typescript-action@v1 +uses: marocchino/sticky-pull-request-comment@v1 with: - milliseconds: 1000 + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + message: | + Release ${{ github.sha }} to ``` diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts index 6f7475e..34fbeb9 100644 --- a/__tests__/main.test.ts +++ b/__tests__/main.test.ts @@ -1,27 +1,2 @@ -import {wait} from '../src/wait' -import * as process from 'process' -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()); -}); \ No newline at end of file +test("create a comment when no comment", async () => {}); +test("update a comment when comment is exists", async () => {}); diff --git a/action.yml b/action.yml index 5cfdde4..5c31ae2 100644 --- a/action.yml +++ b/action.yml @@ -1,10 +1,11 @@ -name: 'Your name here' -description: 'Provide a description here' -author: 'Your name or organization here' +name: "Your name here" +description: "Provide a description here" +author: "Your name or organization here" inputs: - myInput: # change this - description: 'input description here' - default: 'default value if applicable' + message: + description: "comment message" + GITHUB_TOKEN: + description: "set secrets.GITHUB_TOKEN here" runs: - using: 'node12' - main: 'lib/main.js' + using: "node12" + main: "lib/main.js" diff --git a/lib/main.js b/lib/main.js index 9598b7e..3f28aa8 100644 --- a/lib/main.js +++ b/lib/main.js @@ -1,9 +1,10 @@ "use strict"; 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) { 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 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()); }); }; @@ -16,19 +17,36 @@ var __importStar = (this && this.__importStar) || function (mod) { }; Object.defineProperty(exports, "__esModule", { value: true }); const core = __importStar(require("@actions/core")); -const wait_1 = require("./wait"); +const github_1 = require("@actions/github"); function run() { + var _a, _b, _c; return __awaiter(this, void 0, void 0, function* () { try { - const ms = core.getInput('milliseconds'); - console.log(`Waiting ${ms} milliseconds ...`); - core.debug((new Date()).toTimeString()); - wait_1.wait(parseInt(ms)); - core.debug((new Date()).toTimeString()); - core.setOutput('time', new Date().toTimeString()); + const repo = github_1.context.repo; + 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; + if (!issue_number) { + core.setFailed("This action only works for pull_request"); + return; + } + 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) { - core.setFailed(error.message); + catch ({ message }) { + core.setFailed(message); } }); } diff --git a/lib/wait.js b/lib/wait.js deleted file mode 100644 index 727df44..0000000 --- a/lib/wait.js +++ /dev/null @@ -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; diff --git a/src/main.ts b/src/main.ts index 191f388..9172e53 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,18 +1,43 @@ -import * as core from '@actions/core'; -import {wait} from './wait' +import * as core from "@actions/core"; +import { context, GitHub } from "@actions/github"; async function run() { try { - const ms = core.getInput('milliseconds'); - console.log(`Waiting ${ms} milliseconds ...`) - - core.debug((new Date()).toTimeString()) - await wait(parseInt(ms, 10)); - core.debug((new Date()).toTimeString()) - - core.setOutput('time', new Date().toTimeString()); - } catch (error) { - core.setFailed(error.message); + const repo = context.repo; + const issue_number = context?.payload?.pull_request?.number; + if (!issue_number) { + core.setFailed("This action only works for pull_request"); + return; + } + 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(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); } } diff --git a/src/wait.ts b/src/wait.ts deleted file mode 100644 index 9eff51f..0000000 --- a/src/wait.ts +++ /dev/null @@ -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) - }); -} - \ No newline at end of file