Initial commit
This commit is contained in:
commit
7679370a9e
41
.devcontainer/devcontainer.json
Normal file
41
.devcontainer/devcontainer.json
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"name": "GitHub Actions (TypeScript)",
|
||||||
|
"image": "mcr.microsoft.com/devcontainers/typescript-node:20",
|
||||||
|
"postCreateCommand": "npm install",
|
||||||
|
"customizations": {
|
||||||
|
"codespaces": {
|
||||||
|
"openFiles": ["README.md"]
|
||||||
|
},
|
||||||
|
"vscode": {
|
||||||
|
"extensions": [
|
||||||
|
"bierner.markdown-preview-github-styles",
|
||||||
|
"davidanson.vscode-markdownlint",
|
||||||
|
"dbaeumer.vscode-eslint",
|
||||||
|
"esbenp.prettier-vscode",
|
||||||
|
"github.copilot",
|
||||||
|
"github.copilot-chat",
|
||||||
|
"github.vscode-github-actions",
|
||||||
|
"github.vscode-pull-request-github",
|
||||||
|
"me-dutour-mathieu.vscode-github-actions",
|
||||||
|
"redhat.vscode-yaml",
|
||||||
|
"rvest.vs-code-prettier-eslint",
|
||||||
|
"yzhang.markdown-all-in-one"
|
||||||
|
],
|
||||||
|
"settings": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||||
|
"editor.tabSize": 2,
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"markdown.extension.list.indentationSize": "adaptive",
|
||||||
|
"markdown.extension.italic.indicator": "_",
|
||||||
|
"markdown.extension.orderedList.marker": "one"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"remoteEnv": {
|
||||||
|
"GITHUB_TOKEN": "${localEnv:GITHUB_TOKEN}"
|
||||||
|
},
|
||||||
|
"features": {
|
||||||
|
"ghcr.io/devcontainers/features/github-cli:1": {},
|
||||||
|
"ghcr.io/devcontainers-contrib/features/prettier:1": {}
|
||||||
|
}
|
||||||
|
}
|
4
.eslintignore
Normal file
4
.eslintignore
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
lib/
|
||||||
|
dist/
|
||||||
|
node_modules/
|
||||||
|
coverage/
|
3
.gitattributes
vendored
Normal file
3
.gitattributes
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
* text=auto eol=lf
|
||||||
|
|
||||||
|
dist/** -diff linguist-generated=true
|
26
.github/dependabot.yml
vendored
Normal file
26
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: github-actions
|
||||||
|
directory: /
|
||||||
|
schedule:
|
||||||
|
interval: weekly
|
||||||
|
groups:
|
||||||
|
actions-minor:
|
||||||
|
update-types:
|
||||||
|
- minor
|
||||||
|
- patch
|
||||||
|
|
||||||
|
- package-ecosystem: npm
|
||||||
|
directory: /
|
||||||
|
schedule:
|
||||||
|
interval: weekly
|
||||||
|
groups:
|
||||||
|
npm-development:
|
||||||
|
dependency-type: development
|
||||||
|
update-types:
|
||||||
|
- minor
|
||||||
|
- patch
|
||||||
|
npm-production:
|
||||||
|
dependency-type: production
|
||||||
|
update-types:
|
||||||
|
- patch
|
83
.github/linters/.eslintrc.yml
vendored
Normal file
83
.github/linters/.eslintrc.yml
vendored
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
env:
|
||||||
|
node: true
|
||||||
|
es6: true
|
||||||
|
jest: true
|
||||||
|
|
||||||
|
globals:
|
||||||
|
Atomics: readonly
|
||||||
|
SharedArrayBuffer: readonly
|
||||||
|
|
||||||
|
ignorePatterns:
|
||||||
|
- '!.*'
|
||||||
|
- '**/node_modules/.*'
|
||||||
|
- '**/dist/.*'
|
||||||
|
- '**/coverage/.*'
|
||||||
|
- '*.json'
|
||||||
|
|
||||||
|
parser: '@typescript-eslint/parser'
|
||||||
|
|
||||||
|
parserOptions:
|
||||||
|
ecmaVersion: 2023
|
||||||
|
sourceType: module
|
||||||
|
project:
|
||||||
|
- './.github/linters/tsconfig.json'
|
||||||
|
- './tsconfig.json'
|
||||||
|
|
||||||
|
plugins:
|
||||||
|
- jest
|
||||||
|
- '@typescript-eslint'
|
||||||
|
|
||||||
|
extends:
|
||||||
|
- eslint:recommended
|
||||||
|
- plugin:@typescript-eslint/eslint-recommended
|
||||||
|
- plugin:@typescript-eslint/recommended
|
||||||
|
- plugin:github/recommended
|
||||||
|
- plugin:jest/recommended
|
||||||
|
|
||||||
|
rules:
|
||||||
|
{
|
||||||
|
'camelcase': 'off',
|
||||||
|
'eslint-comments/no-use': 'off',
|
||||||
|
'eslint-comments/no-unused-disable': 'off',
|
||||||
|
'i18n-text/no-en': 'off',
|
||||||
|
'import/no-namespace': 'off',
|
||||||
|
'no-console': 'off',
|
||||||
|
'no-unused-vars': 'off',
|
||||||
|
'prettier/prettier': 'error',
|
||||||
|
'semi': 'off',
|
||||||
|
'@typescript-eslint/array-type': 'error',
|
||||||
|
'@typescript-eslint/await-thenable': 'error',
|
||||||
|
'@typescript-eslint/ban-ts-comment': 'error',
|
||||||
|
'@typescript-eslint/consistent-type-assertions': 'error',
|
||||||
|
'@typescript-eslint/explicit-member-accessibility':
|
||||||
|
['error', { 'accessibility': 'no-public' }],
|
||||||
|
'@typescript-eslint/explicit-function-return-type':
|
||||||
|
['error', { 'allowExpressions': true }],
|
||||||
|
'@typescript-eslint/func-call-spacing': ['error', 'never'],
|
||||||
|
'@typescript-eslint/no-array-constructor': 'error',
|
||||||
|
'@typescript-eslint/no-empty-interface': 'error',
|
||||||
|
'@typescript-eslint/no-explicit-any': 'error',
|
||||||
|
'@typescript-eslint/no-extraneous-class': 'error',
|
||||||
|
'@typescript-eslint/no-for-in-array': 'error',
|
||||||
|
'@typescript-eslint/no-inferrable-types': 'error',
|
||||||
|
'@typescript-eslint/no-misused-new': 'error',
|
||||||
|
'@typescript-eslint/no-namespace': 'error',
|
||||||
|
'@typescript-eslint/no-non-null-assertion': 'warn',
|
||||||
|
'@typescript-eslint/no-require-imports': 'error',
|
||||||
|
'@typescript-eslint/no-unnecessary-qualifier': 'error',
|
||||||
|
'@typescript-eslint/no-unnecessary-type-assertion': 'error',
|
||||||
|
'@typescript-eslint/no-unused-vars': 'error',
|
||||||
|
'@typescript-eslint/no-useless-constructor': 'error',
|
||||||
|
'@typescript-eslint/no-var-requires': 'error',
|
||||||
|
'@typescript-eslint/prefer-for-of': 'warn',
|
||||||
|
'@typescript-eslint/prefer-function-type': 'warn',
|
||||||
|
'@typescript-eslint/prefer-includes': 'error',
|
||||||
|
'@typescript-eslint/prefer-string-starts-ends-with': 'error',
|
||||||
|
'@typescript-eslint/promise-function-async': 'error',
|
||||||
|
'@typescript-eslint/require-array-sort-compare': 'error',
|
||||||
|
'@typescript-eslint/restrict-plus-operands': 'error',
|
||||||
|
'@typescript-eslint/semi': ['error', 'never'],
|
||||||
|
'@typescript-eslint/space-before-function-paren': 'off',
|
||||||
|
'@typescript-eslint/type-annotation-spacing': 'error',
|
||||||
|
'@typescript-eslint/unbound-method': 'error'
|
||||||
|
}
|
18
.github/linters/.markdown-lint.yml
vendored
Normal file
18
.github/linters/.markdown-lint.yml
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Unordered list style
|
||||||
|
MD004:
|
||||||
|
style: dash
|
||||||
|
|
||||||
|
# Ordered list item prefix
|
||||||
|
MD029:
|
||||||
|
style: one
|
||||||
|
|
||||||
|
# Spaces after list markers
|
||||||
|
MD030:
|
||||||
|
ul_single: 1
|
||||||
|
ol_single: 1
|
||||||
|
ul_multi: 1
|
||||||
|
ol_multi: 1
|
||||||
|
|
||||||
|
# Code block style
|
||||||
|
MD046:
|
||||||
|
style: fenced
|
10
.github/linters/.yaml-lint.yml
vendored
Normal file
10
.github/linters/.yaml-lint.yml
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
rules:
|
||||||
|
document-end: disable
|
||||||
|
document-start:
|
||||||
|
level: warning
|
||||||
|
present: false
|
||||||
|
line-length:
|
||||||
|
level: warning
|
||||||
|
max: 80
|
||||||
|
allow-non-breakable-words: true
|
||||||
|
allow-non-breakable-inline-mappings: true
|
9
.github/linters/tsconfig.json
vendored
Normal file
9
.github/linters/tsconfig.json
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json.schemastore.org/tsconfig",
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"noEmit": true
|
||||||
|
},
|
||||||
|
"include": ["../../__tests__/**/*", "../../src/**/*"],
|
||||||
|
"exclude": ["../../dist", "../../node_modules", "../../coverage", "*.json"]
|
||||||
|
}
|
66
.github/workflows/check-dist.yml
vendored
Normal file
66
.github/workflows/check-dist.yml
vendored
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
# In TypeScript actions, `dist/` is a special directory. When you reference
|
||||||
|
# an action with the `uses:` property, `dist/index.js` is the code that will be
|
||||||
|
# run. For this project, the `dist/index.js` file is transpiled from other
|
||||||
|
# source files. This workflow ensures the `dist/` directory contains the
|
||||||
|
# expected transpiled code.
|
||||||
|
#
|
||||||
|
# If this workflow is run from a feature branch, it will act as an additional CI
|
||||||
|
# check and fail if the checked-in `dist/` directory does not match what is
|
||||||
|
# expected from the build.
|
||||||
|
name: Check Transpiled JavaScript
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check-dist:
|
||||||
|
name: Check dist/
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
id: checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
id: setup-node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version-file: .node-version
|
||||||
|
cache: npm
|
||||||
|
|
||||||
|
- name: Install Dependencies
|
||||||
|
id: install
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Build dist/ Directory
|
||||||
|
id: build
|
||||||
|
run: npm run bundle
|
||||||
|
|
||||||
|
# This will fail the workflow if the PR wasn't created by Dependabot.
|
||||||
|
- name: Compare Directories
|
||||||
|
id: diff
|
||||||
|
run: |
|
||||||
|
if [ "$(git diff --ignore-space-at-eol --text dist/ | wc -l)" -gt "0" ]; then
|
||||||
|
echo "Detected uncommitted changes after build. See status below:"
|
||||||
|
git diff --ignore-space-at-eol --text dist/
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If `dist/` was different than expected, and this was not a Dependabot
|
||||||
|
# PR, upload the expected version as a workflow artifact.
|
||||||
|
- if: ${{ failure() && steps.diff.outcome == 'failure' }}
|
||||||
|
name: Upload Artifact
|
||||||
|
id: upload
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: dist
|
||||||
|
path: dist/
|
64
.github/workflows/ci.yml
vendored
Normal file
64
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
name: Continuous Integration
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test-typescript:
|
||||||
|
name: TypeScript Tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
id: checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
id: setup-node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version-file: .node-version
|
||||||
|
cache: npm
|
||||||
|
|
||||||
|
- name: Install Dependencies
|
||||||
|
id: npm-ci
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Check Format
|
||||||
|
id: npm-format-check
|
||||||
|
run: npm run format:check
|
||||||
|
|
||||||
|
- name: Lint
|
||||||
|
id: npm-lint
|
||||||
|
run: npm run lint
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
id: npm-ci-test
|
||||||
|
run: npm run ci-test
|
||||||
|
|
||||||
|
test-action:
|
||||||
|
name: GitHub Actions Test
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
id: checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Test Local Action
|
||||||
|
id: test-action
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
milliseconds: 2000
|
||||||
|
|
||||||
|
- name: Print Output
|
||||||
|
id: output
|
||||||
|
run: echo "${{ steps.test-action.outputs.time }}"
|
48
.github/workflows/codeql-analysis.yml
vendored
Normal file
48
.github/workflows/codeql-analysis.yml
vendored
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
name: CodeQL
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
schedule:
|
||||||
|
- cron: '31 7 * * 3'
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
actions: read
|
||||||
|
checks: write
|
||||||
|
contents: read
|
||||||
|
security-events: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
name: Analyze
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
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
|
49
.github/workflows/linter.yml
vendored
Normal file
49
.github/workflows/linter.yml
vendored
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
name: Lint Codebase
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: read
|
||||||
|
statuses: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint:
|
||||||
|
name: Lint Codebase
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
id: checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
id: setup-node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version-file: .node-version
|
||||||
|
cache: npm
|
||||||
|
|
||||||
|
- name: Install Dependencies
|
||||||
|
id: install
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Lint Codebase
|
||||||
|
id: super-linter
|
||||||
|
uses: super-linter/super-linter/slim@v6
|
||||||
|
env:
|
||||||
|
DEFAULT_BRANCH: main
|
||||||
|
FILTER_REGEX_EXCLUDE: dist/**/*
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
TYPESCRIPT_DEFAULT_STYLE: prettier
|
||||||
|
VALIDATE_ALL_CODEBASE: true
|
||||||
|
VALIDATE_JAVASCRIPT_STANDARD: false
|
||||||
|
VALIDATE_JSCPD: false
|
103
.gitignore
vendored
Normal file
103
.gitignore
vendored
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
# Dependency directory
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# Rest pulled from https://github.com/github/gitignore/blob/master/Node.gitignore
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
*.lcov
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# TypeScript v1 declaration files
|
||||||
|
typings/
|
||||||
|
|
||||||
|
# TypeScript cache
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variables file
|
||||||
|
.env
|
||||||
|
.env.test
|
||||||
|
|
||||||
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
|
.cache
|
||||||
|
|
||||||
|
# next.js build output
|
||||||
|
.next
|
||||||
|
|
||||||
|
# nuxt.js build output
|
||||||
|
.nuxt
|
||||||
|
|
||||||
|
# vuepress build output
|
||||||
|
.vuepress/dist
|
||||||
|
|
||||||
|
# Serverless directories
|
||||||
|
.serverless/
|
||||||
|
|
||||||
|
# FuseBox cache
|
||||||
|
.fusebox/
|
||||||
|
|
||||||
|
# DynamoDB Local files
|
||||||
|
.dynamodb/
|
||||||
|
|
||||||
|
# OS metadata
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Ignore built ts files
|
||||||
|
__tests__/runner/*
|
||||||
|
|
||||||
|
# IDE files
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.code-workspace
|
1
.node-version
Normal file
1
.node-version
Normal file
@ -0,0 +1 @@
|
|||||||
|
20.6.0
|
3
.prettierignore
Normal file
3
.prettierignore
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
dist/
|
||||||
|
node_modules/
|
||||||
|
coverage/
|
16
.prettierrc.json
Normal file
16
.prettierrc.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"printWidth": 80,
|
||||||
|
"tabWidth": 2,
|
||||||
|
"useTabs": false,
|
||||||
|
"semi": false,
|
||||||
|
"singleQuote": true,
|
||||||
|
"quoteProps": "as-needed",
|
||||||
|
"jsxSingleQuote": false,
|
||||||
|
"trailingComma": "none",
|
||||||
|
"bracketSpacing": true,
|
||||||
|
"bracketSameLine": true,
|
||||||
|
"arrowParens": "avoid",
|
||||||
|
"proseWrap": "always",
|
||||||
|
"htmlWhitespaceSensitivity": "css",
|
||||||
|
"endOfLine": "lf"
|
||||||
|
}
|
3
CODEOWNERS
Normal file
3
CODEOWNERS
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Repository CODEOWNERS
|
||||||
|
|
||||||
|
* @actions/actions-oss-maintainers
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright GitHub
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
229
README.md
Normal file
229
README.md
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
# Create a GitHub Action Using TypeScript
|
||||||
|
|
||||||
|
[![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)
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
## Initial Setup
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
> [!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.
|
||||||
|
|
||||||
|
1. :hammer_and_wrench: Install the dependencies
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
1. :building_construction: Package the TypeScript for distribution
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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'
|
||||||
|
//...
|
||||||
|
|
||||||
|
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
|
||||||
|
npm run all
|
||||||
|
```
|
||||||
|
|
||||||
|
> This step is important! It will run [`ncc`](https://github.com/vercel/ncc)
|
||||||
|
> to build the final JavaScript action code with all dependencies included.
|
||||||
|
> If you do not run this step, your action will not work correctly when it is
|
||||||
|
> used in a workflow. This step also includes the `--license` option for
|
||||||
|
> `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, [`script/release`](./script/release)
|
||||||
|
designed to streamline the process of tagging and pushing new releases for
|
||||||
|
GitHub Actions.
|
||||||
|
|
||||||
|
GitHub Actions allows users to select a specific version of the action to use,
|
||||||
|
based on release tags. This script simplifies this process by performing the
|
||||||
|
following steps:
|
||||||
|
|
||||||
|
1. **Retrieving the latest release tag:** The script starts by fetching the most
|
||||||
|
recent release tag by looking at the local data available in your repository.
|
||||||
|
1. **Prompting for a new release tag:** The user is then prompted to enter a new
|
||||||
|
release tag. To assist with this, the script displays the latest release tag
|
||||||
|
and provides a regular expression to validate the format of the new tag.
|
||||||
|
1. **Tagging the new release:** Once a valid new tag is entered, the script tags
|
||||||
|
the new release.
|
||||||
|
1. **Pushing the new tag to the remote:** Finally, the script pushes the new tag
|
||||||
|
to the remote repository. From here, you will need to create a new release in
|
||||||
|
GitHub and users can easily reference the new tag in their workflows.
|
17
__tests__/index.test.ts
Normal file
17
__tests__/index.test.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/**
|
||||||
|
* Unit tests for the action's entrypoint, src/index.ts
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as main from '../src/main'
|
||||||
|
|
||||||
|
// Mock the action's entrypoint
|
||||||
|
const runMock = jest.spyOn(main, 'run').mockImplementation()
|
||||||
|
|
||||||
|
describe('index', () => {
|
||||||
|
it('calls run when imported', async () => {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||||
|
require('../src/index')
|
||||||
|
|
||||||
|
expect(runMock).toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
})
|
89
__tests__/main.test.ts
Normal file
89
__tests__/main.test.ts
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
/**
|
||||||
|
* Unit tests for the action's main functionality, src/main.ts
|
||||||
|
*
|
||||||
|
* These should be run as if the action was called from a workflow.
|
||||||
|
* Specifically, the inputs listed in `action.yml` should be set as environment
|
||||||
|
* variables following the pattern `INPUT_<INPUT_NAME>`.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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.SpiedFunction<typeof core.debug>
|
||||||
|
let errorMock: jest.SpiedFunction<typeof core.error>
|
||||||
|
let getInputMock: jest.SpiedFunction<typeof core.getInput>
|
||||||
|
let setFailedMock: jest.SpiedFunction<typeof core.setFailed>
|
||||||
|
let setOutputMock: jest.SpiedFunction<typeof core.setOutput>
|
||||||
|
|
||||||
|
describe('action', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks()
|
||||||
|
|
||||||
|
debugMock = jest.spyOn(core, 'debug').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()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('sets the time output', async () => {
|
||||||
|
// Set the action's inputs as return values from core.getInput()
|
||||||
|
getInputMock.mockImplementation(name => {
|
||||||
|
switch (name) {
|
||||||
|
case 'milliseconds':
|
||||||
|
return '500'
|
||||||
|
default:
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
await main.run()
|
||||||
|
expect(runMock).toHaveReturned()
|
||||||
|
|
||||||
|
// 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(errorMock).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('sets a failed status', async () => {
|
||||||
|
// Set the action's inputs as return values from core.getInput()
|
||||||
|
getInputMock.mockImplementation(name => {
|
||||||
|
switch (name) {
|
||||||
|
case 'milliseconds':
|
||||||
|
return 'this is not a number'
|
||||||
|
default:
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
await main.run()
|
||||||
|
expect(runMock).toHaveReturned()
|
||||||
|
|
||||||
|
// Verify that all of the core library functions were called correctly
|
||||||
|
expect(setFailedMock).toHaveBeenNthCalledWith(
|
||||||
|
1,
|
||||||
|
'milliseconds not a number'
|
||||||
|
)
|
||||||
|
expect(errorMock).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
})
|
25
__tests__/wait.test.ts
Normal file
25
__tests__/wait.test.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/**
|
||||||
|
* 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)
|
||||||
|
})
|
||||||
|
})
|
24
action.yml
Normal file
24
action.yml
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
name: 'The name of your action here'
|
||||||
|
description: 'Provide a description here'
|
||||||
|
author: 'Your name or organization here'
|
||||||
|
|
||||||
|
# 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'
|
||||||
|
required: true
|
||||||
|
default: '1000'
|
||||||
|
|
||||||
|
# Define your outputs here.
|
||||||
|
outputs:
|
||||||
|
time:
|
||||||
|
description: 'Your output description here'
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: node20
|
||||||
|
main: dist/index.js
|
1
badges/coverage.svg
Normal file
1
badges/coverage.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="106" height="20" role="img" aria-label="Coverage: 100%"><title>Coverage: 100%</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="106" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="63" height="20" fill="#555"/><rect x="63" width="43" height="20" fill="#4c1"/><rect width="106" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="325" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="530">Coverage</text><text x="325" y="140" transform="scale(.1)" fill="#fff" textLength="530">Coverage</text><text aria-hidden="true" x="835" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="330">100%</text><text x="835" y="140" transform="scale(.1)" fill="#fff" textLength="330">100%</text></g></svg>
|
After Width: | Height: | Size: 1.1 KiB |
BIN
dist/index.js
generated
vendored
Normal file
BIN
dist/index.js
generated
vendored
Normal file
Binary file not shown.
BIN
dist/index.js.map
generated
vendored
Normal file
BIN
dist/index.js.map
generated
vendored
Normal file
Binary file not shown.
BIN
dist/licenses.txt
generated
vendored
Normal file
BIN
dist/licenses.txt
generated
vendored
Normal file
Binary file not shown.
BIN
dist/sourcemap-register.js
generated
vendored
Normal file
BIN
dist/sourcemap-register.js
generated
vendored
Normal file
Binary file not shown.
7400
package-lock.json
generated
Normal file
7400
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
89
package.json
Normal file
89
package.json
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
{
|
||||||
|
"name": "typescript-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"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"bundle": "npm run format:write && npm run package",
|
||||||
|
"ci-test": "npx jest",
|
||||||
|
"coverage": "npx make-coverage-badge --output-path ./badges/coverage.svg",
|
||||||
|
"format:write": "npx prettier --write .",
|
||||||
|
"format:check": "npx prettier --check .",
|
||||||
|
"lint": "npx eslint . -c ./.github/linters/.eslintrc.yml",
|
||||||
|
"package": "npx ncc build src/index.ts -o dist --source-map --license licenses.txt",
|
||||||
|
"package:watch": "npm run package -- --watch",
|
||||||
|
"test": "npx jest",
|
||||||
|
"all": "npm run format:write && npm run lint && npm run test && npm run coverage && npm run package"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"jest": {
|
||||||
|
"preset": "ts-jest",
|
||||||
|
"verbose": true,
|
||||||
|
"clearMocks": true,
|
||||||
|
"testEnvironment": "node",
|
||||||
|
"moduleFileExtensions": [
|
||||||
|
"js",
|
||||||
|
"ts"
|
||||||
|
],
|
||||||
|
"testMatch": [
|
||||||
|
"**/*.test.ts"
|
||||||
|
],
|
||||||
|
"testPathIgnorePatterns": [
|
||||||
|
"/node_modules/",
|
||||||
|
"/dist/"
|
||||||
|
],
|
||||||
|
"transform": {
|
||||||
|
"^.+\\.ts$": "ts-jest"
|
||||||
|
},
|
||||||
|
"coverageReporters": [
|
||||||
|
"json-summary",
|
||||||
|
"text",
|
||||||
|
"lcov"
|
||||||
|
],
|
||||||
|
"collectCoverage": true,
|
||||||
|
"collectCoverageFrom": [
|
||||||
|
"./src/**"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@actions/core": "^1.10.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/jest": "^29.5.12",
|
||||||
|
"@types/node": "^20.11.28",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
||||||
|
"@typescript-eslint/parser": "^7.2.0",
|
||||||
|
"@vercel/ncc": "^0.38.1",
|
||||||
|
"eslint": "^8.57.0",
|
||||||
|
"eslint-plugin-github": "^4.10.2",
|
||||||
|
"eslint-plugin-jest": "^27.9.0",
|
||||||
|
"eslint-plugin-jsonc": "^2.13.0",
|
||||||
|
"eslint-plugin-prettier": "^5.1.3",
|
||||||
|
"jest": "^29.7.0",
|
||||||
|
"make-coverage-badge": "^1.2.0",
|
||||||
|
"prettier": "^3.2.5",
|
||||||
|
"prettier-eslint": "^16.3.0",
|
||||||
|
"ts-jest": "^29.1.2",
|
||||||
|
"typescript": "^5.4.2"
|
||||||
|
}
|
||||||
|
}
|
59
script/release
Executable file
59
script/release
Executable file
@ -0,0 +1,59 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# About:
|
||||||
|
#
|
||||||
|
# This is a helper script to tag and push a new release. GitHub Actions use
|
||||||
|
# release tags to allow users to select a specific version of the action to use.
|
||||||
|
#
|
||||||
|
# See: https://github.com/actions/typescript-action#publishing-a-new-release
|
||||||
|
#
|
||||||
|
# This script will do the following:
|
||||||
|
#
|
||||||
|
# 1. Get the latest release tag
|
||||||
|
# 2. Prompt the user for a new release tag
|
||||||
|
# 3. Tag the new release
|
||||||
|
# 4. Push the new tag to the remote
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
#
|
||||||
|
# script/release
|
||||||
|
|
||||||
|
# Terminal colors
|
||||||
|
OFF='\033[0m'
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
|
||||||
|
# Get the latest release tag
|
||||||
|
latest_tag=$(git describe --tags "$(git rev-list --tags --max-count=1)")
|
||||||
|
|
||||||
|
if [[ -z "$latest_tag" ]]; then
|
||||||
|
# There are no existing release tags
|
||||||
|
echo -e "No tags found (yet) - Continue to create and push your first tag"
|
||||||
|
latest_tag="[unknown]"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Display the latest release tag
|
||||||
|
echo -e "The latest release tag is: ${BLUE}${latest_tag}${OFF}"
|
||||||
|
|
||||||
|
# Prompt the user for the new release tag
|
||||||
|
read -r -p 'Enter a new release tag (vX.X.X format): ' new_tag
|
||||||
|
|
||||||
|
# Validate the new release tag
|
||||||
|
tag_regex='v[0-9]+\.[0-9]+\.[0-9]+$'
|
||||||
|
if echo "$new_tag" | grep -q -E "$tag_regex"; then
|
||||||
|
echo -e "Tag: ${BLUE}$new_tag${OFF} is valid"
|
||||||
|
else
|
||||||
|
# Release tag is not `vX.X.X` format
|
||||||
|
echo -e "Tag: ${BLUE}$new_tag${OFF} is ${RED}not valid${OFF} (must be in vX.X.X format)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Tag the new release
|
||||||
|
git tag -a "$new_tag" -m "$new_tag Release"
|
||||||
|
echo -e "${GREEN}Tagged: $new_tag${OFF}"
|
||||||
|
|
||||||
|
# Push the new tag to the remote
|
||||||
|
git push --tags
|
||||||
|
echo -e "${GREEN}Release tag pushed to remote${OFF}"
|
||||||
|
echo -e "${GREEN}Done!${OFF}"
|
7
src/index.ts
Normal file
7
src/index.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
/**
|
||||||
|
* The entrypoint for the action.
|
||||||
|
*/
|
||||||
|
import { run } from './main'
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
|
run()
|
26
src/main.ts
Normal file
26
src/main.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import * as core from '@actions/core'
|
||||||
|
import { wait } from './wait'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main function for the action.
|
||||||
|
* @returns {Promise<void>} Resolves when the action is complete.
|
||||||
|
*/
|
||||||
|
export async function run(): Promise<void> {
|
||||||
|
try {
|
||||||
|
const ms: string = 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 wait(parseInt(ms, 10))
|
||||||
|
core.debug(new Date().toTimeString())
|
||||||
|
|
||||||
|
// Set outputs for other workflow steps to use
|
||||||
|
core.setOutput('time', new Date().toTimeString())
|
||||||
|
} catch (error) {
|
||||||
|
// Fail the workflow run if an error occurs
|
||||||
|
if (error instanceof Error) core.setFailed(error.message)
|
||||||
|
}
|
||||||
|
}
|
14
src/wait.ts
Normal file
14
src/wait.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* Wait for a number of milliseconds.
|
||||||
|
* @param milliseconds The number of milliseconds to wait.
|
||||||
|
* @returns {Promise<string>} Resolves with 'done!' after the wait is over.
|
||||||
|
*/
|
||||||
|
export async function wait(milliseconds: number): Promise<string> {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
if (isNaN(milliseconds)) {
|
||||||
|
throw new Error('milliseconds not a number')
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => resolve('done!'), milliseconds)
|
||||||
|
})
|
||||||
|
}
|
19
tsconfig.json
Normal file
19
tsconfig.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json.schemastore.org/tsconfig",
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2022",
|
||||||
|
"module": "NodeNext",
|
||||||
|
"rootDir": "./src",
|
||||||
|
"moduleResolution": "NodeNext",
|
||||||
|
"baseUrl": "./",
|
||||||
|
"sourceMap": true,
|
||||||
|
"outDir": "./dist",
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"strict": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"newLine": "lf"
|
||||||
|
},
|
||||||
|
"exclude": ["./dist", "./node_modules", "./__tests__", "./coverage"]
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user