Merge pull request #331 from actions/ncalteen-format

Format and add testing/CI
This commit is contained in:
Nick Alteen
2023-09-15 09:37:56 -04:00
committed by GitHub
34 changed files with 5947 additions and 4340 deletions

View File

@ -1 +1,4 @@
lib/
dist/ dist/
node_modules/
coverage/

View File

@ -1,18 +0,0 @@
{
"env": {
"commonjs": true,
"es6": true,
"jest": true,
"node": true
},
"extends": "eslint:recommended",
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parserOptions": {
"ecmaVersion": 2018
},
"rules": {
}
}

2
.gitattributes vendored
View File

@ -1 +1 @@
dist/** -diff linguist-generated=true dist/** -diff linguist-generated=true

View File

@ -1,5 +1,5 @@
name: "javascript-action CodeQL config" name: JavaScript CodeQL Configuration
paths-ignore: paths-ignore:
- node_modules - node_modules
- dist - dist

View File

@ -2,10 +2,16 @@ version: 2
updates: updates:
- package-ecosystem: github-actions - package-ecosystem: github-actions
directory: / directory: /
labels:
- dependabot
- actions
schedule: schedule:
interval: daily interval: daily
- package-ecosystem: npm - package-ecosystem: npm
directory: / directory: /
labels:
- dependabot
- npm
schedule: schedule:
interval: daily interval: daily

50
.github/linters/.eslintrc.yml vendored Normal file
View File

@ -0,0 +1,50 @@
env:
commonjs: true
es6: true
jest: true
node: true
globals:
Atomics: readonly
SharedArrayBuffer: readonly
ignorePatterns:
- '!.*'
- '**/node_modules/.*'
- '**/dist/.*'
- '**/coverage/.*'
- '*.json'
parser: '@babel/eslint-parser'
parserOptions:
ecmaVersion: 2023
sourceType: module
requireConfigFile: false
babelOptions:
babelrc: false
configFile: false
presets:
- jest
plugins:
- jest
extends:
- 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-commonjs': 'off',
'import/no-namespace': 'off',
'no-console': 'off',
'no-unused-vars': 'off',
'prettier/prettier': 'error',
'semi': 'off'
}

7
.github/linters/.markdown-lint.yml vendored Normal file
View File

@ -0,0 +1,7 @@
# Unordered list style
MD004:
style: dash
# Ordered list item prefix
MD029:
style: one

10
.github/linters/.yaml-lint.yml vendored Normal file
View 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

View File

@ -1,8 +1,11 @@
# `dist/index.js` is a special file in Actions. # In JavaScript actions, `dist/index.js` is a special file. When you reference
# When you reference an action with `uses:` in a workflow, # an action with `uses:`, `dist/index.js` is the code that will be run. For this
# `index.js` is the code that will run. # project, the `dist/index.js` file is generated from other source files through
# For our project, we generate this file through a build process from other source files. # the build process. We need to make sure that the checked-in `dist/index.js`
# We need to make sure the checked-in `index.js` actually matches what we expect it to be. # file matches what is expected from the build.
#
# This workflow will fail if the checked-in `dist/index.js` file does not match
# what is expected from the build.
name: Check dist/ name: Check dist/
on: on:
@ -18,33 +21,43 @@ on:
jobs: jobs:
check-dist: check-dist:
name: Check dist/
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: permissions:
- uses: actions/checkout@v3 contents: read
statuses: write
- name: Set Node.js 16.x steps:
uses: actions/setup-node@v3.6.0 - name: Checkout
id: checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v3
with: with:
node-version: 16.x node-version: 20
cache: npm cache: npm
- name: Install dependencies - name: Install Dependencies
id: install
run: npm ci run: npm ci
- name: Rebuild the dist/ directory - name: Build dist/ Directory
run: npm run prepare id: build
run: npm run bundle
- name: Compare the expected and actual dist/ directories - name: Compare Expected and Actual Directories
id: diff
run: | run: |
if [ "$(git diff --ignore-space-at-eol dist/ | wc -l)" -gt "0" ]; then if [ "$(git diff --ignore-space-at-eol --text dist/ | wc -l)" -gt "0" ]; then
echo "Detected uncommitted changes after build. See status below:" echo "Detected uncommitted changes after build. See status below:"
git diff git diff --ignore-space-at-eol --text dist/
exit 1 exit 1
fi fi
id: diff
# If index.js was different than expected, upload the expected version as an artifact # If index.js was different than expected, upload the expected version as
# a workflow artifact.
- uses: actions/upload-artifact@v3 - uses: actions/upload-artifact@v3
if: ${{ failure() && steps.diff.conclusion == 'failure' }} if: ${{ failure() && steps.diff.conclusion == 'failure' }}
with: with:

