diff --git a/.github/linters/.jscpd.json b/.github/linters/.jscpd.json new file mode 100644 index 0000000..86eddd9 --- /dev/null +++ b/.github/linters/.jscpd.json @@ -0,0 +1,4 @@ +{ + "threshold": 5, + "ignore": ["**/tests/npm/coverage/*", "**/node_modules/*"] +} diff --git a/.github/workflows/__main-ci.yml b/.github/workflows/__main-ci.yml index 3eafe25..a47fa3b 100644 --- a/.github/workflows/__main-ci.yml +++ b/.github/workflows/__main-ci.yml @@ -24,7 +24,7 @@ jobs: actions: read contents: read packages: write - pull-requests: read + pull-requests: write id-token: write issues: read security-events: write diff --git a/.github/workflows/__pull-request-ci.yml b/.github/workflows/__pull-request-ci.yml index dc88b4d..d405dee 100644 --- a/.github/workflows/__pull-request-ci.yml +++ b/.github/workflows/__pull-request-ci.yml @@ -18,7 +18,7 @@ jobs: actions: read contents: read packages: write - pull-requests: read + pull-requests: write id-token: write issues: read security-events: write diff --git a/.github/workflows/__shared-ci.yml b/.github/workflows/__shared-ci.yml index f2e1988..f7b709a 100644 --- a/.github/workflows/__shared-ci.yml +++ b/.github/workflows/__shared-ci.yml @@ -49,7 +49,7 @@ jobs: permissions: contents: read packages: write - pull-requests: read + pull-requests: write id-token: write issues: read security-events: write diff --git a/.github/workflows/__test-workflow-continuous-integration.yml b/.github/workflows/__test-workflow-continuous-integration.yml index 94899e2..9c5e6ec 100644 --- a/.github/workflows/__test-workflow-continuous-integration.yml +++ b/.github/workflows/__test-workflow-continuous-integration.yml @@ -11,6 +11,7 @@ jobs: uses: ./.github/workflows/continuous-integration.yml permissions: contents: read + pull-requests: write security-events: write # FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659 id-token: write @@ -35,6 +36,24 @@ jobs: - name: Check the build artifacts run: test -f tests/npm/dist/test.txt + act-without-container-and-github-reports: + name: Act - Run the continuous integration workflow (without container and GitHub reports) + uses: ./.github/workflows/continuous-integration.yml + permissions: + contents: read + pull-requests: write + security-events: write + # FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659 + id-token: write + with: + working-directory: tests/npm + build: | + { + "artifact": "dist" + } + test: | + {"coverage": "github"} + arrange-with-container: permissions: id-token: write @@ -63,6 +82,7 @@ jobs: needs: arrange-with-container permissions: contents: read + pull-requests: write security-events: write # FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659 id-token: write @@ -73,6 +93,8 @@ jobs: { "artifact": "dist" } + test: | + {"coverage": "codecov"} assert-with-container: name: Assert - Ensure build artifact has been uploaded (with container) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index da778b6..08dfdae 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -52,10 +52,13 @@ on: required: false default: true lint: - description: "Optional flag to enable linting." - type: boolean + description: | + Whether to enable linting. + Set to `null` or empty to disable. + Accepts a JSON object for lint options. See [lint action](../actions/lint/README.md). + type: string required: false - default: true + default: "true" code-ql: description: "Code QL analysis language. See ." type: string @@ -67,15 +70,13 @@ on: required: false default: true test: - description: "Optional flag to enable test." - type: boolean - required: false - default: true - coverage: - description: "Specify code coverage reporter. Supported values: `codecov`." + description: | + Whether to enable testing. + Set to `null` or empty to disable. + Accepts a JSON object for test options. See [test action](../actions/test/README.md). type: string required: false - default: "codecov" + default: "true" working-directory: description: "Working directory where the dependencies are installed." type: string @@ -247,7 +248,7 @@ jobs: lint: name: ๐Ÿ‘• Lint - if: inputs.checks == true && inputs.lint != false + if: inputs.checks == true && inputs.lint runs-on: ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }} container: image: ${{ inputs.container != '' && inputs.container || null }} @@ -276,25 +277,30 @@ jobs: - run: | if [ -f .gitignore ]; then grep -q "self-workflow" .gitignore || echo "self-workflow" >> .gitignore; else echo "self-workflow" >> .gitignore; fi if [ -f .dockerignore ]; then grep -q "self-workflow" .dockerignore || echo "self-workflow" >> .dockerignore; else echo "self-workflow" >> .dockerignore; fi - - - id: setup-node - if: inputs.container == '' - uses: ./self-workflow/actions/setup-node + # jscpd:ignore-end + - id: preparel-lint-options + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + env: + LINT_INPUT: ${{ inputs.lint }} with: - working-directory: ${{ inputs.working-directory }} - dependencies-cache: | - nx - prettier + script: | + const lintInput = process.env.LINT_INPUT.trim(); - - id: get-package-manager - if: inputs.container - uses: ./self-workflow/actions/get-package-manager + let lintOptions = {}; + if (lintInput && lintInput !== 'true') { + try { + const parsed = JSON.parse(lintInput); + lintOptions = { ...lintOptions, ...parsed }; + } catch (error) { + core.setFailed(`Failed to parse lint input as JSON: ${error.message}`); + return; + } + } + + - uses: ./self-workflow/actions/lint with: working-directory: ${{ inputs.working-directory }} - # jscpd:ignore-end - - - run: ${{ inputs.container && steps.get-package-manager.outputs.run-script-command || steps.setup-node.outputs.run-script-command }} lint - working-directory: ${{ inputs.working-directory }} + container: ${{ inputs.container != '' }} build: name: ๐Ÿ—๏ธ Build @@ -311,7 +317,7 @@ jobs: # FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659 id-token: write outputs: - artifact-id: ${{ steps.build-artifact-id.outputs.artifact-id }} + artifact-id: ${{ steps.build.outputs.artifact-id }} steps: - uses: hoverkraft-tech/ci-github-common/actions/checkout@753288393de1f3d92f687a6761d236ca800f5306 # 0.28.1 if: needs.setup.outputs.build-commands && inputs.container == '' @@ -333,83 +339,20 @@ jobs: if [ -f .gitignore ]; then grep -q "self-workflow" .gitignore || echo "self-workflow" >> .gitignore; else echo "self-workflow" >> .gitignore; fi if [ -f .dockerignore ]; then grep -q "self-workflow" .dockerignore || echo "self-workflow" >> .dockerignore; else echo "self-workflow" >> .dockerignore; fi # jscpd:ignore-end - - if: needs.setup.outputs.build-commands - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 - env: - BUILD_ENV: ${{ needs.setup.outputs.build-env }} - BUILD_SECRETS: ${{ secrets.build-secrets }} - with: - script: | - const envInput = process.env.BUILD_ENV || '{}'; - - let buildEnv = {}; - - try { - buildEnv = JSON.parse(envInput); - } catch (e) { - core.setFailed(`Invalid build env JSON: ${e.message}`); - } - - for (const [key, value] of Object.entries(buildEnv)) { - core.exportVariable(key, value); - } - - const secretsInput = process.env.BUILD_SECRETS || ''; - for (const line of secretsInput.split('\n').map(line => line.trim()).filter(Boolean)) { - const [key, ...rest] = line.split('='); - if (!key || !rest.length) { - return core.setFailed(`Invalid build secrets format: ${line}`); - } - const value = rest.join('='); - core.exportVariable(key.trim(), value.trim()); - } - - - id: setup-node - if: needs.setup.outputs.build-commands && inputs.container == '' - uses: ./self-workflow/actions/setup-node - with: - working-directory: ${{ inputs.working-directory }} - dependencies-cache: | - nx - gatsby - storybook - - - id: get-package-manager - if: needs.setup.outputs.build-commands && inputs.container - uses: ./self-workflow/actions/get-package-manager + - id: build + if: needs.setup.outputs.build-commands + uses: ./self-workflow/actions/build with: working-directory: ${{ inputs.working-directory }} - - - if: needs.setup.outputs.build-commands - working-directory: ${{ inputs.working-directory }} - env: - BUILD_COMMANDS: ${{ needs.setup.outputs.build-commands }} - RUN_SCRIPT_COMMAND: ${{ inputs.container && steps.get-package-manager.outputs.run-script-command || steps.setup-node.outputs.run-script-command }} - run: | - echo "$BUILD_COMMANDS" | while IFS= read -r COMMAND ; do - # Trim whitespace - COMMAND=$(echo "$COMMAND" | xargs) - - # Skip empty lines - if [ -z "$COMMAND" ]; then - continue - fi - - echo -e "\n - Running $COMMAND" - $RUN_SCRIPT_COMMAND "$COMMAND" - done - - - id: build-artifact-id - if: needs.setup.outputs.build-commands && needs.setup.outputs.build-artifact - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 - with: - name: ${{ fromJSON(needs.setup.outputs.build-artifact).name }} - path: ${{ fromJSON(needs.setup.outputs.build-artifact).paths }} - if-no-files-found: error + build-commands: ${{ needs.setup.outputs.build-commands }} + build-env: ${{ needs.setup.outputs.build-env }} + build-secrets: ${{ secrets.build-secrets }} + build-artifact: ${{ needs.setup.outputs.build-artifact }} + container: ${{ inputs.container != '' }} test: name: ๐Ÿงช Test - if: inputs.checks == true && inputs.test == true + if: inputs.checks == true && inputs.test runs-on: ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }} container: image: ${{ inputs.container != '' && inputs.container || null }} @@ -420,6 +363,7 @@ jobs: - build permissions: contents: read + pull-requests: write # FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659 id-token: write steps: @@ -446,43 +390,36 @@ jobs: if [ -f .gitignore ]; then grep -q "self-workflow" .gitignore || echo "self-workflow" >> .gitignore; else echo "self-workflow" >> .gitignore; fi if [ -f .dockerignore ]; then grep -q "self-workflow" .dockerignore || echo "self-workflow" >> .dockerignore; else echo "self-workflow" >> .dockerignore; fi - - id: setup-node - if: inputs.container == '' - uses: ./self-workflow/actions/setup-node + - id: prepare-test-options + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + env: + TEST_INPUT: ${{ inputs.test }} with: - working-directory: ${{ inputs.working-directory }} - dependencies-cache: | - nx - jest + script: | + const testInput = process.env.TEST_INPUT.trim(); - - id: get-package-manager - if: needs.setup.outputs.build-commands && inputs.container - uses: ./self-workflow/actions/get-package-manager - with: - working-directory: ${{ inputs.working-directory }} + let testOptions = {}; + if (testInput && testInput !== 'true') { + try { + const parsed = JSON.parse(testInput); + testOptions = { ...testOptions, ...parsed }; + } catch (error) { + core.setFailed(`Failed to parse test input as JSON: ${error.message}`); + return; + } + } - - run: ${{ inputs.container && steps.get-package-manager.outputs.run-script-command || steps.setup-node.outputs.run-script-command }} test:ci - working-directory: ${{ inputs.working-directory }} - env: - CI: "true" + if (testOptions.coverage === undefined) { + testOptions.coverage = 'github'; + } + core.setOutput('coverage', testOptions.coverage ); - - if: inputs.coverage == 'codecov' && inputs.container - env: - REQUIRED_DEPS: | - git - curl - gpg - run: | - apt-get update - for dep in $REQUIRED_DEPS; do - if ! dpkg -s "$dep" >/dev/null 2>&1; then - apt-get install -y "$dep" - fi - done - - - name: ๐Ÿ“Š Code coverage - if: inputs.coverage == 'codecov' - uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1 + core.setOutput('coverage-files', testOptions['coverage-files'] || ''); + + - uses: ./self-workflow/actions/test with: - use_oidc: true - disable_telem: true + working-directory: ${{ inputs.working-directory }} + container: ${{ inputs.container != '' }} + coverage: ${{ steps.prepare-test-options.outputs.coverage }} + coverage-files: ${{ steps.prepare-test-options.outputs['coverage-files'] }} + github-token: ${{ github.token }} diff --git a/.gitignore b/.gitignore index 4e3864b..58e75bd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /node_modules /tests/*/node_modules +/tests/*/coverage /dist \ No newline at end of file diff --git a/README.md b/README.md index 0a917f0..f071b42 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,16 @@ This repository centralizes the Hoverkraft toolkit for building, testing, and sh ## Actions +### CI Actions + +_Actions for continuous integration steps: build, lint, and test._ + +#### - [Build](actions/build/README.md) + +#### - [Lint](actions/lint/README.md) + +#### - [Test](actions/test/README.md) + ### Dependencies _Actions dedicated to caching and validating Node.js dependencies._ diff --git a/actions/build/README.md b/actions/build/README.md new file mode 100644 index 0000000..93907cd --- /dev/null +++ b/actions/build/README.md @@ -0,0 +1,141 @@ + + +# ![Icon](data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJmZWF0aGVyIGZlYXRoZXItcGFja2FnZSIgY29sb3I9ImJsdWUiPjxsaW5lIHgxPSIxNi41IiB5MT0iOS40IiB4Mj0iNy41IiB5Mj0iNC4yMSI+PC9saW5lPjxwYXRoIGQ9Ik0yMSAxNlY4YTIgMiAwIDAgMC0xLTEuNzNsLTctNGEyIDIgMCAwIDAtMiAwbC03IDRBMiAyIDAgMCAwIDMgOHY4YTIgMiAwIDAgMCAxIDEuNzNsNyA0YTIgMiAwIDAgMCAyIDBsNy00QTIgMiAwIDAgMCAyMSAxNnoiPjwvcGF0aD48cG9seWxpbmUgcG9pbnRzPSIzLjI3IDYuOTYgMTIgMTIuMDEgMjAuNzMgNi45NiI+PC9wb2x5bGluZT48bGluZSB4MT0iMTIiIHkxPSIyMi4wOCIgeDI9IjEyIiB5Mj0iMTIiPjwvbGluZT48L3N2Zz4=) GitHub Action: Build + +
+ Build +
+ +--- + + + + +[![Marketplace](https://img.shields.io/badge/Marketplace-build-blue?logo=github-actions)](https://github.com/marketplace/actions/build) +[![Release](https://img.shields.io/github/v/release/hoverkraft-tech/ci-github-nodejs)](https://github.com/hoverkraft-tech/ci-github-nodejs/releases) +[![License](https://img.shields.io/github/license/hoverkraft-tech/ci-github-nodejs)](http://choosealicense.com/licenses/mit/) +[![Stars](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social)](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social) +[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md) + + + + +## Overview + +Action to build Node.js projects with support for custom commands, environment variables, and artifact handling + + + + +## Usage + +````yaml +- uses: hoverkraft-tech/ci-github-nodejs/actions/build@dde8f0c67661ed66da8871a9fb104d36e146d644 # copilot/refactor-ci-actions-lint-test + with: + # Working directory where the build commands are executed. + # Can be absolute or relative to the repository root. + # + # Default: `.` + working-directory: . + + # List of build commands to execute, one per line. + # These are npm/pnpm/yarn script names (e.g., "build", "compile"). + # + # This input is required. + build-commands: "" + + # JSON object of environment variables to set during the build. + # Example: {"NODE_ENV": "production", "API_URL": "https://api.example.com"} + # + # Default: `{}` + build-env: "{}" + + # Multi-line string of secrets in env format (KEY=VALUE). + # Example: + # ``` + # SECRET_KEY=${{ secrets.SECRET_KEY }} + # API_TOKEN=${{ secrets.API_TOKEN }} + # ``` + build-secrets: "" + + # JSON object specifying artifact upload configuration. + # Format: {"name": "artifact-name", "paths": "path1\npath2"} + build-artifact: "" + + # Whether running in container mode (skips checkout and node setup) + # Default: `false` + container: "false" +```` + + + + +## Inputs + +| **Input** | **Description** | **Required** | **Default** | +| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | ------------ | ----------- | +| **`working-directory`** | Working directory where the build commands are executed. | **false** | `.` | +| | Can be absolute or relative to the repository root. | | | +| **`build-commands`** | List of build commands to execute, one per line. | **true** | - | +| | These are npm/pnpm/Yarn script names (e.g., "build", "compile"). | | | +| **`build-env`** | JSON object of environment variables to set during the build. | **false** | `\{}` | +| | Example: {"NODE_ENV": "production", "API_URL": " | | | +| **`build-secrets`** | Multi-line string of secrets in env format (KEY=VALUE). | **false** | - | +| | Example: | | | +| |
SECRET_KEY=${{ secrets.SECRET_KEY }}
API_TOKEN=${{ secrets.API_TOKEN }}
| | | +| **`build-artifact`** | JSON object specifying artifact upload configuration. | **false** | - | +| | Format: {"name": "artifact-name", "paths": "path1\npath2"} | | | +| **`container`** | Whether running in container mode (skips checkout and node setup) | **false** | `false` | + + + + + + +## Outputs + +| **Output** | **Description** | +| ----------------- | ------------------------------------------------------- | +| **`artifact-id`** | ID of the uploaded artifact (if artifact was specified) | + + + + + + + + + +## Contributing + +Contributions are welcome! Please see the [contributing guidelines](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md) for more details. + + + + + + +## License + +This project is licensed under the MIT License. + +SPDX-License-Identifier: MIT + +Copyright ยฉ 2025 hoverkraft + +For more details, see the [license](http://choosealicense.com/licenses/mit/). + + + + +--- + +This documentation was automatically generated by [CI Dokumentor](https://github.com/hoverkraft-tech/ci-dokumentor). + + + + diff --git a/actions/build/action.yml b/actions/build/action.yml new file mode 100644 index 0000000..cd1649e --- /dev/null +++ b/actions/build/action.yml @@ -0,0 +1,151 @@ +name: "Build" +description: "Action to build Node.js projects with support for custom commands, environment variables, and artifact handling" +author: hoverkraft +branding: + icon: package + color: blue + +inputs: + working-directory: + description: | + Working directory where the build commands are executed. + Can be absolute or relative to the repository root. + required: false + default: "." + build-commands: + description: | + List of build commands to execute, one per line. + These are npm/pnpm/yarn script names (e.g., "build", "compile"). + required: true + build-env: + description: | + JSON object of environment variables to set during the build. + Example: {"NODE_ENV": "production", "API_URL": "https://api.example.com"} + required: false + default: "{}" + build-secrets: + description: | + Multi-line string of secrets in env format (KEY=VALUE). + Example: + ``` + SECRET_KEY=$\{{ secrets.SECRET_KEY }} + API_TOKEN=$\{{ secrets.API_TOKEN }} + ``` + required: false + default: "" + build-artifact: + description: | + JSON object specifying artifact upload configuration. + Format: {"name": "artifact-name", "paths": "path1\npath2"} + required: false + default: "" + container: + description: "Whether running in container mode (skips checkout and node setup)" + required: false + default: "false" + +outputs: + artifact-id: + description: "ID of the uploaded artifact (if artifact was specified)" + value: ${{ steps.build-artifact-id.outputs.artifact-id }} + +runs: + using: "composite" + steps: + - shell: bash + # FIXME: workaround until will be merged: https://github.com/actions/runner/pull/1684 + run: mkdir -p ./self-build-action/ && cp -r $GITHUB_ACTION_PATH/../* ./self-build-action/ + + - id: setup-node + if: inputs.container != 'true' + uses: ./self-build-action/setup-node + with: + working-directory: ${{ inputs.working-directory }} + dependencies-cache: | + nx + gatsby + storybook + + - id: get-package-manager + if: inputs.container == 'true' + uses: ./self-build-action/get-package-manager + with: + working-directory: ${{ inputs.working-directory }} + + - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + env: + BUILD_ENV: ${{ inputs.build-env }} + BUILD_SECRETS: ${{ inputs.build-secrets }} + with: + script: | + const envInput = process.env.BUILD_ENV || '{}'; + + let buildEnv = {}; + + try { + buildEnv = JSON.parse(envInput); + } catch (e) { + core.setFailed(`Invalid build env JSON: ${e.message}`); + } + + for (const [key, value] of Object.entries(buildEnv)) { + core.exportVariable(key, value); + } + + const secretsInput = process.env.BUILD_SECRETS || ''; + for (const line of secretsInput.split('\n').map(line => line.trim()).filter(Boolean)) { + const [key, ...rest] = line.split('='); + if (!key || !rest.length) { + return core.setFailed(`Invalid build secrets format: ${line}`); + } + const value = rest.join('='); + core.exportVariable(key.trim(), value.trim()); + } + + - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + env: + BUILD_COMMANDS: ${{ inputs.build-commands }} + RUN_SCRIPT_COMMAND: ${{ inputs.container == 'true' && steps.get-package-manager.outputs.run-script-command || steps.setup-node.outputs.run-script-command }} + WORKING_DIRECTORY: ${{ inputs.working-directory }} + with: + script: | + const buildCommands = process.env.BUILD_COMMANDS || ''; + const runScriptCommand = process.env.RUN_SCRIPT_COMMAND; + const workingDirectory = process.env.WORKING_DIRECTORY || '.'; + + const commands = buildCommands.split('\n') + .map(cmd => cmd.trim()) + .filter(Boolean); + + for (const command of commands) { + core.info(`Running build command: ${command}`); + + try { + const result = await exec.getExecOutput(runScriptCommand, [command], { + cwd: require('path').resolve(process.env.GITHUB_WORKSPACE, workingDirectory) + }); + + if (result.stdout) { + core.info(result.stdout); + } + if (result.stderr) { + core.warning(result.stderr); + } + } catch (error) { + core.setFailed(`Build command "${command}" failed: ${error.message}`); + throw error; + } + } + + - id: build-artifact-id + if: inputs.build-artifact != '' + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + with: + name: ${{ fromJSON(inputs.build-artifact).name }} + path: ${{ fromJSON(inputs.build-artifact).paths }} + if-no-files-found: error + + # FIXME: workaround until will be merged: https://github.com/actions/runner/pull/1684 + - shell: bash + if: always() + run: rm -fr ./self-build-action diff --git a/actions/dependencies-cache/action.yml b/actions/dependencies-cache/action.yml index 56d1bff..245c3da 100644 --- a/actions/dependencies-cache/action.yml +++ b/actions/dependencies-cache/action.yml @@ -1,9 +1,9 @@ name: "Dependencies cache" description: "Action to setup dependencies cache managment." -author: Hoverkraft +author: hoverkraft branding: icon: archive - color: gray-dark + color: blue inputs: dependencies: diff --git a/actions/get-package-manager/action.yml b/actions/get-package-manager/action.yml index 944f9a3..35d09e0 100644 --- a/actions/get-package-manager/action.yml +++ b/actions/get-package-manager/action.yml @@ -1,9 +1,9 @@ name: "Get package manager" description: "Action to detect the package manager used. Supports Yarn, pnpm, and npm" -author: Hoverkraft +author: hoverkraft branding: icon: package - color: gray-dark + color: blue inputs: working-directory: diff --git a/actions/has-installed-dependencies/action.yml b/actions/has-installed-dependencies/action.yml index f8e82b9..078f4e0 100644 --- a/actions/has-installed-dependencies/action.yml +++ b/actions/has-installed-dependencies/action.yml @@ -1,9 +1,9 @@ name: "Has installed dependencies" description: "Action to check if dependencies have been installed according to the package manager used." -author: Hoverkraft +author: hoverkraft branding: icon: settings - color: gray-dark + color: blue inputs: dependencies: diff --git a/actions/lint/README.md b/actions/lint/README.md new file mode 100644 index 0000000..a24544e --- /dev/null +++ b/actions/lint/README.md @@ -0,0 +1,113 @@ + + +# ![Icon](data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJmZWF0aGVyIGZlYXRoZXItY2hlY2stY2lyY2xlIiBjb2xvcj0iYmx1ZSI+PHBhdGggZD0iTTIyIDExLjA4VjEyYTEwIDEwIDAgMSAxLTUuOTMtOS4xNCI+PC9wYXRoPjxwb2x5bGluZSBwb2ludHM9IjIyIDQgMTIgMTQuMDEgOSAxMS4wMSI+PC9wb2x5bGluZT48L3N2Zz4=) GitHub Action: Lint + +
+ Lint +
+ +--- + + + + +[![Marketplace](https://img.shields.io/badge/Marketplace-lint-blue?logo=github-actions)](https://github.com/marketplace/actions/lint) +[![Release](https://img.shields.io/github/v/release/hoverkraft-tech/ci-github-nodejs)](https://github.com/hoverkraft-tech/ci-github-nodejs/releases) +[![License](https://img.shields.io/github/license/hoverkraft-tech/ci-github-nodejs)](http://choosealicense.com/licenses/mit/) +[![Stars](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social)](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social) +[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md) + + + + +## Overview + +Action to lint Node.js projects with support for pull request reporting and annotations + + + + +## Usage + +```yaml +- uses: hoverkraft-tech/ci-github-nodejs/actions/lint@dde8f0c67661ed66da8871a9fb104d36e146d644 # copilot/refactor-ci-actions-lint-test + with: + # Working directory where lint commands are executed. + # Can be absolute or relative to the repository root. + # + # Default: `.` + working-directory: . + + # Whether running in container mode (skips checkout and node setup) + # Default: `false` + container: "false" + + # Path to lint report file to process as GitHub annotations. + # Supports ESLint JSON and Checkstyle XML formats. + # If not specified, auto-detection will be attempted for common paths: + # - eslint-report.json, eslint.json + # - checkstyle-result.xml, checkstyle.xml + report-file: "" +``` + + + + +## Inputs + +| **Input** | **Description** | **Required** | **Default** | +| ----------------------- | -------------------------------------------------------------------- | ------------ | ----------- | +| **`working-directory`** | Working directory where lint commands are executed. | **false** | `.` | +| | Can be absolute or relative to the repository root. | | | +| **`container`** | Whether running in container mode (skips checkout and node setup) | **false** | `false` | +| **`report-file`** | Path to lint report file to process as GitHub annotations. | **false** | - | +| | Supports ESLint JSON and Checkstyle XML formats. | | | +| | If not specified, auto-detection will be attempted for common paths: | | | +| | - eslint-report.json, eslint.json | | | +| | - checkstyle-result.xml, checkstyle.xml | | | + + + + + + + + + + + + + +## Contributing + +Contributions are welcome! Please see the [contributing guidelines](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md) for more details. + + + + + + +## License + +This project is licensed under the MIT License. + +SPDX-License-Identifier: MIT + +Copyright ยฉ 2025 hoverkraft + +For more details, see the [license](http://choosealicense.com/licenses/mit/). + + + + +--- + +This documentation was automatically generated by [CI Dokumentor](https://github.com/hoverkraft-tech/ci-dokumentor). + + + + diff --git a/actions/lint/action.yml b/actions/lint/action.yml new file mode 100644 index 0000000..1e8f692 --- /dev/null +++ b/actions/lint/action.yml @@ -0,0 +1,165 @@ +name: "Lint" +description: "Action to lint Node.js projects with support for pull request reporting and annotations" +author: hoverkraft +branding: + icon: check-circle + color: blue + +inputs: + working-directory: + description: | + Working directory where lint commands are executed. + Can be absolute or relative to the repository root. + required: false + default: "." + container: + description: "Whether running in container mode (skips checkout and node setup)" + required: false + default: "false" + report-file: + description: | + Path to lint report file to process as GitHub annotations. + Supports ESLint JSON and Checkstyle XML formats. + If not specified, auto-detection will be attempted for common paths: + - eslint-report.json, eslint.json + - checkstyle-result.xml, checkstyle.xml + required: false + default: "" + +runs: + using: "composite" + steps: + - shell: bash + # FIXME: workaround until will be merged: https://github.com/actions/runner/pull/1684 + run: mkdir -p ./self-lint-action/ && cp -r $GITHUB_ACTION_PATH/../* ./self-lint-action/ + + - id: setup-node + if: inputs.container != 'true' + uses: ./self-lint-action/setup-node + with: + working-directory: ${{ inputs.working-directory }} + dependencies-cache: | + nx + prettier + + - id: get-package-manager + if: inputs.container == 'true' + uses: ./self-lint-action/get-package-manager + with: + working-directory: ${{ inputs.working-directory }} + + - id: run-lint + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + env: + RUN_LINT_COMMAND: ${{ inputs.container == 'true' && steps.get-package-manager.outputs.run-script-command || steps.setup-node.outputs.run-script-command }} + WORKING_DIRECTORY: ${{ inputs.working-directory }} + with: + script: | + const workingDirectory = process.env.WORKING_DIRECTORY || '.'; + const runScriptCommand = process.env.RUN_LINT_COMMAND; + + core.info('๐Ÿ‘• Running lint...'); + + try { + const result = await exec.getExecOutput(runScriptCommand, ['lint'], { + cwd: require('path').resolve(process.env.GITHUB_WORKSPACE, workingDirectory), + ignoreReturnCode: true + }); + + if (result.stdout) core.info(result.stdout); + if (result.stderr) core.warning(result.stderr); + + core.setOutput('lint-exit-code', result.exitCode); + + if (result.exitCode !== 0) { + core.setFailed(`Linting failed with exit code ${result.exitCode}`); + } + } catch (error) { + core.setOutput('lint-exit-code', 1); + core.setFailed(`Linting error: ${error.message}`); + } + + # Auto-detect report file if not specified + - id: detect-report-file + if: always() + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + env: + REPORT_FILE: ${{ inputs.report-file }} + WORKING_DIRECTORY: ${{ inputs.working-directory }} + with: + script: | + const path = require('node:path'); + const fs = require('node:fs'); + + const workingDirectory = process.env.WORKING_DIRECTORY || '.'; + const workDir = path.resolve(process.env.GITHUB_WORKSPACE, workingDirectory); + + const autoDetectReportFormat = (filePath) => { + if (filePath.endsWith('.json')) { + return 'eslint'; + } else if (filePath.endsWith('.xml')) { + return 'checkstyle'; + } + return core.setFailed(`Unable to auto-detect report format from file extension: ${filePath}`); + }; + + if (process.env.REPORT_FILE && process.env.REPORT_FILE.trim() !== '') { + const reportFilePath = path.join(workDir, process.env.REPORT_FILE.trim()); + + if (!fs.existsSync(reportFilePath)) { + core.setFailed(`Specified report file does not exist: ${process.env.REPORT_FILE.trim()}`); + return; + } + core.info(`Report file specified: ${reportFilePath}`); + core.setOutput('report-file', reportFilePath); + core.setOutput('report-format', autoDetectReportFormat(reportFilePath)); + + return; + } + + // Common lint report file paths + const commonPaths = [ + 'eslint-report.json', + 'eslint.json', + '.eslint-report.json', + 'checkstyle-result.xml', + 'checkstyle.xml', + 'lint-results.xml', + 'reports/eslint-report.json', + 'reports/checkstyle.xml' + ]; + + for (const filePath of commonPaths) { + const fullPath = path.join(workDir, filePath); + if (fs.existsSync(fullPath)) { + core.info(`Auto-detected lint report file: ${fullPath}`); + core.setOutput('report-file', fullPath); + + // Auto-detect format from extension + core.setOutput('report-format', autoDetectReportFormat(fullPath)); + return; + } + } + + core.info('No lint report file auto-detected'); + + # Process ESLint report + - name: ๐Ÿ“Š Annotate ESLint results + if: always() && steps.detect-report-file.outputs.report-format == 'eslint' + uses: ataylorme/eslint-annotate-action@d57a1193d4c59cbfbf3f86c271f42612f9dbd9e9 # v3.0.0 + with: + report-json: ${{ steps.detect-report-file.outputs.report-file }} + fail-on-error: false + fail-on-warning: false + + # Process Checkstyle report + - name: ๐Ÿ“Š Annotate Checkstyle results + if: always() && steps.detect-report-file.outputs.report-format == 'checkstyle' + uses: lcollins/checkstyle-github-action@658deddef713a1132a9c59b64d754221b66a6f27 # v3.1.0 + with: + path: ${{ steps.detect-report-file.outputs.report-file }} + + # FIXME: workaround until will be merged: https://github.com/actions/runner/pull/1684 + - shell: bash + if: always() + run: rm -fr ./self-lint-action diff --git a/actions/setup-node/action.yml b/actions/setup-node/action.yml index ce6de12..61caef8 100644 --- a/actions/setup-node/action.yml +++ b/actions/setup-node/action.yml @@ -1,9 +1,9 @@ name: "Setup Node.js" description: "Action to setup Node.js and install dependencies according to the package manager used." -author: Hoverkraft +author: hoverkraft branding: icon: settings - color: gray-dark + color: blue inputs: dependencies-cache: diff --git a/actions/test/README.md b/actions/test/README.md new file mode 100644 index 0000000..ffce263 --- /dev/null +++ b/actions/test/README.md @@ -0,0 +1,135 @@ + + +# ![Icon](data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJmZWF0aGVyIGZlYXRoZXItY2hlY2stc3F1YXJlIiBjb2xvcj0iYmx1ZSI+PHBvbHlsaW5lIHBvaW50cz0iOSAxMSAxMiAxNCAyMiA0Ij48L3BvbHlsaW5lPjxwYXRoIGQ9Ik0yMSAxMnY3YTIgMiAwIDAgMS0yIDJINWEyIDIgMCAwIDEtMi0yVjVhMiAyIDAgMCAxIDItMmgxMSI+PC9wYXRoPjwvc3ZnPg==) GitHub Action: Test + +
+ Test +
+ +--- + + + + +[![Marketplace](https://img.shields.io/badge/Marketplace-test-blue?logo=github-actions)](https://github.com/marketplace/actions/test) +[![Release](https://img.shields.io/github/v/release/hoverkraft-tech/ci-github-nodejs)](https://github.com/hoverkraft-tech/ci-github-nodejs/releases) +[![License](https://img.shields.io/github/license/hoverkraft-tech/ci-github-nodejs)](http://choosealicense.com/licenses/mit/) +[![Stars](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social)](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social) +[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md) + + + + +## Overview + +Action to test Node.js projects with support for coverage reporting and pull request annotations + + + + +## Usage + +```yaml +- uses: hoverkraft-tech/ci-github-nodejs/actions/test@dde8f0c67661ed66da8871a9fb104d36e146d644 # copilot/refactor-ci-actions-lint-test + with: + # Working directory where test commands are executed. + # Can be absolute or relative to the repository root. + # + # Default: `.` + working-directory: . + + # Whether running in container mode (skips checkout and node setup) + # Default: `false` + container: "false" + + # Code coverage reporter to use. Supported values: + # - "github": Use ReportGenerator for PR comments with coverage reports + # - "codecov": Upload coverage to Codecov + # - "": No coverage reporting + # + # Default: `github` + coverage: github + + # Path to coverage files for reporting. + # Supports multiple formats (Cobertura, OpenCover, lcov, etc.). + # Can be a single file or multiple files separated by semicolons. + # If not specified, auto-detection will be attempted for common paths: + # - coverage/cobertura-coverage.xml, coverage/coverage.xml + # - coverage/lcov.info + # - coverage/clover.xml + coverage-files: "" + + # GitHub token for coverage PR comments. + # Required when coverage is set to "github". + github-token: "" +``` + + + + +## Inputs + +| **Input** | **Description** | **Required** | **Default** | +| ----------------------- | --------------------------------------------------------------------- | ------------ | ----------- | +| **`working-directory`** | Working directory where test commands are executed. | **false** | `.` | +| | Can be absolute or relative to the repository root. | | | +| **`container`** | Whether running in container mode (skips checkout and node setup) | **false** | `false` | +| **`coverage`** | Code coverage reporter to use. Supported values: | **false** | `github` | +| | - "GitHub": Use ReportGenerator for PR comments with coverage reports | | | +| | - "Codecov": Upload coverage to Codecov | | | +| | - "": No coverage reporting | | | +| **`coverage-files`** | Path to coverage files for reporting. | **false** | - | +| | Supports multiple formats (Cobertura, OpenCover, lcov, etc.). | | | +| | Can be a single file or multiple files separated by semicolons. | | | +| | If not specified, auto-detection will be attempted for common paths: | | | +| | - coverage/cobertura-coverage.xml, coverage/coverage.xml | | | +| | - coverage/lcov.info | | | +| | - coverage/clover.xml | | | +| **`github-token`** | GitHub token for coverage PR comments. | **false** | - | +| | Required when coverage is set to "GitHub". | | | + + + + + + + + + + + + + +## Contributing + +Contributions are welcome! Please see the [contributing guidelines](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md) for more details. + + + + + + +## License + +This project is licensed under the MIT License. + +SPDX-License-Identifier: MIT + +Copyright ยฉ 2025 hoverkraft + +For more details, see the [license](http://choosealicense.com/licenses/mit/). + + + + +--- + +This documentation was automatically generated by [CI Dokumentor](https://github.com/hoverkraft-tech/ci-dokumentor). + + + + diff --git a/actions/test/action.yml b/actions/test/action.yml new file mode 100644 index 0000000..6f0fd23 --- /dev/null +++ b/actions/test/action.yml @@ -0,0 +1,195 @@ +name: "Test" +description: "Action to test Node.js projects with support for coverage reporting and pull request annotations" +author: hoverkraft +branding: + icon: check-square + color: blue + +inputs: + working-directory: + description: | + Working directory where test commands are executed. + Can be absolute or relative to the repository root. + required: false + default: "." + container: + description: "Whether running in container mode (skips checkout and node setup)" + required: false + default: "false" + coverage: + description: | + Code coverage reporter to use. Supported values: + - "github": Use ReportGenerator for PR comments with coverage reports + - "codecov": Upload coverage to Codecov + - "": No coverage reporting + required: false + default: "github" + coverage-files: + description: | + Path to coverage files for reporting. + Supports multiple formats (Cobertura, OpenCover, lcov, etc.). + Can be a single file or multiple files separated by semicolons. + If not specified, auto-detection will be attempted for common paths: + - coverage/cobertura-coverage.xml, coverage/coverage.xml + - coverage/lcov.info + - coverage/clover.xml + required: false + default: "" + github-token: + description: | + GitHub token for coverage PR comments. + Required when coverage is set to "github". + required: false + default: "" + +runs: + using: "composite" + steps: + - shell: bash + # FIXME: workaround until will be merged: https://github.com/actions/runner/pull/1684 + run: mkdir -p ./self-test-action/ && cp -r $GITHUB_ACTION_PATH/../* ./self-test-action/ + + - id: setup-node + if: inputs.container != 'true' + uses: ./self-test-action/setup-node + with: + working-directory: ${{ inputs.working-directory }} + dependencies-cache: | + nx + jest + + - id: get-package-manager + if: inputs.container == 'true' + uses: ./self-test-action/get-package-manager + with: + working-directory: ${{ inputs.working-directory }} + + - id: run-test + name: ๐Ÿงช Run tests + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + env: + RUN_TEST_COMMAND: ${{ inputs.container == 'true' && steps.get-package-manager.outputs.run-script-command || steps.setup-node.outputs.run-script-command }} + WORKING_DIRECTORY: ${{ inputs.working-directory }} + with: + script: | + const workingDirectory = process.env.WORKING_DIRECTORY || '.'; + const runScriptCommand = process.env.RUN_TEST_COMMAND; + try { + const result = await exec.getExecOutput(runScriptCommand, ['test:ci'], { + cwd: require('path').resolve(process.env.GITHUB_WORKSPACE, workingDirectory), + env: { ...process.env, CI: 'true' }, + ignoreReturnCode: true + }); + + if (result.stdout) core.info(result.stdout); + if (result.stderr) core.warning(result.stderr); + + core.setOutput('test-exit-code', result.exitCode); + + if (result.exitCode !== 0) { + core.setFailed(`Tests failed with exit code ${result.exitCode}`); + } + } catch (error) { + core.setOutput('test-exit-code', 1); + core.setFailed(`Test execution error: ${error.message}`); + } + + # Auto-detect coverage files if not specified + - id: detect-coverage-files + if: always() && inputs.coverage == 'github' + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + env: + WORKING_DIRECTORY: ${{ inputs.working-directory }} + COVERAGE_FILES: ${{ inputs.coverage-files }} + with: + script: | + const path = require('node:path'); + const fs = require('node:fs'); + + const workingDirectory = process.env.WORKING_DIRECTORY || '.'; + const workDir = path.resolve(process.env.GITHUB_WORKSPACE, workingDirectory); + + if (process.env.COVERAGE_FILES && process.env.COVERAGE_FILES.trim() !== '') { + core.info(`Using specified coverage files: ${process.env.COVERAGE_FILES}`); + core.setOutput('coverage-files', process.env.COVERAGE_FILES); + return; + } + + // Common coverage file paths + const commonPaths = [ + 'coverage/cobertura-coverage.xml', + 'coverage/coverage.xml', + 'coverage/lcov.info', + 'coverage/clover.xml', + 'coverage/coverage-final.json', + 'test-results/coverage.xml', + 'test-results/cobertura-coverage.xml' + ]; + + for (const filePath of commonPaths) { + const fullPath = path.join(workDir, filePath); + if (fs.existsSync(fullPath)) { + core.info(`Auto-detected coverage file: ${fullPath}`); + core.setOutput('coverage-files', fullPath); + return; + } + } + + core.warning('No coverage file auto-detected'); + + # ReportGenerator for PR comments with coverage reports + - name: ๐Ÿ“Š Generate coverage report + if: always() && inputs.coverage == 'github' && github.event_name == 'pull_request' && steps.detect-coverage-files.outputs.coverage-files + uses: danielpalme/ReportGenerator-GitHub-Action@dcdfb6e704e87df6b2ed0cf123a6c9f69e364869 # v5.5.0 + with: + reports: ${{ steps.detect-coverage-files.outputs.coverage-files }} + targetdir: ${{ runner.temp }}/coveragereport-${{ github.run_id }} + reporttypes: MarkdownSummaryGithub + sourcedirs: ${{ inputs.working-directory }} + + - if: always() && inputs.coverage == 'github' + id: get-coverage-report-summary + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + env: + SUMMARY_FILE: ${{ runner.temp }}/coveragereport-${{ github.run_id }}/SummaryGithub.md + with: + script: | + const fs = require('fs'); + const summaryFilePath = process.env.SUMMARY_FILE; + + if (!fs.existsSync(summaryFilePath)) { + return core.setFailed(`Coverage summary file not found: ${summaryFilePath}`); + } + + const summaryContent = fs.readFileSync(summaryFilePath, 'utf8'); + core.summary.addRaw(summaryContent).write(); + + core.setOutput('summary-content', summaryContent); + + - name: ๐Ÿ“Š Add coverage PR comment + if: always() && steps.get-coverage-report-summary.outputs.summary-content + uses: hoverkraft-tech/ci-github-common/actions/create-or-update-comment@5f11437c716059f30c635f90055060e4ef8b31a0 # 0.28.0 + with: + title: "Code Coverage Report" + body: ${{ steps.get-coverage-report-summary.outputs.summary-content }} + + # Install dependencies for codecov in container mode + - name: Install Codecov dependencies + if: inputs.coverage == 'codecov' && inputs.container == 'true' + uses: pkgxdev/setup@f211ee4db3110b42e5a156282372527e7c1ed723 # v4.0.0 + with: + +: git curl gnupg.org + + - name: ๐Ÿ“Š Upload coverage to Codecov + if: always() && inputs.coverage == 'codecov' + uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1 + with: + working-directory: ${{ inputs.working-directory }} + use_oidc: true + disable_telem: true + fail_ci_if_error: false + + # FIXME: workaround until will be merged: https://github.com/actions/runner/pull/1684 + - shell: bash + if: always() + run: rm -fr ./self-test-action diff --git a/tests/npm/package-lock.json b/tests/npm/package-lock.json index ed2590a..f7342f5 100644 --- a/tests/npm/package-lock.json +++ b/tests/npm/package-lock.json @@ -91,6 +91,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.4.tgz", "integrity": "sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g==", "license": "MIT", + "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", @@ -2739,6 +2740,7 @@ "resolved": "https://registry.npmjs.org/@gatsbyjs/reach-router/-/reach-router-2.0.1.tgz", "integrity": "sha512-gmSZniS9/phwgEgpFARMpNg21PkYDZEpfgEzvkgpE/iku4uvXqCrxr86fXbTpI9mkrhKS1SCTYmLGe60VdHcdQ==", "license": "MIT", + "peer": true, "dependencies": { "invariant": "^2.2.4", "prop-types": "^15.8.1" @@ -4515,6 +4517,7 @@ "resolved": "https://registry.npmjs.org/@parcel/core/-/core-2.8.3.tgz", "integrity": "sha512-Euf/un4ZAiClnlUXqPB9phQlKbveU+2CotZv7m7i+qkgvFn5nAGnrV4h1OzQU42j9dpgOxWi7AttUDMrvkbhCQ==", "license": "MIT", + "peer": true, "dependencies": { "@mischnic/json-sourcemap": "^0.1.0", "@parcel/cache": "2.8.3", @@ -5637,7 +5640,6 @@ "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -5657,7 +5659,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -5670,7 +5671,6 @@ "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", "license": "Apache-2.0", - "peer": true, "dependencies": { "dequal": "^2.0.3" } @@ -5680,7 +5680,6 @@ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "license": "MIT", - "peer": true, "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -5694,8 +5693,7 @@ "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@testing-library/jest-dom": { "version": "6.6.3", @@ -5777,8 +5775,7 @@ "version": "5.0.4", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@types/babel__core": { "version": "7.20.5", @@ -6060,7 +6057,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz", "integrity": "sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q==", "license": "MIT", - "peer": true, "dependencies": { "@types/json-schema": "^7.0.7", "@typescript-eslint/scope-manager": "4.33.0", @@ -6085,7 +6081,6 @@ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", "license": "MIT", - "peer": true, "dependencies": { "eslint-visitor-keys": "^2.0.0" }, @@ -6132,7 +6127,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz", "integrity": "sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ==", "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/types": "4.33.0", "@typescript-eslint/visitor-keys": "4.33.0" @@ -6150,7 +6144,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.33.0.tgz", "integrity": "sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ==", "license": "MIT", - "peer": true, "engines": { "node": "^8.10.0 || ^10.13.0 || >=11.10.1" }, @@ -6164,7 +6157,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz", "integrity": "sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==", "license": "BSD-2-Clause", - "peer": true, "dependencies": { "@typescript-eslint/types": "4.33.0", "@typescript-eslint/visitor-keys": "4.33.0", @@ -6192,7 +6184,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz", "integrity": "sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg==", "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/types": "4.33.0", "eslint-visitor-keys": "^2.0.0" @@ -6782,6 +6773,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -6848,6 +6840,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -7393,7 +7386,6 @@ "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", "deprecated": "babel-eslint is now @babel/eslint-parser. This package will no longer receive updates.", "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.0.0", "@babel/parser": "^7.7.0", @@ -7414,7 +7406,6 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", "license": "Apache-2.0", - "peer": true, "engines": { "node": ">=4" } @@ -8006,6 +7997,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001735", "electron-to-chromium": "^1.5.204", @@ -8940,6 +8932,7 @@ "integrity": "sha512-L4NPsJlCfZsPeXukyzHFlg/i7IIVwHSItR0wg0FLNqYClJ4MQYTYLbC7EkjKYRLZF2iof2MUgN0EGy7MdQFChg==", "hasInstallScript": true, "license": "MIT", + "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/core-js" @@ -9621,7 +9614,6 @@ "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", "license": "MIT", - "peer": true, "engines": { "node": ">=6" } @@ -9734,8 +9726,7 @@ "version": "0.5.16", "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/dom-converter": { "version": "0.2.0", @@ -10307,6 +10298,7 @@ "integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==", "hasInstallScript": true, "license": "MIT", + "peer": true, "bin": { "esbuild": "bin/esbuild" }, @@ -10341,20 +10333,6 @@ "@esbuild/win32-x64": "0.25.5" } }, - "node_modules/esbuild-register": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.6.0.tgz", - "integrity": "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "debug": "^4.3.4" - }, - "peerDependencies": { - "esbuild": ">=0.12 <1" - } - }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -10388,6 +10366,7 @@ "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "7.12.11", "@eslint/eslintrc": "^0.4.3", @@ -10524,6 +10503,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-5.10.0.tgz", "integrity": "sha512-vcz32f+7TP+kvTUyMXZmCnNujBQZDNmcqPImw8b9PZ+16w1Qdm6ryRuYZYVaG9xRqqmAPr2Cs9FAX5gN+x/bjw==", "license": "BSD-3-Clause", + "peer": true, "dependencies": { "lodash": "^4.17.15", "string-natural-compare": "^3.0.1" @@ -10540,6 +10520,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz", "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", "license": "MIT", + "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.8", @@ -10603,6 +10584,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz", "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==", "license": "MIT", + "peer": true, "dependencies": { "aria-query": "^5.3.2", "array-includes": "^3.1.8", @@ -10632,6 +10614,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", "license": "MIT", + "peer": true, "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", @@ -10664,6 +10647,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=10" }, @@ -12440,6 +12424,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", "license": "BSD-2-Clause", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "5.62.0", "@typescript-eslint/types": "5.62.0", @@ -12829,6 +12814,7 @@ "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.11.0.tgz", "integrity": "sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==", "license": "MIT", + "peer": true, "engines": { "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" } @@ -15395,7 +15381,6 @@ "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "license": "MIT", - "peer": true, "bin": { "lz-string": "bin/bin.js" } @@ -17146,6 +17131,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", @@ -17755,6 +17741,7 @@ "version": "3.6.2", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", + "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -18246,6 +18233,7 @@ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -18429,6 +18417,7 @@ "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.9.2" } @@ -18936,7 +18925,6 @@ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", "license": "MIT", - "peer": true, "dependencies": { "loose-envify": "^1.1.0" } @@ -18965,6 +18953,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -20684,6 +20673,7 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "license": "(MIT OR CC0-1.0)", + "peer": true, "engines": { "node": ">=10" }, @@ -21227,6 +21217,7 @@ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.98.0.tgz", "integrity": "sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA==", "license": "MIT", + "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.6", diff --git a/tests/npm/package.json b/tests/npm/package.json index 9641c7e..3cdc0e2 100644 --- a/tests/npm/package.json +++ b/tests/npm/package.json @@ -1,9 +1,10 @@ { "name": "test-for-ci-with-npm", + "main": "src/index.js", "scripts": { "lint": "echo \"lint test\"", "build": "mkdir -p dist && echo \"build test\" > dist/test.txt", - "test:ci": "echo \"test CI\"" + "test:ci": "jest --coverage" }, "dependencies": { "gatsby": "^5.15.0", diff --git a/tests/npm/src/index.js b/tests/npm/src/index.js new file mode 100644 index 0000000..a7c7a71 --- /dev/null +++ b/tests/npm/src/index.js @@ -0,0 +1,5 @@ +function sample() { + return "sample"; +} + +module.exports = { sample }; diff --git a/tests/npm/src/index.spec.js b/tests/npm/src/index.spec.js new file mode 100644 index 0000000..038296d --- /dev/null +++ b/tests/npm/src/index.spec.js @@ -0,0 +1,8 @@ +const index = require("./index"); + +describe("sample function", () => { + it('should return "sample"', () => { + const result = index.sample(); + expect(result).toBe("sample"); + }); +});