├── .devcontainer └── devcontainer.json ├── .env.example ├── .gitattributes ├── .github ├── codeql │ └── codeql-config.yml ├── dependabot.yml └── workflows │ ├── check-dist.yml │ ├── ci.yml │ ├── codeql-analysis.yml │ ├── licensed.yml │ └── linter.yml ├── .gitignore ├── .licensed.yml ├── .licenses └── npm │ ├── @actions │ ├── core.dep.yml │ ├── exec.dep.yml │ ├── http-client.dep.yml │ └── io.dep.yml │ ├── @fastify │ └── busboy.dep.yml │ ├── tunnel.dep.yml │ └── undici.dep.yml ├── .markdown-lint.yml ├── .node-version ├── .prettierignore ├── .prettierrc.yml ├── .vscode └── launch.json ├── .yaml-lint.yml ├── CODEOWNERS ├── LICENSE ├── README.md ├── __fixtures__ ├── core.js └── wait.js ├── __tests__ ├── main.test.js └── wait.test.js ├── action.yml ├── badges └── coverage.svg ├── dist ├── index.js └── index.js.map ├── eslint.config.mjs ├── jest.config.js ├── package-lock.json ├── package.json ├── rollup.config.js └── src ├── index.js ├── main.js └── wait.js /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "GitHub Actions (JavaScript)", 3 | "image": "mcr.microsoft.com/devcontainers/javascript-node:20", 4 | "postCreateCommand": "npm install", 5 | "customizations": { 6 | "codespaces": { 7 | "openFiles": ["README.md"] 8 | }, 9 | "vscode": { 10 | "extensions": [ 11 | "bierner.markdown-preview-github-styles", 12 | "davidanson.vscode-markdownlint", 13 | "dbaeumer.vscode-eslint", 14 | "esbenp.prettier-vscode", 15 | "github.copilot", 16 | "github.copilot-chat", 17 | "github.vscode-github-actions", 18 | "github.vscode-pull-request-github", 19 | "me-dutour-mathieu.vscode-github-actions", 20 | "redhat.vscode-yaml", 21 | "rvest.vs-code-prettier-eslint", 22 | "yzhang.markdown-all-in-one" 23 | ], 24 | "settings": { 25 | "editor.defaultFormatter": "esbenp.prettier-vscode", 26 | "editor.tabSize": 2, 27 | "editor.formatOnSave": true, 28 | "markdown.extension.list.indentationSize": "adaptive", 29 | "markdown.extension.italic.indicator": "_", 30 | "markdown.extension.orderedList.marker": "one" 31 | } 32 | } 33 | }, 34 | "remoteEnv": { 35 | "GITHUB_TOKEN": "${localEnv:GITHUB_TOKEN}" 36 | }, 37 | "features": { 38 | "ghcr.io/devcontainers/features/github-cli:1": {}, 39 | "ghcr.io/devcontainers-contrib/features/prettier:1": {} 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | # Do not commit your actual .env file to Git! This may contain secrets or other 2 | # private information. 3 | 4 | # Enable/disable step debug logging (default: `false`). For local debugging, it 5 | # may be useful to set it to `true`. 6 | ACTIONS_STEP_DEBUG=true 7 | 8 | # GitHub Actions inputs should follow `INPUT_` format (case-sensitive). 9 | # Hyphens should not be converted to underscores! 10 | INPUT_MILLISECONDS=2400 11 | 12 | # GitHub Actions default environment variables. These are set for every run of a 13 | # workflow and can be used in your actions. Setting the value here will override 14 | # any value set by the local-action tool. 15 | # https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables 16 | 17 | # CI="true" 18 | # GITHUB_ACTION="" 19 | # GITHUB_ACTION_PATH="" 20 | # GITHUB_ACTION_REPOSITORY="" 21 | # GITHUB_ACTIONS="" 22 | # GITHUB_ACTOR="" 23 | # GITHUB_ACTOR_ID="" 24 | # GITHUB_API_URL="" 25 | # GITHUB_BASE_REF="" 26 | # GITHUB_ENV="" 27 | # GITHUB_EVENT_NAME="" 28 | # GITHUB_EVENT_PATH="" 29 | # GITHUB_GRAPHQL_URL="" 30 | # GITHUB_HEAD_REF="" 31 | # GITHUB_JOB="" 32 | # GITHUB_OUTPUT="" 33 | # GITHUB_PATH="" 34 | # GITHUB_REF="" 35 | # GITHUB_REF_NAME="" 36 | # GITHUB_REF_PROTECTED="" 37 | # GITHUB_REF_TYPE="" 38 | # GITHUB_REPOSITORY="" 39 | # GITHUB_REPOSITORY_ID="" 40 | # GITHUB_REPOSITORY_OWNER="" 41 | # GITHUB_REPOSITORY_OWNER_ID="" 42 | # GITHUB_RETENTION_DAYS="" 43 | # GITHUB_RUN_ATTEMPT="" 44 | # GITHUB_RUN_ID="" 45 | # GITHUB_RUN_NUMBER="" 46 | # GITHUB_SERVER_URL="" 47 | # GITHUB_SHA="" 48 | # GITHUB_STEP_SUMMARY="" 49 | # GITHUB_TRIGGERING_ACTOR="" 50 | # GITHUB_WORKFLOW="" 51 | # GITHUB_WORKFLOW_REF="" 52 | # GITHUB_WORKFLOW_SHA="" 53 | # GITHUB_WORKSPACE="" 54 | # RUNNER_ARCH="" 55 | # RUNNER_DEBUG="" 56 | # RUNNER_NAME="" 57 | # RUNNER_OS="" 58 | # RUNNER_TEMP="" 59 | # RUNNER_TOOL_CACHE="" 60 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | 3 | dist/** -diff linguist-generated=true 4 | -------------------------------------------------------------------------------- /.github/codeql/codeql-config.yml: -------------------------------------------------------------------------------- 1 | name: JavaScript CodeQL Configuration 2 | 3 | paths-ignore: 4 | - node_modules 5 | - dist 6 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: / 5 | schedule: 6 | interval: weekly 7 | groups: 8 | actions-minor: 9 | update-types: 10 | - minor 11 | - patch 12 | 13 | - package-ecosystem: npm 14 | directory: / 15 | schedule: 16 | interval: weekly 17 | groups: 18 | npm-development: 19 | dependency-type: development 20 | update-types: 21 | - minor 22 | - patch 23 | npm-production: 24 | dependency-type: production 25 | update-types: 26 | - patch 27 | -------------------------------------------------------------------------------- /.github/workflows/check-dist.yml: -------------------------------------------------------------------------------- 1 | # In JavaScript actions, `dist/` is a special directory. When you reference 2 | # an action with the `uses:` property, `dist/index.js` is the code that will be 3 | # run. For this project, the `dist/index.js` file is transpiled from other 4 | # source files. This workflow ensures the `dist/` directory contains the 5 | # expected transpiled code. 6 | # 7 | # If this workflow is run from a feature branch, it will act as an additional CI 8 | # check and fail if the checked-in `dist/` directory does not match what is 9 | # expected from the build. 10 | name: Check Transpiled JavaScript 11 | 12 | on: 13 | pull_request: 14 | branches: 15 | - main 16 | push: 17 | branches: 18 | - main 19 | 20 | permissions: 21 | contents: read 22 | 23 | jobs: 24 | check-dist: 25 | name: Check dist/ 26 | runs-on: ubuntu-latest 27 | 28 | steps: 29 | # Checkout the repository. 30 | - name: Checkout 31 | id: checkout 32 | uses: actions/checkout@v4 33 | 34 | # Setup Node.js using the version specified in `.node-version`. 35 | - name: Setup Node.js 36 | id: setup-node 37 | uses: actions/setup-node@v4 38 | with: 39 | node-version-file: .node-version 40 | cache: npm 41 | 42 | # Install dependencies using `npm ci`. 43 | - name: Install Dependencies 44 | id: install 45 | run: npm ci 46 | 47 | # Build the `dist/` directory. 48 | - name: Build dist/ Directory 49 | id: build 50 | run: npm run bundle 51 | 52 | # This will fail the workflow if the `dist/` directory is different than 53 | # expected. 54 | - name: Compare Directories 55 | id: diff 56 | run: | 57 | if [ ! -d dist/ ]; then 58 | echo "Expected dist/ directory does not exist. See status below:" 59 | ls -la ./ 60 | exit 1 61 | fi 62 | if [ "$(git diff --ignore-space-at-eol --text dist/ | wc -l)" -gt "0" ]; then 63 | echo "Detected uncommitted changes after build. See status below:" 64 | git diff --ignore-space-at-eol --text dist/ 65 | exit 1 66 | fi 67 | 68 | # If `dist/` was different than expected, upload the expected version as a 69 | # workflow artifact. 70 | - if: ${{ failure() && steps.diff.outcome == 'failure' }} 71 | name: Upload Artifact 72 | id: upload 73 | uses: actions/upload-artifact@v4 74 | with: 75 | name: dist 76 | path: dist/ 77 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Continuous Integration 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | push: 8 | branches: 9 | - main 10 | 11 | permissions: 12 | contents: read 13 | 14 | jobs: 15 | test-javascript: 16 | name: JavaScript Tests 17 | runs-on: ubuntu-latest 18 | 19 | steps: 20 | - name: Checkout 21 | id: checkout 22 | uses: actions/checkout@v4 23 | 24 | - name: Setup Node.js 25 | id: setup-node 26 | uses: actions/setup-node@v4 27 | with: 28 | node-version-file: .node-version 29 | cache: npm 30 | 31 | - name: Install Dependencies 32 | id: npm-ci 33 | run: npm ci 34 | 35 | - name: Check Format 36 | id: npm-format-check 37 | run: npm run format:check 38 | 39 | - name: Lint 40 | id: npm-lint 41 | run: npm run lint 42 | 43 | - name: Test 44 | id: npm-ci-test 45 | run: npm run ci-test 46 | 47 | test-action: 48 | name: GitHub Actions Test 49 | runs-on: ubuntu-latest 50 | 51 | steps: 52 | - name: Checkout 53 | id: checkout 54 | uses: actions/checkout@v4 55 | 56 | - name: Test Local Action 57 | id: test-action 58 | uses: ./ 59 | with: 60 | milliseconds: 1000 61 | 62 | - name: Print Output 63 | id: output 64 | run: echo "${{ steps.test-action.outputs.time }}" 65 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: CodeQL 13 | 14 | on: 15 | push: 16 | branches: 17 | - main 18 | pull_request: 19 | branches: 20 | - main 21 | schedule: 22 | - cron: '24 5 * * 6' 23 | 24 | permissions: 25 | actions: read 26 | contents: read 27 | security-events: write 28 | 29 | jobs: 30 | analyze: 31 | name: Analyze 32 | runs-on: ubuntu-latest 33 | 34 | strategy: 35 | fail-fast: false 36 | matrix: 37 | language: ['javascript'] 38 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 39 | # Learn more about CodeQL language support at https://git.io/codeql-language-support 40 | 41 | steps: 42 | - name: Checkout repository 43 | uses: actions/checkout@v4 44 | 45 | # Initializes the CodeQL tools for scanning. 46 | - name: Initialize CodeQL 47 | uses: github/codeql-action/init@v3 48 | with: 49 | languages: ${{ matrix.language }} 50 | config-file: ./.github/codeql/codeql-config.yml 51 | # If you wish to specify custom queries, you can do so here or in a config file. 52 | # By default, queries listed here will override any specified in a config file. 53 | # Prefix the list here with "+" to use these queries and those in the config file. 54 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 55 | 56 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 57 | # If this step fails, then you should remove it and run the build manually (see below) 58 | - name: Autobuild 59 | uses: github/codeql-action/autobuild@v3 60 | 61 | # ℹ️ Command-line programs to run using the OS shell. 62 | # 📚 https://git.io/JvXDl 63 | 64 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 65 | # and modify them (or add more) to build your code if your project 66 | # uses a compiled language 67 | 68 | #- run: | 69 | # make bootstrap 70 | # make release 71 | 72 | - name: Perform CodeQL Analysis 73 | uses: github/codeql-action/analyze@v3 74 | -------------------------------------------------------------------------------- /.github/workflows/licensed.yml: -------------------------------------------------------------------------------- 1 | # This workflow checks the statuses of cached dependencies used in this action 2 | # with the help of the Licensed tool. If any licenses are invalid or missing, 3 | # this workflow will fail. See: https://github.com/licensee/licensed 4 | 5 | name: Licensed 6 | 7 | on: 8 | # Uncomment the below lines to run this workflow on pull requests and pushes 9 | # to the default branch. This is useful for checking licenses before merging 10 | # changes into the default branch. 11 | # pull_request: 12 | # branches: 13 | # - main 14 | # push: 15 | # branches: 16 | # - main 17 | workflow_dispatch: 18 | 19 | permissions: 20 | contents: write 21 | 22 | jobs: 23 | licensed: 24 | name: Check Licenses 25 | runs-on: ubuntu-latest 26 | 27 | steps: 28 | - name: Checkout 29 | id: checkout 30 | uses: actions/checkout@v4 31 | 32 | - name: Setup Node.js 33 | id: setup-node 34 | uses: actions/setup-node@v4 35 | with: 36 | node-version-file: .node-version 37 | cache: npm 38 | 39 | - name: Install Dependencies 40 | id: npm-ci 41 | run: npm ci 42 | 43 | - name: Setup Ruby 44 | id: setup-ruby 45 | uses: ruby/setup-ruby@v1 46 | with: 47 | ruby-version: ruby 48 | 49 | - uses: licensee/setup-licensed@v1.3.2 50 | with: 51 | version: 4.x 52 | github_token: ${{ secrets.GITHUB_TOKEN }} 53 | 54 | # If this is a workflow_dispatch event, update the cached licenses. 55 | - if: ${{ github.event_name == 'workflow_dispatch' }} 56 | name: Update Licenses 57 | id: update-licenses 58 | run: licensed cache 59 | 60 | # Then, commit the updated licenses to the repository. 61 | - if: ${{ github.event_name == 'workflow_dispatch' }} 62 | name: Commit Licenses 63 | id: commit-licenses 64 | run: | 65 | git config --local user.email "licensed-ci@users.noreply.github.com" 66 | git config --local user.name "licensed-ci" 67 | git add . 68 | git commit -m "Auto-update license files" 69 | git push 70 | 71 | # Last, check the status of the cached licenses. 72 | - name: Check Licenses 73 | id: check-licenses 74 | run: licensed status 75 | -------------------------------------------------------------------------------- /.github/workflows/linter.yml: -------------------------------------------------------------------------------- 1 | # This workflow will lint the entire codebase using the 2 | # `super-linter/super-linter` action. 3 | # 4 | # For more information, see the super-linter repository: 5 | # https://github.com/super-linter/super-linter 6 | name: Lint Codebase 7 | 8 | on: 9 | pull_request: 10 | branches: 11 | - main 12 | push: 13 | branches: 14 | - main 15 | 16 | permissions: 17 | contents: read 18 | packages: read 19 | statuses: write 20 | 21 | jobs: 22 | lint: 23 | name: Lint Codebase 24 | runs-on: ubuntu-latest 25 | 26 | steps: 27 | # Checkout the repository. 28 | - name: Checkout 29 | id: checkout 30 | uses: actions/checkout@v4 31 | with: 32 | fetch-depth: 0 33 | 34 | # Setup Node.js using the version specified in `.node-version`. 35 | - name: Setup Node.js 36 | id: setup-node 37 | uses: actions/setup-node@v4 38 | with: 39 | node-version-file: .node-version 40 | cache: npm 41 | 42 | # Install dependencies using `npm ci`. 43 | - name: Install Dependencies 44 | id: install 45 | run: npm ci 46 | 47 | # Lint the codebase using the `super-linter/super-linter` action. 48 | - name: Lint Codebase 49 | id: super-linter 50 | uses: super-linter/super-linter/slim@v7 51 | env: 52 | DEFAULT_BRANCH: main 53 | FILTER_REGEX_EXCLUDE: dist/**/* 54 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 55 | LINTER_RULES_PATH: ${{ github.workspace }} 56 | VALIDATE_ALL_CODEBASE: true 57 | VALIDATE_JAVASCRIPT_ES: false 58 | VALIDATE_JAVASCRIPT_STANDARD: false 59 | VALIDATE_JSCPD: false 60 | VALIDATE_JSON: false 61 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependency directory 2 | node_modules 3 | 4 | # Rest pulled from https://github.com/github/gitignore/blob/master/Node.gitignore 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | 13 | # Diagnostic reports (https://nodejs.org/api/report.html) 14 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 15 | 16 | # Runtime data 17 | pids 18 | *.pid 19 | *.seed 20 | *.pid.lock 21 | 22 | # Directory for instrumented libs generated by jscoverage/JSCover 23 | lib-cov 24 | 25 | # Coverage directory used by tools like istanbul 26 | coverage 27 | *.lcov 28 | 29 | # nyc test coverage 30 | .nyc_output 31 | 32 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 33 | .grunt 34 | 35 | # Bower dependency directory (https://bower.io/) 36 | bower_components 37 | 38 | # node-waf configuration 39 | .lock-wscript 40 | 41 | # Compiled binary addons (https://nodejs.org/api/addons.html) 42 | build/Release 43 | 44 | # Dependency directories 45 | jspm_packages/ 46 | 47 | # TypeScript v1 declaration files 48 | typings/ 49 | 50 | # TypeScript cache 51 | *.tsbuildinfo 52 | 53 | # Optional npm cache directory 54 | .npm 55 | 56 | # Optional eslint cache 57 | .eslintcache 58 | 59 | # Optional REPL history 60 | .node_repl_history 61 | 62 | # Output of 'npm pack' 63 | *.tgz 64 | 65 | # Yarn Integrity file 66 | .yarn-integrity 67 | 68 | # dotenv environment variables file 69 | .env 70 | .env.test 71 | 72 | # parcel-bundler cache (https://parceljs.org/) 73 | .cache 74 | 75 | # next.js build output 76 | .next 77 | 78 | # nuxt.js build output 79 | .nuxt 80 | 81 | # vuepress build output 82 | .vuepress/dist 83 | 84 | # Serverless directories 85 | .serverless/ 86 | 87 | # FuseBox cache 88 | .fusebox/ 89 | 90 | # DynamoDB Local files 91 | .dynamodb/ 92 | 93 | # OS metadata 94 | .DS_Store 95 | Thumbs.db 96 | 97 | # Ignore built ts files 98 | __tests__/runner/* 99 | 100 | # IDE files 101 | .idea 102 | *.code-workspace 103 | -------------------------------------------------------------------------------- /.licensed.yml: -------------------------------------------------------------------------------- 1 | # See: https://github.com/licensee/licensed/blob/main/docs/configuration.md 2 | 3 | sources: 4 | npm: true 5 | 6 | allowed: 7 | - apache-2.0 8 | - bsd-2-clause 9 | - bsd-3-clause 10 | - isc 11 | - mit 12 | - cc0-1.0 13 | - other 14 | 15 | ignored: 16 | npm: 17 | # Used by Rollup.js when building in GitHub Actions 18 | - '@rollup/rollup-linux-x64-gnu' 19 | -------------------------------------------------------------------------------- /.licenses/npm/@actions/core.dep.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "@actions/core" 3 | version: 1.11.1 4 | type: npm 5 | summary: Actions core lib 6 | homepage: https://github.com/actions/toolkit/tree/main/packages/core 7 | license: mit 8 | licenses: 9 | - sources: LICENSE.md 10 | text: |- 11 | The MIT License (MIT) 12 | 13 | Copyright 2019 GitHub 14 | 15 | 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: 16 | 17 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 18 | 19 | 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. 20 | notices: [] 21 | -------------------------------------------------------------------------------- /.licenses/npm/@actions/exec.dep.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "@actions/exec" 3 | version: 1.1.1 4 | type: npm 5 | summary: Actions exec lib 6 | homepage: https://github.com/actions/toolkit/tree/main/packages/exec 7 | license: mit 8 | licenses: 9 | - sources: LICENSE.md 10 | text: |- 11 | The MIT License (MIT) 12 | 13 | Copyright 2019 GitHub 14 | 15 | 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: 16 | 17 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 18 | 19 | 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. 20 | notices: [] 21 | -------------------------------------------------------------------------------- /.licenses/npm/@actions/http-client.dep.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "@actions/http-client" 3 | version: 2.2.3 4 | type: npm 5 | summary: Actions Http Client 6 | homepage: https://github.com/actions/toolkit/tree/main/packages/http-client 7 | license: other 8 | licenses: 9 | - sources: LICENSE 10 | text: | 11 | Actions Http Client for Node.js 12 | 13 | Copyright (c) GitHub, Inc. 14 | 15 | All rights reserved. 16 | 17 | MIT License 18 | 19 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 20 | associated documentation files (the "Software"), to deal in the Software without restriction, 21 | including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 22 | and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 23 | subject to the following conditions: 24 | 25 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 26 | 27 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 28 | LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 29 | NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 30 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 31 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 | notices: [] 33 | -------------------------------------------------------------------------------- /.licenses/npm/@actions/io.dep.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "@actions/io" 3 | version: 1.1.3 4 | type: npm 5 | summary: Actions io lib 6 | homepage: https://github.com/actions/toolkit/tree/main/packages/io 7 | license: mit 8 | licenses: 9 | - sources: LICENSE.md 10 | text: |- 11 | The MIT License (MIT) 12 | 13 | Copyright 2019 GitHub 14 | 15 | 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: 16 | 17 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 18 | 19 | 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. 20 | notices: [] 21 | -------------------------------------------------------------------------------- /.licenses/npm/@fastify/busboy.dep.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "@fastify/busboy" 3 | version: 2.1.1 4 | type: npm 5 | summary: A streaming parser for HTML form data for node.js 6 | homepage: 7 | license: mit 8 | licenses: 9 | - sources: LICENSE 10 | text: |- 11 | Copyright Brian White. All rights reserved. 12 | 13 | Permission is hereby granted, free of charge, to any person obtaining a copy 14 | of this software and associated documentation files (the "Software"), to 15 | deal in the Software without restriction, including without limitation the 16 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 17 | sell copies of the Software, and to permit persons to whom the Software is 18 | furnished to do so, subject to the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be included in 21 | all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 28 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 29 | IN THE SOFTWARE. 30 | notices: [] 31 | -------------------------------------------------------------------------------- /.licenses/npm/tunnel.dep.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: tunnel 3 | version: 0.0.6 4 | type: npm 5 | summary: Node HTTP/HTTPS Agents for tunneling proxies 6 | homepage: https://github.com/koichik/node-tunnel/ 7 | license: mit 8 | licenses: 9 | - sources: LICENSE 10 | text: | 11 | The MIT License (MIT) 12 | 13 | Copyright (c) 2012 Koichi Kobayashi 14 | 15 | Permission is hereby granted, free of charge, to any person obtaining a copy 16 | of this software and associated documentation files (the "Software"), to deal 17 | in the Software without restriction, including without limitation the rights 18 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 19 | copies of the Software, and to permit persons to whom the Software is 20 | furnished to do so, subject to the following conditions: 21 | 22 | The above copyright notice and this permission notice shall be included in 23 | all copies or substantial portions of the Software. 24 | 25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 31 | THE SOFTWARE. 32 | - sources: README.md 33 | text: Licensed under the [MIT](https://github.com/koichik/node-tunnel/blob/master/LICENSE) 34 | license. 35 | notices: [] 36 | -------------------------------------------------------------------------------- /.licenses/npm/undici.dep.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: undici 3 | version: 5.28.5 4 | type: npm 5 | summary: An HTTP/1.1 client, written from scratch for Node.js 6 | homepage: https://undici.nodejs.org 7 | license: mit 8 | licenses: 9 | - sources: LICENSE 10 | text: | 11 | MIT License 12 | 13 | Copyright (c) Matteo Collina and Undici contributors 14 | 15 | Permission is hereby granted, free of charge, to any person obtaining a copy 16 | of this software and associated documentation files (the "Software"), to deal 17 | in the Software without restriction, including without limitation the rights 18 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 19 | copies of the Software, and to permit persons to whom the Software is 20 | furnished to do so, subject to the following conditions: 21 | 22 | The above copyright notice and this permission notice shall be included in all 23 | copies or substantial portions of the Software. 24 | 25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 | SOFTWARE. 32 | - sources: README.md 33 | text: MIT 34 | notices: [] 35 | -------------------------------------------------------------------------------- /.markdown-lint.yml: -------------------------------------------------------------------------------- 1 | # See: https://github.com/DavidAnson/markdownlint 2 | 3 | # Unordered list style 4 | MD004: 5 | style: dash 6 | 7 | # Disable line length for tables 8 | MD013: 9 | tables: false 10 | 11 | # Ordered list item prefix 12 | MD029: 13 | style: one 14 | 15 | # Spaces after list markers 16 | MD030: 17 | ul_single: 1 18 | ol_single: 1 19 | ul_multi: 1 20 | ol_multi: 1 21 | 22 | # Code block style 23 | MD046: 24 | style: fenced 25 | -------------------------------------------------------------------------------- /.node-version: -------------------------------------------------------------------------------- 1 | 20.9.0 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .licenses/ 3 | dist/ 4 | node_modules/ 5 | coverage/ 6 | -------------------------------------------------------------------------------- /.prettierrc.yml: -------------------------------------------------------------------------------- 1 | # See: https://prettier.io/docs/en/configuration 2 | 3 | printWidth: 80 4 | tabWidth: 2 5 | useTabs: false 6 | semi: false 7 | singleQuote: true 8 | quoteProps: as-needed 9 | jsxSingleQuote: false 10 | trailingComma: none 11 | bracketSpacing: true 12 | bracketSameLine: true 13 | arrowParens: always 14 | proseWrap: always 15 | htmlWhitespaceSensitivity: css 16 | endOfLine: lf 17 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Debug Action", 6 | "type": "node", 7 | "request": "launch", 8 | "runtimeExecutable": "npx", 9 | "cwd": "${workspaceRoot}", 10 | "args": ["@github/local-action", ".", "src/main.js", ".env"], 11 | "console": "integratedTerminal", 12 | "skipFiles": ["/**", "node_modules/**"] 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /.yaml-lint.yml: -------------------------------------------------------------------------------- 1 | # See: https://yamllint.readthedocs.io/en/stable/ 2 | 3 | rules: 4 | document-end: disable 5 | document-start: 6 | level: warning 7 | present: false 8 | line-length: 9 | level: warning 10 | max: 80 11 | allow-non-breakable-words: true 12 | allow-non-breakable-inline-mappings: true 13 | ignore: 14 | - .licenses/ 15 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | ############################################################################ 2 | # Repository CODEOWNERS # 3 | # Order is important! The last matching pattern takes the most precedence. # 4 | ############################################################################ 5 | 6 | # Default owners, unless a later match takes precedence. 7 | * @actions/actions-oss-maintainers 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright GitHub 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Create a JavaScript Action 2 | 3 | [![GitHub Super-Linter](https://github.com/actions/javascript-action/actions/workflows/linter.yml/badge.svg)](https://github.com/super-linter/super-linter) 4 | ![CI](https://github.com/actions/javascript-action/actions/workflows/ci.yml/badge.svg) 5 | 6 | Use this template to bootstrap the creation of a JavaScript action. :rocket: 7 | 8 | This template includes compilation support, tests, a validation workflow, 9 | publishing, and versioning guidance. 10 | 11 | If you are new, there's also a simpler introduction in the 12 | [Hello world JavaScript action repository](https://github.com/actions/hello-world-javascript-action). 13 | 14 | ## Create Your Own Action 15 | 16 | To create your own action, you can use this repository as a template! Just 17 | follow the below instructions: 18 | 19 | 1. Click the **Use this template** button at the top of the repository 20 | 1. Select **Create a new repository** 21 | 1. Select an owner and name for your new repository 22 | 1. Click **Create repository** 23 | 1. Clone your new repository 24 | 25 | > [!IMPORTANT] 26 | > 27 | > Make sure to remove or update the [`CODEOWNERS`](./CODEOWNERS) file! For 28 | > details on how to use this file, see 29 | > [About code owners](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners). 30 | 31 | ## Initial Setup 32 | 33 | After you've cloned the repository to your local machine or codespace, you'll 34 | need to perform some initial setup steps before you can develop your action. 35 | 36 | > [!NOTE] 37 | > 38 | > You'll need to have a reasonably modern version of 39 | > [Node.js](https://nodejs.org) handy. If you are using a version manager like 40 | > [`nodenv`](https://github.com/nodenv/nodenv) or 41 | > [`nvm`](https://github.com/nvm-sh/nvm), you can run `nodenv install` in the 42 | > root of your repository to install the version specified in 43 | > [`package.json`](./package.json). Otherwise, 20.x or later should work! 44 | 45 | 1. :hammer_and_wrench: Install the dependencies 46 | 47 | ```bash 48 | npm install 49 | ``` 50 | 51 | 1. :building_construction: Package the JavaScript for distribution 52 | 53 | ```bash 54 | npm run bundle 55 | ``` 56 | 57 | 1. :white_check_mark: Run the tests 58 | 59 | ```bash 60 | $ npm test 61 | 62 | PASS ./index.test.js 63 | ✓ throws invalid number (3ms) 64 | ✓ wait 500 ms (504ms) 65 | ✓ test runs (95ms) 66 | 67 | ... 68 | ``` 69 | 70 | ## Update the Action Metadata 71 | 72 | The [`action.yml`](action.yml) file defines metadata about your action, such as 73 | input(s) and output(s). For details about this file, see 74 | [Metadata syntax for GitHub Actions](https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions). 75 | 76 | When you copy this repository, update `action.yml` with the name, description, 77 | inputs, and outputs for your action. 78 | 79 | ## Update the Action Code 80 | 81 | The [`src/`](./src/) directory is the heart of your action! This contains the 82 | source code that will be run when your action is invoked. You can replace the 83 | contents of this directory with your own code. 84 | 85 | There are a few things to keep in mind when writing your action code: 86 | 87 | - Most GitHub Actions toolkit and CI/CD operations are processed asynchronously. 88 | In `main.js`, you will see that the action is run in an `async` function. 89 | 90 | ```javascript 91 | const core = require('@actions/core') 92 | //... 93 | 94 | async function run() { 95 | try { 96 | //... 97 | } catch (error) { 98 | core.setFailed(error.message) 99 | } 100 | } 101 | ``` 102 | 103 | For more information about the GitHub Actions toolkit, see the 104 | [documentation](https://github.com/actions/toolkit/blob/main/README.md). 105 | 106 | So, what are you waiting for? Go ahead and start customizing your action! 107 | 108 | 1. Create a new branch 109 | 110 | ```bash 111 | git checkout -b releases/v1 112 | ``` 113 | 114 | 1. Replace the contents of `src/` with your action code 115 | 1. Add tests to `__tests__/` for your source code 116 | 1. Format, test, and build the action 117 | 118 | ```bash 119 | npm run all 120 | ``` 121 | 122 | > This step is important! It will run [`ncc`](https://github.com/vercel/ncc) 123 | > to build the final JavaScript action code with all dependencies included. 124 | > If you do not run this step, your action will not work correctly when it is 125 | > used in a workflow. This step also includes the `--license` option for 126 | > `ncc`, which will create a license file for all of the production node 127 | > modules used in your project. 128 | 129 | 1. (Optional) Test your action locally 130 | 131 | The [`@github/local-action`](https://github.com/github/local-action) utility 132 | can be used to test your action locally. It is a simple command-line tool 133 | that "stubs" (or simulates) the GitHub Actions Toolkit. This way, you can run 134 | your JavaScript action locally without having to commit and push your changes 135 | to a repository. 136 | 137 | The `local-action` utility can be run in the following ways: 138 | 139 | - Visual Studio Code Debugger 140 | 141 | Make sure to review and, if needed, update 142 | [`.vscode/launch.json`](./.vscode/launch.json) 143 | 144 | - Terminal/Command Prompt 145 | 146 | ```bash 147 | # npx @github/local action 148 | npx @github/local-action . src/main.js .env 149 | ``` 150 | 151 | You can provide a `.env` file to the `local-action` CLI to set environment 152 | variables used by the GitHub Actions Toolkit. For example, setting inputs and 153 | event payload data used by your action. For more information, see the example 154 | file, [`.env.example`](./.env.example), and the 155 | [GitHub Actions Documentation](https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables). 156 | 157 | 1. Commit your changes 158 | 159 | ```bash 160 | git add . 161 | git commit -m "My first action is ready!" 162 | ``` 163 | 164 | 1. Push them to your repository 165 | 166 | ```bash 167 | git push -u origin releases/v1 168 | ``` 169 | 170 | 1. Create a pull request and get feedback on your action 171 | 1. Merge the pull request into the `main` branch 172 | 173 | Your action is now published! :rocket: 174 | 175 | For information about versioning your action, see 176 | [Versioning](https://github.com/actions/toolkit/blob/main/docs/action-versioning.md) 177 | in the GitHub Actions toolkit. 178 | 179 | ## Validate the Action 180 | 181 | You can now validate the action by referencing it in a workflow file. For 182 | example, [`ci.yml`](./.github/workflows/ci.yml) demonstrates how to reference an 183 | action in the same repository. 184 | 185 | ```yaml 186 | steps: 187 | - name: Checkout 188 | id: checkout 189 | uses: actions/checkout@v3 190 | 191 | - name: Test Local Action 192 | id: test-action 193 | uses: ./ 194 | with: 195 | milliseconds: 1000 196 | 197 | - name: Print Output 198 | id: output 199 | run: echo "${{ steps.test-action.outputs.time }}" 200 | ``` 201 | 202 | For example workflow runs, check out the 203 | [Actions tab](https://github.com/actions/javascript-action/actions)! :rocket: 204 | 205 | ## Usage 206 | 207 | After testing, you can create version tag(s) that developers can use to 208 | reference different stable versions of your action. For more information, see 209 | [Versioning](https://github.com/actions/toolkit/blob/main/docs/action-versioning.md) 210 | in the GitHub Actions toolkit. 211 | 212 | To include the action in a workflow in another repository, you can use the 213 | `uses` syntax with the `@` symbol to reference a specific branch, tag, or commit 214 | hash. 215 | 216 | ```yaml 217 | steps: 218 | - name: Checkout 219 | id: checkout 220 | uses: actions/checkout@v4 221 | 222 | - name: Run my Action 223 | id: run-action 224 | uses: actions/javascript-action@v1 # Commit with the `v1` tag 225 | with: 226 | milliseconds: 1000 227 | 228 | - name: Print Output 229 | id: output 230 | run: echo "${{ steps.run-action.outputs.time }}" 231 | ``` 232 | 233 | ## Dependency License Management 234 | 235 | This template includes a GitHub Actions workflow, 236 | [`licensed.yml`](./.github/workflows/licensed.yml), that uses 237 | [Licensed](https://github.com/licensee/licensed) to check for dependencies with 238 | missing or non-compliant licenses. This workflow is initially disabled. To 239 | enable the workflow, follow the below steps. 240 | 241 | 1. Open [`licensed.yml`](./.github/workflows/licensed.yml) 242 | 1. Uncomment the following lines: 243 | 244 | ```yaml 245 | # pull_request: 246 | # branches: 247 | # - main 248 | # push: 249 | # branches: 250 | # - main 251 | ``` 252 | 253 | 1. Save and commit the changes 254 | 255 | Once complete, this workflow will run any time a pull request is created or 256 | changes pushed directly to `main`. If the workflow detects any dependencies with 257 | missing or non-compliant licenses, it will fail the workflow and provide details 258 | on the issue(s) found. 259 | 260 | ### Updating Licenses 261 | 262 | Whenever you install or update dependencies, you can use the Licensed CLI to 263 | update the licenses database. To install Licensed, see the project's 264 | [Readme](https://github.com/licensee/licensed?tab=readme-ov-file#installation). 265 | 266 | To update the cached licenses, run the following command: 267 | 268 | ```bash 269 | licensed cache 270 | ``` 271 | 272 | To check the status of cached licenses, run the following command: 273 | 274 | ```bash 275 | licensed status 276 | ``` 277 | -------------------------------------------------------------------------------- /__fixtures__/core.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is used to mock the `@actions/core` module in tests. 3 | */ 4 | import { jest } from '@jest/globals' 5 | 6 | export const debug = jest.fn() 7 | export const error = jest.fn() 8 | export const info = jest.fn() 9 | export const getInput = jest.fn() 10 | export const setOutput = jest.fn() 11 | export const setFailed = jest.fn() 12 | export const warning = jest.fn() 13 | -------------------------------------------------------------------------------- /__fixtures__/wait.js: -------------------------------------------------------------------------------- 1 | import { jest } from '@jest/globals' 2 | 3 | export const wait = jest.fn() 4 | -------------------------------------------------------------------------------- /__tests__/main.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Unit tests for the action's main functionality, src/main.js 3 | * 4 | * To mock dependencies in ESM, you can create fixtures that export mock 5 | * functions and objects. For example, the core module is mocked in this test, 6 | * so that the actual '@actions/core' module is not imported. 7 | */ 8 | import { jest } from '@jest/globals' 9 | import * as core from '../__fixtures__/core.js' 10 | import { wait } from '../__fixtures__/wait.js' 11 | 12 | // Mocks should be declared before the module being tested is imported. 13 | jest.unstable_mockModule('@actions/core', () => core) 14 | jest.unstable_mockModule('../src/wait.js', () => ({ wait })) 15 | 16 | // The module being tested should be imported dynamically. This ensures that the 17 | // mocks are used in place of any actual dependencies. 18 | const { run } = await import('../src/main.js') 19 | 20 | describe('main.js', () => { 21 | beforeEach(() => { 22 | // Set the action's inputs as return values from core.getInput(). 23 | core.getInput.mockImplementation(() => '500') 24 | 25 | // Mock the wait function so that it does not actually wait. 26 | wait.mockImplementation(() => Promise.resolve('done!')) 27 | }) 28 | 29 | afterEach(() => { 30 | jest.resetAllMocks() 31 | }) 32 | 33 | it('Sets the time output', async () => { 34 | await run() 35 | 36 | // Verify the time output was set. 37 | expect(core.setOutput).toHaveBeenNthCalledWith( 38 | 1, 39 | 'time', 40 | // Simple regex to match a time string in the format HH:MM:SS. 41 | expect.stringMatching(/^\d{2}:\d{2}:\d{2}/) 42 | ) 43 | }) 44 | 45 | it('Sets a failed status', async () => { 46 | // Clear the getInput mock and return an invalid value. 47 | core.getInput.mockClear().mockReturnValueOnce('this is not a number') 48 | 49 | // Clear the wait mock and return a rejected promise. 50 | wait 51 | .mockClear() 52 | .mockRejectedValueOnce(new Error('milliseconds is not a number')) 53 | 54 | await run() 55 | 56 | // Verify that the action was marked as failed. 57 | expect(core.setFailed).toHaveBeenNthCalledWith( 58 | 1, 59 | 'milliseconds is not a number' 60 | ) 61 | }) 62 | }) 63 | -------------------------------------------------------------------------------- /__tests__/wait.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Unit tests for src/wait.js 3 | */ 4 | import { wait } from '../src/wait.js' 5 | 6 | describe('wait.js', () => { 7 | it('Throws an invalid number', async () => { 8 | const input = parseInt('foo', 10) 9 | 10 | expect(isNaN(input)).toBe(true) 11 | 12 | await expect(wait(input)).rejects.toThrow('milliseconds is not a number') 13 | }) 14 | 15 | it('Waits with a valid number', async () => { 16 | const start = new Date() 17 | await wait(500) 18 | const end = new Date() 19 | 20 | const delta = Math.abs(end.getTime() - start.getTime()) 21 | 22 | expect(delta).toBeGreaterThan(450) 23 | }) 24 | }) 25 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: The name of your action here 2 | description: Provide a description here 3 | author: Your name or organization here 4 | 5 | # Add your action's branding here. This will appear on the GitHub Marketplace. 6 | branding: 7 | icon: heart 8 | color: red 9 | 10 | # Define your inputs here. 11 | inputs: 12 | milliseconds: 13 | description: Your input description here 14 | required: true 15 | default: '1000' 16 | 17 | # Define your outputs here. 18 | outputs: 19 | time: 20 | description: Your output description here 21 | 22 | runs: 23 | using: node20 24 | main: dist/index.js 25 | -------------------------------------------------------------------------------- /badges/coverage.svg: -------------------------------------------------------------------------------- 1 | Coverage: 100%Coverage100% -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | // See: https://eslint.org/docs/latest/use/configure/configuration-files 2 | 3 | import { fixupPluginRules } from '@eslint/compat' 4 | import { FlatCompat } from '@eslint/eslintrc' 5 | import js from '@eslint/js' 6 | import _import from 'eslint-plugin-import' 7 | import jest from 'eslint-plugin-jest' 8 | import prettier from 'eslint-plugin-prettier' 9 | import globals from 'globals' 10 | import path from 'node:path' 11 | import { fileURLToPath } from 'node:url' 12 | 13 | const __filename = fileURLToPath(import.meta.url) 14 | const __dirname = path.dirname(__filename) 15 | const compat = new FlatCompat({ 16 | baseDirectory: __dirname, 17 | recommendedConfig: js.configs.recommended, 18 | allConfig: js.configs.all 19 | }) 20 | 21 | export default [ 22 | { 23 | ignores: ['**/coverage', '**/dist', '**/linter', '**/node_modules'] 24 | }, 25 | ...compat.extends( 26 | 'eslint:recommended', 27 | 'plugin:jest/recommended', 28 | 'plugin:prettier/recommended' 29 | ), 30 | { 31 | plugins: { 32 | import: fixupPluginRules(_import), 33 | jest, 34 | prettier 35 | }, 36 | 37 | languageOptions: { 38 | globals: { 39 | ...globals.node, 40 | ...globals.jest, 41 | Atomics: 'readonly', 42 | SharedArrayBuffer: 'readonly' 43 | }, 44 | 45 | ecmaVersion: 2023, 46 | sourceType: 'module' 47 | }, 48 | 49 | rules: { 50 | camelcase: 'off', 51 | 'eslint-comments/no-use': 'off', 52 | 'eslint-comments/no-unused-disable': 'off', 53 | 'i18n-text/no-en': 'off', 54 | 'import/no-namespace': 'off', 55 | 'no-console': 'off', 56 | 'no-shadow': 'off', 57 | 'no-unused-vars': 'off', 58 | 'prettier/prettier': 'error' 59 | } 60 | } 61 | ] 62 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | // See: https://jestjs.io/docs/configuration 2 | 3 | /** @type {import('jest').Config} */ 4 | const jestConfig = { 5 | clearMocks: true, 6 | collectCoverage: true, 7 | collectCoverageFrom: ['./src/**'], 8 | coverageDirectory: './coverage', 9 | coveragePathIgnorePatterns: ['/node_modules/', '/dist/'], 10 | coverageReporters: ['json-summary', 'text', 'lcov'], 11 | // Uncomment the below lines if you would like to enforce a coverage threshold 12 | // for your action. This will fail the build if the coverage is below the 13 | // specified thresholds. 14 | // coverageThreshold: { 15 | // global: { 16 | // branches: 100, 17 | // functions: 100, 18 | // lines: 100, 19 | // statements: 100 20 | // } 21 | // }, 22 | moduleFileExtensions: ['js'], 23 | reporters: ['default'], 24 | testEnvironment: 'node', 25 | testMatch: ['**/*.test.js'], 26 | testPathIgnorePatterns: ['/dist/', '/node_modules/'], 27 | verbose: true 28 | } 29 | 30 | export default jestConfig 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "javascript-action", 3 | "description": "GitHub Actions JavaScript Template", 4 | "version": "0.0.0", 5 | "author": "", 6 | "type": "module", 7 | "private": true, 8 | "homepage": "https://github.com/actions/javascript-action#readme", 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/actions/javascript-action.git" 12 | }, 13 | "bugs": { 14 | "url": "https://github.com/actions/javascript-action/issues" 15 | }, 16 | "keywords": [ 17 | "actions" 18 | ], 19 | "exports": { 20 | ".": "./dist/index.js" 21 | }, 22 | "engines": { 23 | "node": ">=20" 24 | }, 25 | "scripts": { 26 | "bundle": "npm run format:write && npm run package", 27 | "ci-test": "NODE_OPTIONS=--experimental-vm-modules NODE_NO_WARNINGS=1 npx jest", 28 | "coverage": "npx make-coverage-badge --output-path ./badges/coverage.svg", 29 | "format:write": "npx prettier --write .", 30 | "format:check": "npx prettier --check .", 31 | "lint": "npx eslint .", 32 | "local-action": "npx @github/local-action . src/main.js .env", 33 | "package": "npx rollup --config rollup.config.js", 34 | "package:watch": "npm run package -- --watch", 35 | "test": "NODE_OPTIONS=--experimental-vm-modules NODE_NO_WARNINGS=1 npx jest", 36 | "all": "npm run format:write && npm run lint && npm run test && npm run coverage && npm run package" 37 | }, 38 | "license": "MIT", 39 | "dependencies": { 40 | "@actions/core": "^1.11.1" 41 | }, 42 | "devDependencies": { 43 | "@eslint/compat": "^1.2.9", 44 | "@github/local-action": "^3.2.1", 45 | "@jest/globals": "^29.7.0", 46 | "@rollup/plugin-commonjs": "^28.0.3", 47 | "@rollup/plugin-node-resolve": "^16.0.1", 48 | "eslint": "^9.27.0", 49 | "eslint-config-prettier": "^10.1.5", 50 | "eslint-plugin-import": "^2.31.0", 51 | "eslint-plugin-jest": "^28.11.0", 52 | "eslint-plugin-prettier": "^5.4.0", 53 | "jest": "^29.7.0", 54 | "make-coverage-badge": "^1.2.0", 55 | "prettier": "^3.5.3", 56 | "prettier-eslint": "^16.4.2", 57 | "rollup": "^4.41.0" 58 | }, 59 | "optionalDependencies": { 60 | "@rollup/rollup-linux-x64-gnu": "*" 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | // See: https://rollupjs.org/introduction/ 2 | 3 | import commonjs from '@rollup/plugin-commonjs' 4 | import { nodeResolve } from '@rollup/plugin-node-resolve' 5 | 6 | const config = { 7 | input: 'src/index.js', 8 | output: { 9 | esModule: true, 10 | file: 'dist/index.js', 11 | format: 'es', 12 | sourcemap: true 13 | }, 14 | plugins: [commonjs(), nodeResolve({ preferBuiltins: true })] 15 | } 16 | 17 | export default config 18 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The entrypoint for the action. This file simply imports and runs the action's 3 | * main logic. 4 | */ 5 | import { run } from './main.js' 6 | 7 | /* istanbul ignore next */ 8 | run() 9 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import * as core from '@actions/core' 2 | import { wait } from './wait.js' 3 | 4 | /** 5 | * The main function for the action. 6 | * 7 | * @returns {Promise} Resolves when the action is complete. 8 | */ 9 | export async function run() { 10 | try { 11 | const ms = core.getInput('milliseconds') 12 | 13 | // Debug logs are only output if the `ACTIONS_STEP_DEBUG` secret is true 14 | core.debug(`Waiting ${ms} milliseconds ...`) 15 | 16 | // Log the current timestamp, wait, then log the new timestamp 17 | core.debug(new Date().toTimeString()) 18 | await wait(parseInt(ms, 10)) 19 | core.debug(new Date().toTimeString()) 20 | 21 | // Set outputs for other workflow steps to use 22 | core.setOutput('time', new Date().toTimeString()) 23 | } catch (error) { 24 | // Fail the workflow run if an error occurs 25 | if (error instanceof Error) core.setFailed(error.message) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/wait.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Waits for a number of milliseconds. 3 | * 4 | * @param {number} milliseconds The number of milliseconds to wait. 5 | * @returns {Promise} Resolves with 'done!' after the wait is over. 6 | */ 7 | export async function wait(milliseconds) { 8 | return new Promise((resolve) => { 9 | if (isNaN(milliseconds)) throw new Error('milliseconds is not a number') 10 | 11 | setTimeout(() => resolve('done!'), milliseconds) 12 | }) 13 | } 14 | --------------------------------------------------------------------------------