60
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,60 @@
name: Continuous Integration
on:
pull_request:
push:
branches:
- main
- "releases/*"
jobs:
test-javascript:
name: JavaScript 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@v3
with:
node-version: 20
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: 1000
- name: Print Output
id: output
run: echo "${{ steps.test-action.outputs.time }}"

44
.github/workflows/linter.yml vendored Normal file
View File

@ -0,0 +1,44 @@
name: Lint Code Base
on:
pull_request:
branches:
- main
push:
branches-ignore:
- main
jobs:
lint:
name: Lint Code Base
runs-on: ubuntu-latest
permissions:
contents: read
packages: read
statuses: write
steps:
- name: Checkout
id: checkout
uses: actions/checkout@v4
- name: Setup Node.js
id: setup-node
uses: actions/setup-node@v3
with:
node-version: 20
cache: npm
- name: Install Dependencies
id: install
run: npm ci
- name: Lint Code Base
id: super-linter
uses: super-linter/super-linter/slim@v5
env:
DEFAULT_BRANCH: main
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
JAVASCRIPT_DEFAULT_STYLE: prettier
VALIDATE_JSCPD: false

View File

@ -1,25 +0,0 @@
name: "units-test"
on:
pull_request:
push:
branches:
- main
- 'releases/*'
jobs:
# unit tests
units:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: npm ci
- run: npm test
# test action works running from the graph
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ./
with:
milliseconds: 1000

52
.gitignore vendored
View File

@ -1,16 +1,17 @@
node_modules/ # Dependency directory
node_modules
# Editors
.vscode/
.idea/
*.iml
# Rest pulled from https://github.com/github/gitignore/blob/master/Node.gitignore
# Logs # Logs
logs logs
*.log *.log
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.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 # Runtime data
pids pids
@ -23,11 +24,12 @@ lib-cov
# Coverage directory used by tools like istanbul # Coverage directory used by tools like istanbul
coverage coverage
*.lcov
# nyc test coverage # nyc test coverage
.nyc_output .nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt .grunt
# Bower dependency directory (https://bower.io/) # Bower dependency directory (https://bower.io/)
@ -39,12 +41,15 @@ bower_components
# Compiled binary addons (https://nodejs.org/api/addons.html) # Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release build/Release
# Other Dependency directories # Dependency directories
jspm_packages/ jspm_packages/
# TypeScript v1 declaration files # TypeScript v1 declaration files
typings/ typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory # Optional npm cache directory
.npm .npm
@ -62,6 +67,37 @@ typings/
# dotenv environment variables file # dotenv environment variables file
.env .env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# next.js build output # next.js build output
.next .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

3
.prettierignore Normal file
View File

@ -0,0 +1,3 @@
dist/
node_modules/
coverage/

16
.prettierrc.json Normal file
View 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"
}

View File

@ -1 +1,4 @@
# Repository CODEOWNERS
* @actions/actions-runtime * @actions/actions-runtime
* @ncalteen

View File

@ -1,4 +1,5 @@
MIT License
The MIT License (MIT)
Copyright (c) 2019 GitHub Actions Copyright (c) 2019 GitHub Actions

229
README.md
View File

