diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index dbc263b..91d059c 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -41,7 +41,6 @@ jobs:
- name: Test
id: npm-ci-test
run: npm run ci-test
-
test-action:
name: GitHub Actions Test
runs-on: ubuntu-latest
@@ -55,8 +54,7 @@ jobs:
id: test-action
uses: ./
with:
- milliseconds: 2000
-
- - name: Print Output
- id: output
- run: echo "${{ steps.test-action.outputs.time }}"
+ threadName: 'v1.0-test-action'
+ channelName: 'bifrost'
+ webhookUrl: ${{ secrets.HUBOT_WEBHOOK_URl }}
+ webhookAuth: ${{ secrets.HUBOT_WEBHOOK_AUTH }}
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
deleted file mode 100644
index 6ad7cb6..0000000
--- a/.github/workflows/codeql-analysis.yml
+++ /dev/null
@@ -1,48 +0,0 @@
-name: CodeQL
-
-on:
- push:
- branches:
- - main
- pull_request:
- branches:
- - main
- schedule:
- - cron: '31 7 * * 3'
-
-jobs:
- analyze:
- name: Analyze
- runs-on: ubuntu-latest
-
- permissions:
- actions: read
- checks: write
- contents: read
- security-events: write
-
- strategy:
- fail-fast: false
- matrix:
- language:
- - TypeScript
-
- steps:
- - name: Checkout
- id: checkout
- uses: actions/checkout@v4
-
- - name: Initialize CodeQL
- id: initialize
- uses: github/codeql-action/init@v3
- with:
- languages: ${{ matrix.language }}
- source-root: src
-
- - name: Autobuild
- id: autobuild
- uses: github/codeql-action/autobuild@v3
-
- - name: Perform CodeQL Analysis
- id: analyze
- uses: github/codeql-action/analyze@v3
diff --git a/CODEOWNERS b/CODEOWNERS
deleted file mode 100644
index a9802d7..0000000
--- a/CODEOWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Repository CODEOWNERS
-
-* @actions/actions-runtime
-* @ncalteen
diff --git a/README.md b/README.md
index f198d8a..292b2fd 100644
--- a/README.md
+++ b/README.md
@@ -1,51 +1,29 @@
-# Create a GitHub Action Using TypeScript
+# valkyrie-thread-action
-[![GitHub Super-Linter](https://github.com/actions/typescript-action/actions/workflows/linter.yml/badge.svg)](https://github.com/super-linter/super-linter)
-![CI](https://github.com/actions/typescript-action/actions/workflows/ci.yml/badge.svg)
-[![Check dist/](https://github.com/actions/typescript-action/actions/workflows/check-dist.yml/badge.svg)](https://github.com/actions/typescript-action/actions/workflows/check-dist.yml)
-[![CodeQL](https://github.com/actions/typescript-action/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/actions/typescript-action/actions/workflows/codeql-analysis.yml)
-[![Coverage](./badges/coverage.svg)](./badges/coverage.svg)
+This action can be triggered after a release tag is created to start a thread
+with the release details.
-Use this template to bootstrap the creation of a TypeScript action. :rocket:
-
-This template includes compilation support, tests, a validation workflow,
-publishing, and versioning guidance.
-
-If you are new, there's also a simpler introduction in the
-[Hello world JavaScript action repository](https://github.com/actions/hello-world-javascript-action).
-
-## Create Your Own Action
-
-To create your own action, you can use this repository as a template! Just
-follow the below instructions:
-
-1. Click the **Use this template** button at the top of the repository
-1. Select **Create a new repository**
-1. Select an owner and name for your new repository
-1. Click **Create repository**
-1. Clone your new repository
-
-> [!IMPORTANT]
->
-> Make sure to remove or update the [`CODEOWNERS`](./CODEOWNERS) file! For
-> details on how to use this file, see
-> [About code owners](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners).
+## Usage
-## Initial Setup
+```yaml
+on:
+ push:
+ tags:
+ - v1.*
-After you've cloned the repository to your local machine or codespace, you'll
-need to perform some initial setup steps before you can develop your action.
+steps:
+ - name: Example action
+ id: example-action
+ uses: thesis/valyrie-thread-action@v1
+ with:
+ threadName: 'v1.0'
+ channelName: 'release'
+ message: 'release notes'
+ webhookUrl: ${{ secrets.WEBHOOK_URL }}
+ webhookAuth: ${{ secrets.WEBHOOK_AUTH }}
+```
-> [!NOTE]
->
-> You'll need to have a reasonably modern version of
-> [Node.js](https://nodejs.org) handy (20.x or later should work!). If you are
-> using a version manager like [`nodenv`](https://github.com/nodenv/nodenv) or
-> [`nvm`](https://github.com/nvm-sh/nvm), this template has a `.node-version`
-> file at the root of the repository that will be used to automatically switch
-> to the correct version when you `cd` into the repository. Additionally, this
-> `.node-version` file is used by GitHub Actions in any `actions/setup-node`
-> actions.
+## Initial Local Setup
1. :hammer_and_wrench: Install the dependencies
@@ -59,65 +37,8 @@ need to perform some initial setup steps before you can develop your action.
npm run bundle
```
-1. :white_check_mark: Run the tests
-
- ```bash
- $ npm test
-
- PASS ./index.test.js
- ✓ throws invalid number (3ms)
- ✓ wait 500 ms (504ms)
- ✓ test runs (95ms)
-
- ...
- ```
-
-## Update the Action Metadata
-
-The [`action.yml`](action.yml) file defines metadata about your action, such as
-input(s) and output(s). For details about this file, see
-[Metadata syntax for GitHub Actions](https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions).
-
-When you copy this repository, update `action.yml` with the name, description,
-inputs, and outputs for your action.
-
-## Update the Action Code
-
-The [`src/`](./src/) directory is the heart of your action! This contains the
-source code that will be run when your action is invoked. You can replace the
-contents of this directory with your own code.
-
-There are a few things to keep in mind when writing your action code:
-
-- Most GitHub Actions toolkit and CI/CD operations are processed asynchronously.
- In `main.ts`, you will see that the action is run in an `async` function.
-
- ```javascript
- import * as core from '@actions/core'
- //...
+## Updating the action
- async function run() {
- try {
- //...
- } catch (error) {
- core.setFailed(error.message)
- }
- }
- ```
-
- For more information about the GitHub Actions toolkit, see the
- [documentation](https://github.com/actions/toolkit/blob/master/README.md).
-
-So, what are you waiting for? Go ahead and start customizing your action!
-
-1. Create a new branch
-
- ```bash
- git checkout -b releases/v1
- ```
-
-1. Replace the contents of `src/` with your action code
-1. Add tests to `__tests__/` for your source code
1. Format, test, and build the action
```bash
@@ -133,82 +54,6 @@ So, what are you waiting for? Go ahead and start customizing your action!
> `ncc`, which will create a license file for all of the production node
> modules used in your project.
-1. Commit your changes
-
- ```bash
- git add .
- git commit -m "My first action is ready!"
- ```
-
-1. Push them to your repository
-
- ```bash
- git push -u origin releases/v1
- ```
-
-1. Create a pull request and get feedback on your action
-1. Merge the pull request into the `main` branch
-
-Your action is now published! :rocket:
-
-For information about versioning your action, see
-[Versioning](https://github.com/actions/toolkit/blob/master/docs/action-versioning.md)
-in the GitHub Actions toolkit.
-
-## Validate the Action
-
-You can now validate the action by referencing it in a workflow file. For
-example, [`ci.yml`](./.github/workflows/ci.yml) demonstrates how to reference an
-action in the same repository.
-
-```yaml
-steps:
- - name: Checkout
- id: checkout
- uses: actions/checkout@v4
-
- - name: Test Local Action
- id: test-action
- uses: ./
- with:
- milliseconds: 1000
-
- - name: Print Output
- id: output
- run: echo "${{ steps.test-action.outputs.time }}"
-```
-
-For example workflow runs, check out the
-[Actions tab](https://github.com/actions/typescript-action/actions)! :rocket:
-
-## Usage
-
-After testing, you can create version tag(s) that developers can use to
-reference different stable versions of your action. For more information, see
-[Versioning](https://github.com/actions/toolkit/blob/master/docs/action-versioning.md)
-in the GitHub Actions toolkit.
-
-To include the action in a workflow in another repository, you can use the
-`uses` syntax with the `@` symbol to reference a specific branch, tag, or commit
-hash.
-
-```yaml
-steps:
- - name: Checkout
- id: checkout
- uses: actions/checkout@v4
-
- - name: Test Local Action
- id: test-action
- uses: actions/typescript-action@v1 # Commit with the `v1` tag
- with:
- milliseconds: 1000
-
- - name: Print Output
- id: output
- run: echo "${{ steps.test-action.outputs.time }}"
-```
-
## Publishing a new release
This project includes a helper script designed to streamline the process of
diff --git a/__tests__/index.test.ts b/__tests__/index.test.ts
index 34a4dfe..c5c0dfb 100644
--- a/__tests__/index.test.ts
+++ b/__tests__/index.test.ts
@@ -5,13 +5,13 @@
import * as main from '../src/main'
// Mock the action's entrypoint
-const runMock = jest.spyOn(main, 'run').mockImplementation()
+const createThreadMock = jest.spyOn(main, 'createThread').mockImplementation()
describe('index', () => {
- it('calls run when imported', async () => {
+ it('calls createThread when imported', async () => {
// eslint-disable-next-line @typescript-eslint/no-require-imports
require('../src/index')
- expect(runMock).toHaveBeenCalled()
+ expect(createThreadMock).toHaveBeenCalled()
})
})
diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts
index 30efdfb..dde2006 100644
--- a/__tests__/main.test.ts
+++ b/__tests__/main.test.ts
@@ -9,81 +9,103 @@
import * as core from '@actions/core'
import * as main from '../src/main'
-// Mock the action's main function
-const runMock = jest.spyOn(main, 'run')
-
-// Other utilities
-const timeRegex = /^\d{2}:\d{2}:\d{2}/
-
// Mock the GitHub Actions core library
-let debugMock: jest.SpyInstance
+let infoMock: jest.SpyInstance
let errorMock: jest.SpyInstance
let getInputMock: jest.SpyInstance
let setFailedMock: jest.SpyInstance
-let setOutputMock: jest.SpyInstance
+let fetchMock: jest.SpyInstance
describe('action', () => {
beforeEach(() => {
jest.clearAllMocks()
- debugMock = jest.spyOn(core, 'debug').mockImplementation()
+ infoMock = jest.spyOn(core, 'info').mockImplementation()
errorMock = jest.spyOn(core, 'error').mockImplementation()
- getInputMock = jest.spyOn(core, 'getInput').mockImplementation()
+
setFailedMock = jest.spyOn(core, 'setFailed').mockImplementation()
- setOutputMock = jest.spyOn(core, 'setOutput').mockImplementation()
+ fetchMock = jest.spyOn(global, 'fetch').mockImplementation()
+
+ getInputMock = jest
+ .spyOn(core, 'getInput')
+ .mockImplementation((name: string): string => {
+ switch (name) {
+ case 'threadName':
+ return 'v1'
+ case 'channelName':
+ return 'test'
+ case 'webhookUrl':
+ return 'webhookUrl'
+ case 'webhookAuth':
+ return 'webhookAuth'
+ case 'message':
+ return 'message'
+ default:
+ return ''
+ }
+ })
})
- it('sets the time output', async () => {
- // Set the action's inputs as return values from core.getInput()
- getInputMock.mockImplementation((name: string): string => {
- switch (name) {
- case 'milliseconds':
- return '500'
- default:
- return ''
- }
+ afterEach(() => {
+ jest.clearAllMocks()
+ })
+
+ it('should call webhook to create thread', async () => {
+ fetchMock.mockResolvedValueOnce({
+ ok: true,
+ json: jest.fn().mockResolvedValueOnce({}),
+ text: jest.fn().mockResolvedValueOnce(''),
+ status: 200
})
- await main.run()
- expect(runMock).toHaveReturned()
+ await main.createThread()
// Verify that all of the core library functions were called correctly
- expect(debugMock).toHaveBeenNthCalledWith(1, 'Waiting 500 milliseconds ...')
- expect(debugMock).toHaveBeenNthCalledWith(
- 2,
- expect.stringMatching(timeRegex)
- )
- expect(debugMock).toHaveBeenNthCalledWith(
- 3,
- expect.stringMatching(timeRegex)
- )
- expect(setOutputMock).toHaveBeenNthCalledWith(
- 1,
- 'time',
- expect.stringMatching(timeRegex)
- )
+ expect(infoMock).toHaveBeenNthCalledWith(1, 'Thread created')
+ expect(errorMock).not.toHaveBeenCalled()
+
+ expect(fetchMock).toHaveBeenNthCalledWith(1, 'webhookUrl', {
+ method: 'POST',
+ headers: {
+ 'Content-type': 'application/json',
+ Accept: 'application/json',
+ Authorization: 'webhookAuth'
+ },
+ body: JSON.stringify({
+ channelName: 'test',
+ title: 'v1',
+ message: 'message',
+ tagUser: '0'
+ })
+ })
+ })
+
+ it('should failed action if return is not ok', async () => {
+ fetchMock.mockResolvedValueOnce({
+ ok: false,
+ json: jest.fn().mockResolvedValueOnce({}),
+ text: jest.fn().mockResolvedValueOnce(''),
+ status: 401
+ })
+
+ await main.createThread()
+
+ // Verify that all of the core library functions were called correctly
+ expect(setFailedMock).toHaveBeenNthCalledWith(1, 'HTTP error! status: 401')
expect(errorMock).not.toHaveBeenCalled()
})
- it('sets a failed status', async () => {
- // Set the action's inputs as return values from core.getInput()
- getInputMock.mockImplementation((name: string): string => {
- switch (name) {
- case 'milliseconds':
- return 'this is not a number'
- default:
- return ''
- }
+ it('should error if missig inputs', async () => {
+ getInputMock.mockImplementationOnce(() => {
+ throw new Error('Input required and not supplied: webhookUrl')
})
- await main.run()
- expect(runMock).toHaveReturned()
+ await main.createThread()
// Verify that all of the core library functions were called correctly
expect(setFailedMock).toHaveBeenNthCalledWith(
1,
- 'milliseconds not a number'
+ 'Input required and not supplied: webhookUrl'
)
- expect(errorMock).not.toHaveBeenCalled()
})
})
diff --git a/__tests__/wait.test.ts b/__tests__/wait.test.ts
deleted file mode 100644
index 1336aaa..0000000
--- a/__tests__/wait.test.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * Unit tests for src/wait.ts
- */
-
-import { wait } from '../src/wait'
-import { expect } from '@jest/globals'
-
-describe('wait.ts', () => {
- it('throws an invalid number', async () => {
- const input = parseInt('foo', 10)
- expect(isNaN(input)).toBe(true)
-
- await expect(wait(input)).rejects.toThrow('milliseconds not a number')
- })
-
- it('waits with a valid number', async () => {
- const start = new Date()
- await wait(500)
- const end = new Date()
-
- const delta = Math.abs(end.getTime() - start.getTime())
-
- expect(delta).toBeGreaterThan(450)
- })
-})
diff --git a/action.yml b/action.yml
index 101186a..8b1c8ba 100644
--- a/action.yml
+++ b/action.yml
@@ -1,23 +1,22 @@
-name: 'The name of your action here'
-description: 'Provide a description here'
-author: 'Your name or organization here'
+name: 'valyrie-thread-action'
+description: 'Triggers a thread in a Discord channel.'
-# Add your action's branding here. This will appear on the GitHub Marketplace.
-branding:
- icon: 'heart'
- color: 'red'
-
-# Define your inputs here.
inputs:
- milliseconds:
- description: 'Your input description here'
+ threadName:
+ description: 'The name of the thread.'
+ required: true
+ channelName:
+ description: 'The name of the channel to create the thread in.'
+ required: true
+ message:
+ description: 'The message to send in the thread.'
+ required: false
+ default: '.'
+ webhookUrl:
+ description: 'The webhook url to send the message to.'
+ required: true
+ webhookAuth:
required: true
- default: '1000'
-
-# Define your outputs here.
-outputs:
- time:
- description: 'Your output description here'
runs:
using: node20
diff --git a/badges/coverage.svg b/badges/coverage.svg
index 5bb55be..8c73e34 100644
--- a/badges/coverage.svg
+++ b/badges/coverage.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/dist/index.js b/dist/index.js
index 9bbc394..743cab0 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -2751,24 +2751,35 @@ var __importStar = (this && this.__importStar) || function (mod) {
return result;
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
-exports.run = void 0;
+exports.createThread = void 0;
const core = __importStar(__nccwpck_require__(186));
-const wait_1 = __nccwpck_require__(259);
+const getRequiredInput = (name) => core.getInput(name, { required: true });
/**
* The main function for the action.
* @returns {Promise} Resolves when the action is complete.
*/
-async function run() {
+async function createThread() {
try {
- const ms = core.getInput('milliseconds');
- // Debug logs are only output if the `ACTIONS_STEP_DEBUG` secret is true
- core.debug(`Waiting ${ms} milliseconds ...`);
- // Log the current timestamp, wait, then log the new timestamp
- core.debug(new Date().toTimeString());
- await (0, wait_1.wait)(parseInt(ms, 10));
- core.debug(new Date().toTimeString());
- // Set outputs for other workflow steps to use
- core.setOutput('time', new Date().toTimeString());
+ const webhookUrl = getRequiredInput('webhookUrl');
+ const webhookAuth = getRequiredInput('webhookAuth');
+ const response = await fetch(webhookUrl, {
+ method: 'POST',
+ headers: {
+ 'Content-type': 'application/json',
+ Accept: 'application/json',
+ Authorization: webhookAuth
+ },
+ body: JSON.stringify({
+ channelName: getRequiredInput('channelName'),
+ title: getRequiredInput('threadName'),
+ message: core.getInput('message'),
+ tagUser: '0'
+ })
+ });
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+ core.info('Thread created');
}
catch (error) {
// Fail the workflow run if an error occurs
@@ -2776,32 +2787,7 @@ async function run() {
core.setFailed(error.message);
}
}
-exports.run = run;
-
-
-/***/ }),
-
-/***/ 259:
-/***/ ((__unused_webpack_module, exports) => {
-
-"use strict";
-
-Object.defineProperty(exports, "__esModule", ({ value: true }));
-exports.wait = void 0;
-/**
- * Wait for a number of milliseconds.
- * @param milliseconds The number of milliseconds to wait.
- * @returns {Promise} Resolves with 'done!' after the wait is over.
- */
-async function wait(milliseconds) {
- return new Promise(resolve => {
- if (isNaN(milliseconds)) {
- throw new Error('milliseconds not a number');
- }
- setTimeout(() => resolve('done!'), milliseconds);
- });
-}
-exports.wait = wait;
+exports.createThread = createThread;
/***/ }),
@@ -2943,8 +2929,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
* The entrypoint for the action.
*/
const main_1 = __nccwpck_require__(399);
-// eslint-disable-next-line @typescript-eslint/no-floating-promises
-(0, main_1.run)();
+(0, main_1.createThread)();
})();
diff --git a/package-lock.json b/package-lock.json
index aa22c45..15cb731 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,11 +1,11 @@
{
- "name": "typescript-action",
+ "name": "valkyrie-thread-action",
"version": "0.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
- "name": "typescript-action",
+ "name": "valkyrie-thread-action",
"version": "0.0.0",
"license": "MIT",
"dependencies": {
diff --git a/package.json b/package.json
index c548558..0ee4c0d 100644
--- a/package.json
+++ b/package.json
@@ -1,22 +1,9 @@
{
- "name": "typescript-action",
+ "name": "valkyrie-thread-action",
"description": "GitHub Actions TypeScript template",
"version": "0.0.0",
"author": "",
"private": true,
- "homepage": "https://github.com/actions/typescript-action",
- "repository": {
- "type": "git",
- "url": "git+https://github.com/actions/typescript-action.git"
- },
- "bugs": {
- "url": "https://github.com/actions/typescript-action/issues"
- },
- "keywords": [
- "actions",
- "node",
- "setup"
- ],
"exports": {
".": "./dist/index.js"
},
diff --git a/src/index.ts b/src/index.ts
index b08f970..a65ffae 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,7 +1,6 @@
/**
* The entrypoint for the action.
*/
-import { run } from './main'
+import { createThread } from './main'
-// eslint-disable-next-line @typescript-eslint/no-floating-promises
-run()
+createThread()
diff --git a/src/main.ts b/src/main.ts
index c804f90..ace5a55 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -1,24 +1,37 @@
import * as core from '@actions/core'
-import { wait } from './wait'
+
+const getRequiredInput = (name: string): string =>
+ core.getInput(name, { required: true })
/**
* The main function for the action.
* @returns {Promise} Resolves when the action is complete.
*/
-export async function run(): Promise {
+export async function createThread(): Promise {
try {
- const ms: string = core.getInput('milliseconds')
+ const webhookUrl = getRequiredInput('webhookUrl')
+ const webhookAuth = getRequiredInput('webhookAuth')
- // Debug logs are only output if the `ACTIONS_STEP_DEBUG` secret is true
- core.debug(`Waiting ${ms} milliseconds ...`)
+ const response = await fetch(webhookUrl, {
+ method: 'POST',
+ headers: {
+ 'Content-type': 'application/json',
+ Accept: 'application/json',
+ Authorization: webhookAuth
+ },
+ body: JSON.stringify({
+ channelName: getRequiredInput('channelName'),
+ title: getRequiredInput('threadName'),
+ message: core.getInput('message'),
+ tagUser: '0'
+ })
+ })
- // Log the current timestamp, wait, then log the new timestamp
- core.debug(new Date().toTimeString())
- await wait(parseInt(ms, 10))
- core.debug(new Date().toTimeString())
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`)
+ }
- // Set outputs for other workflow steps to use
- core.setOutput('time', new Date().toTimeString())
+ core.info('Thread created')
} catch (error) {
// Fail the workflow run if an error occurs
if (error instanceof Error) core.setFailed(error.message)
diff --git a/src/wait.ts b/src/wait.ts
deleted file mode 100644
index 0ddf692..0000000
--- a/src/wait.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Wait for a number of milliseconds.
- * @param milliseconds The number of milliseconds to wait.
- * @returns {Promise} Resolves with 'done!' after the wait is over.
- */
-export async function wait(milliseconds: number): Promise {
- return new Promise(resolve => {
- if (isNaN(milliseconds)) {
- throw new Error('milliseconds not a number')
- }
-
- setTimeout(() => resolve('done!'), milliseconds)
- })
-}