@ -1,116 +1,199 @@
# Create a JavaScript Action # Create a JavaScript Action
<p align="center"> [![GitHub Super-Linter](https://github.com/actions/javascript-action/actions/workflows/linter.yml/badge.svg)](https://github.com/super-linter/super-linter)
<a href="https://github.com/actions/javascript-action/actions"><img alt="javscript-action status" src="https://github.com/actions/javascript-action/workflows/units-test/badge.svg"></a> ![CI](https://github.com/actions/javascript-action/actions/workflows/ci.yml/badge.svg)
</p>
Use this template to bootstrap the creation of a JavaScript action.:rocket: Use this template to bootstrap the creation of a JavaScript action. :rocket:
This template includes tests, linting, a validation workflow, publishing, and versioning guidance. This template includes compilation support, tests, a validation workflow,
publishing, and versioning guidance.
If you are new, there's also a simpler introduction. See the [Hello World JavaScript Action](https://github.com/actions/hello-world-javascript-action) 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 an action from this template ## Create Your Own Action
Click the `Use this Template` and provide the new repo details for your action To create your own action, you can use this repository as a template! Just
follow the below instructions:
## Code in Main 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
Install the dependencies ## Initial Setup
```bash After you've cloned the repository to your local machine or codespace, you'll
npm install need to perform some initial setup steps before you can develop your action.
```
Run the tests :heavy_check_mark: > [!NOTE]
>
> You'll need to have a reasonably modern version of
> [Node.js](https://nodejs.org) handy. If you are using a version manager like
> [`nodenv`](https://github.com/nodenv/nodenv) or
> [`nvm`](https://github.com/nvm-sh/nvm), you can run `nodenv install` in the
> root of your repository to install the version specified in
> [`package.json`](./package.json). Otherwise, 20.x or later should work!
```bash 1. :hammer_and_wrench: Install the dependencies
$ npm test
PASS ./index.test.js ```bash
✓ throws invalid number (3ms) npm install
wait 500 ms (504ms) ```
test runs (95ms)
...
```
## Change action.yml 1. :building_construction: Package the JavaScript for distribution
The action.yml defines the inputs and output for your action. ```bash
npm run bundle
```
Update the action.yml with your name, description, inputs and outputs for your action. 1. :white_check_mark: Run the tests
See the [documentation](https://help.github.com/en/articles/metadata-syntax-for-github-actions) ```bash
$ npm test
## Change the Code PASS ./index.test.js
✓ throws invalid number (3ms)
✓ wait 500 ms (504ms)
✓ test runs (95ms)
Most toolkit and CI/CD operations involve async operations so the action is run in an async function. ...
```
```javascript ## Update the Action Metadata
const core = require('@actions/core');
...
async function run() { The [`action.yml`](action.yml) file defines metadata about your action, such as
try { 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.js`, you will see that the action is run in an `async` function.
```javascript
const core = require('@actions/core')
//...
async function run() {
try {
//...
} catch (error) {
core.setFailed(error.message)
}
} }
catch (error) { ```
core.setFailed(error.message);
}
}
run() For more information about the GitHub Actions toolkit, see the
``` [documentation](https://github.com/actions/toolkit/blob/master/README.md).
See the [toolkit documentation](https://github.com/actions/toolkit/blob/master/README.md#packages) for the various packages. So, what are you waiting for? Go ahead and start customizing your action!
## Package for distribution 1. Create a new branch
GitHub Actions will run the entry point from the action.yml. Packaging assembles the code into one file that can be checked in to Git, enabling fast and reliable execution and preventing the need to check in node_modules. ```bash
git checkout -b releases/v1
```
Actions are run from GitHub repos. Packaging the action will create a packaged action in the dist folder. 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
Run prepare ```bash
npm run all
```
```bash > [!WARNING]
npm run prepare >
``` > 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.
Since the packaged index.js is run from the dist folder. 1. Commit your changes
```bash ```bash
git add dist git add .
``` git commit -m "My first action is ready!"
```
## Create a release branch 1. Push them to your repository
Users shouldn't consume the action from master since that would be latest code and actions can break compatibility between major versions. ```bash
git push -u origin releases/v1
```
Checkin to the v1 release branch 1. Create a pull request and get feedback on your action
1. Merge the pull request into the `main` branch
```bash
git checkout -b v1
git commit -a -m "v1 release"
```
```bash
git push origin v1
```
Note: We recommend using the `--license` option for ncc, which will create a license file for all of the production node modules used in your project.
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) 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@v3
- 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/javascript-action/actions)! :rocket:
## Usage ## Usage
You can now consume the action by referencing the v1 branch 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 ```yaml
uses: actions/javascript-action@v1 steps:
with: - name: Checkout
milliseconds: 1000 id: checkout
``` uses: actions/checkout@v4
See the [actions tab](https://github.com/actions/javascript-action/actions) for runs of this action! :rocket: - name: Run my Action
id: run-action
uses: actions/javascript-action@v1 # Commit with the `v1` tag
with:
milliseconds: 1000
- name: Print Output
id: output
run: echo "${{ steps.test-action.outputs.time }}"
```

18
__tests__/index.test.js Normal file
View File

@ -0,0 +1,18 @@
/**
* Unit tests for the action's entrypoint, src/index.ts
*/
const { run } = require('../src/main')
// Mock the action's entrypoint
jest.mock('../src/main', () => ({
run: jest.fn()
}))
describe('index', () => {
it('calls run when imported', async () => {
require('../src/index')
expect(run).toHaveBeenCalled()
})
})

100
__tests__/main.test.js Normal file
View File

@ -0,0 +1,100 @@
/**
* 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>`.
*/
const core = require('@actions/core')
const main = require('../src/main')
// Mock the GitHub Actions core library
const debugMock = jest.spyOn(core, 'debug').mockImplementation()
const getInputMock = jest.spyOn(core, 'getInput').mockImplementation()
const setFailedMock = jest.spyOn(core, 'setFailed').mockImplementation()
const setOutputMock = jest.spyOn(core, 'setOutput').mockImplementation()
// Mock the action's main function
const runMock = jest.spyOn(main, 'run')
// Other utilities
const timeRegex = /^\d{2}:\d{2}:\d{2}/
describe('action', () => {
beforeEach(() => {
jest.clearAllMocks()
})
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)
)
})
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'
)
})
it('fails if no input is provided', async () => {
// Set the action's inputs as return values from core.getInput()
getInputMock.mockImplementation(name => {
switch (name) {
case 'milliseconds':
throw new Error('Input required and not supplied: milliseconds')
default:
return ''
}
})
await main.run()
expect(runMock).toHaveReturned()
// Verify that all of the core library functions were called correctly
expect(setFailedMock).toHaveBeenNthCalledWith(
1,
'Input required and not supplied: milliseconds'
)
})
})

24
__tests__/wait.test.js Normal file
View File

@ -0,0 +1,24 @@
/**
* Unit tests for src/wait.ts
*/
const { wait } = require('../src/wait')
const { expect } = require('@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)
})
})

View File

@ -1,13 +1,19 @@
name: 'Wait' name: 'The name of your action here'
description: 'Wait a designated number of milliseconds' description: 'Provide a description here'
author: 'Your name or organization here'
# Define your inputs here.
inputs: inputs:
milliseconds: # id of input milliseconds:
description: 'number of milliseconds to wait' description: 'Your input description here'
required: true required: true
default: '1000' default: '1000'
# Define your outputs here.
outputs: outputs:
time: # output will be available to future steps time:
description: 'The current time after waiting' description: 'Your output description here'
runs: runs:
using: 'node16' using: node20
main: 'dist/index.js' main: dist/index.js

1
badges/coverage.svg Normal file
View 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

136
dist/index.js generated vendored
View File

@ -1,7 +1,7 @@
require('./sourcemap-register.js');/******/ (() => { // webpackBootstrap /******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({ /******/ var __webpack_modules__ = ({
/***/ 351: /***/ 241:
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
"use strict"; "use strict";
@ -135,7 +135,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
}; };
Object.defineProperty(exports, "__esModule", ({ value: true })); Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.getIDToken = exports.getState = exports.saveState = exports.group = exports.endGroup = exports.startGroup = exports.info = exports.notice = exports.warning = exports.error = exports.debug = exports.isDebug = exports.setFailed = exports.setCommandEcho = exports.setOutput = exports.getBooleanInput = exports.getMultilineInput = exports.getInput = exports.addPath = exports.setSecret = exports.exportVariable = exports.ExitCode = void 0; exports.getIDToken = exports.getState = exports.saveState = exports.group = exports.endGroup = exports.startGroup = exports.info = exports.notice = exports.warning = exports.error = exports.debug = exports.isDebug = exports.setFailed = exports.setCommandEcho = exports.setOutput = exports.getBooleanInput = exports.getMultilineInput = exports.getInput = exports.addPath = exports.setSecret = exports.exportVariable = exports.ExitCode = void 0;
const command_1 = __nccwpck_require__(351); const command_1 = __nccwpck_require__(241);
const file_command_1 = __nccwpck_require__(717); const file_command_1 = __nccwpck_require__(717);
const utils_1 = __nccwpck_require__(278); const utils_1 = __nccwpck_require__(278);
const os = __importStar(__nccwpck_require__(37)); const os = __importStar(__nccwpck_require__(37));
@ -558,7 +558,7 @@ class OidcClient {
.catch(error => { .catch(error => {
throw new Error(`Failed to get ID Token. \n throw new Error(`Failed to get ID Token. \n
Error Code : ${error.statusCode}\n Error Code : ${error.statusCode}\n
Error Message: ${error.result.message}`); Error Message: ${error.message}`);
}); });
const id_token = (_a = res.result) === null || _a === void 0 ? void 0 : _a.value; const id_token = (_a = res.result) === null || _a === void 0 ? void 0 : _a.value;
if (!id_token) { if (!id_token) {
@ -1211,6 +1211,19 @@ class HttpClientResponse {
})); }));
}); });
} }
readBodyBuffer() {
return __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
const chunks = [];
this.message.on('data', (chunk) => {
chunks.push(chunk);
});
this.message.on('end', () => {
resolve(Buffer.concat(chunks));
});
}));
});
}
} }
exports.HttpClientResponse = HttpClientResponse; exports.HttpClientResponse = HttpClientResponse;
function isHttps(requestUrl) { function isHttps(requestUrl) {
@ -1715,7 +1728,13 @@ function getProxyUrl(reqUrl) {
} }
})(); })();
if (proxyVar) { if (proxyVar) {
return new URL(proxyVar); try {
return new URL(proxyVar);
}
catch (_a) {
if (!proxyVar.startsWith('http://') && !proxyVar.startsWith('https://'))
return new URL(`http://${proxyVar}`);
}
} }
else { else {
return undefined; return undefined;
@ -1726,6 +1745,10 @@ function checkBypass(reqUrl) {
if (!reqUrl.hostname) { if (!reqUrl.hostname) {
return false; return false;
} }
const reqHost = reqUrl.hostname;
if (isLoopbackAddress(reqHost)) {
return true;
}
const noProxy = process.env['no_proxy'] || process.env['NO_PROXY'] || ''; const noProxy = process.env['no_proxy'] || process.env['NO_PROXY'] || '';
if (!noProxy) { if (!noProxy) {
return false; return false;
@ -1751,13 +1774,24 @@ function checkBypass(reqUrl) {
.split(',') .split(',')
.map(x => x.trim().toUpperCase()) .map(x => x.trim().toUpperCase())
.filter(x => x)) { .filter(x => x)) {
if (upperReqHosts.some(x => x === upperNoProxyItem)) { if (upperNoProxyItem === '*' ||
upperReqHosts.some(x => x === upperNoProxyItem ||
x.endsWith(`.${upperNoProxyItem}`) ||
(upperNoProxyItem.startsWith('.') &&
x.endsWith(`${upperNoProxyItem}`)))) {
return true; return true;
} }
} }
return false; return false;
} }
exports.checkBypass = checkBypass; exports.checkBypass = checkBypass;
function isLoopbackAddress(host) {
const hostLower = host.toLowerCase();
return (hostLower === 'localhost' ||
hostLower.startsWith('127.') ||
hostLower.startsWith('[::1]') ||
hostLower.startsWith('[0:0:0:0:0:0:0:1]'));
}
//# sourceMappingURL=proxy.js.map //# sourceMappingURL=proxy.js.map
/***/ }), /***/ }),
@ -2688,19 +2722,63 @@ exports["default"] = _default;
/***/ }), /***/ }),
/***/ 258: /***/ 713:
/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
const core = __nccwpck_require__(186)
const { wait } = __nccwpck_require__(312)
/**
* The main function for the action.
* @returns {Promise<void>} Resolves when the action is complete.
*/
async function run() {
try {
const ms = core.getInput('milliseconds', { required: true })
// 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
core.setFailed(error.message)
}
}
module.exports = {
run
}
/***/ }),
/***/ 312:
/***/ ((module) => { /***/ ((module) => {
let wait = function (milliseconds) { /**
return new Promise((resolve) => { * Wait for a number of milliseconds.
if (typeof milliseconds !== 'number') { *
throw new Error('milliseconds not a number'); * @param {number} milliseconds The number of milliseconds to wait.
* @returns {Promise<string>} 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)
});
};
module.exports = wait; setTimeout(() => resolve('done!'), milliseconds)
})
}
module.exports = { wait }
/***/ }), /***/ }),
@ -2834,31 +2912,15 @@ module.exports = require("util");
var __webpack_exports__ = {}; var __webpack_exports__ = {};
// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. // This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
(() => { (() => {
const core = __nccwpck_require__(186); /**
const wait = __nccwpck_require__(258); * The entrypoint for the action.
*/
const { run } = __nccwpck_require__(713)
run()
// most @actions toolkit packages have async methods
async function run() {
try {
const ms = core.getInput('milliseconds');
core.info(`Waiting ${ms} milliseconds ...`);
core.debug((new Date()).toTimeString()); // debug is only output if you set the secret `ACTIONS_RUNNER_DEBUG` to true
await wait(parseInt(ms));
core.info((new Date()).toTimeString());
core.setOutput('time', new Date().toTimeString());
} catch (error) {
core.setFailed(error.message);
}
}
run();
})(); })();
module.exports = __webpack_exports__; module.exports = __webpack_exports__;
/******/ })() /******/ })()
; ;
//# sourceMappingURL=index.js.map

1
dist/index.js.map generated vendored

File diff suppressed because one or more lines are too long

1
dist/sourcemap-register.js generated vendored

File diff suppressed because one or more lines are too long

View File

@ -1,21 +0,0 @@
const core = require('@actions/core');
const wait = require('./wait');
// most @actions toolkit packages have async methods
async function run() {
try {
const ms = core.getInput('milliseconds');
core.info(`Waiting ${ms} milliseconds ...`);
core.debug((new Date()).toTimeString()); // debug is only output if you set the secret `ACTIONS_RUNNER_DEBUG` to true
await wait(parseInt(ms));
core.info((new Date()).toTimeString());
core.setOutput('time', new Date().toTimeString());
} catch (error) {
core.setFailed(error.message);
}
}
run();

View File

@ -1,24 +0,0 @@
const wait = require('./wait');
const process = require('process');
const cp = require('child_process');
const path = require('path');
test('throws invalid number', async () => {
await expect(wait('foo')).rejects.toThrow('milliseconds not a number');
});
test('wait 500 ms', async () => {
const start = new Date();
await wait(500);
const end = new Date();
var delta = Math.abs(end - start);
expect(delta).toBeGreaterThanOrEqual(500);
});
// shows how the runner will run a javascript action with env / stdout protocol
test('test runs', () => {
process.env['INPUT_MILLISECONDS'] = 100;
const ip = path.join(__dirname, 'index.js');
const result = cp.execSync(`node ${ip}`, {env: process.env}).toString();
console.log(result);
})

9208
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,35 +1,81 @@
{ {
"name": "javascript-action", "name": "javascript-action",
"version": "1.0.0", "description": "GitHub Actions JavaScript Template",
"description": "JavaScript Action Template", "version": "0.0.0",
"main": "index.js", "author": "",
"scripts": { "private": true,
"lint": "eslint .", "homepage": "https://github.com/actions/javascript-action#readme",
"prepare": "ncc build index.js -o dist --source-map --license licenses.txt",
"test": "jest",
"all": "npm run lint && npm run test && npm run prepare"
},
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/actions/javascript-action.git" "url": "git+https://github.com/actions/javascript-action.git"
}, },
"bugs": {
"url": "https://github.com/actions/javascript-action/issues"
},
"keywords": [ "keywords": [
"GitHub", "GitHub",
"Actions", "Actions",
"JavaScript" "JavaScript"
], ],
"author": "", "exports": {
"license": "MIT", ".": "./dist/index.js"
"bugs": { },
"url": "https://github.com/actions/javascript-action/issues" "engines": {
"node": ">=20"
},
"scripts": {
"bundle": "npm run format:write && npm run package",
"ci-test": "jest",
"format:write": "prettier --write **/*.js",
"format:check": "prettier --check **/*.js",
"lint": "npx eslint . -c ./.github/linters/.eslintrc.yml",
"package": "ncc build src/index.js --license licenses.txt",
"package:watch": "npm run package -- --watch",
"test": "(jest && make-coverage-badge --output-path ./badges/coverage.svg) || make-coverage-badge --output-path ./badges/coverage.svg",
"all": "npm run format:write && npm run lint && npm run test && npm run package"
},
"license": "MIT",
"eslintConfig": {
"extends": "./.github/linters/.eslintrc.yml"
},
"jest": {
"verbose": true,
"clearMocks": true,
"testEnvironment": "node",
"moduleFileExtensions": [
"js"
],
"testMatch": [
"**/*.test.js"
],
"testPathIgnorePatterns": [
"/node_modules/",
"/dist/"
],
"coverageReporters": [
"json-summary",
"text",
"lcov"
],
"collectCoverage": true,
"collectCoverageFrom": [
"./src/**"
]
}, },
"homepage": "https://github.com/actions/javascript-action#readme",
"dependencies": { "dependencies": {
"@actions/core": "^1.10.0" "@actions/core": "^1.10.1"
}, },
"devDependencies": { "devDependencies": {
"@vercel/ncc": "^0.36.1", "@babel/core": "^7.22.17",
"eslint": "^8.37.0", "@babel/eslint-parser": "^7.22.15",
"jest": "^29.5.0" "@babel/preset-env": "^7.22.15",
"@vercel/ncc": "^0.38.0",
"babel-preset-jest": "^29.6.3",
"eslint": "^8.49.0",
"eslint-plugin-github": "^4.10.0",
"eslint-plugin-jest": "^27.2.3",
"jest": "^29.7.0",
"make-coverage-badge": "^1.2.0",
"prettier": "^3.0.3"
} }
} }

6
src/index.js Normal file
View File

@ -0,0 +1,6 @@
/**
* The entrypoint for the action.
*/
const { run } = require('./main')
run()

30
src/main.js Normal file
View File

@ -0,0 +1,30 @@
const core = require('@actions/core')
const { wait } = require('./wait')
/**
* The main function for the action.
* @returns {Promise<void>} Resolves when the action is complete.
*/
async function run() {
try {
const ms = core.getInput('milliseconds', { required: true })
// 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
core.setFailed(error.message)
}
}
module.exports = {
run
}

17
src/wait.js Normal file
View File

@ -0,0 +1,17 @@
/**
* Wait for a number of milliseconds.
*
* @param {number} milliseconds The number of milliseconds to wait.
* @returns {Promise<string>} 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)
})
}
module.exports = { wait }

10
wait.js
View File

@ -1,10 +0,0 @@
let wait = function (milliseconds) {
return new Promise((resolve) => {
if (typeof milliseconds !== 'number') {
throw new Error('milliseconds not a number');
}
setTimeout(() => resolve("done!"), milliseconds)
});
};
module.exports = wait;