diff --git a/.checkov.yaml b/.checkov.yaml index 096241a..0cab7b1 100644 --- a/.checkov.yaml +++ b/.checkov.yaml @@ -1,7 +1,4 @@ quiet: true skip-check: - - CKV_GHA_7 - # Ensure that HEALTHCHECK instructions have been added to container images - CKV_DOCKER_2 - # Ensure that a user for the container has been created - CKV_DOCKER_3 diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..22523e6 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,133 @@ +# Copilot Instructions + +This GitHub Action is written in TypeScript and transpiled to JavaScript. The +transpiled JavaScript is invoked from within a Docker container. Both the +TypeScript sources and the **generated** JavaScript code are contained in this +repository. The TypeScript sources are contained in the `src` directory and the +JavaScript code is contained in the `dist` directory. A GitHub Actions workflow +checks that the JavaScript code in `dist` is up-to-date. Therefore, you should +not review any changes to the contents of the `dist` folder and it is expected +that the JavaScript code in `dist` closely mirrors the TypeScript code it is +generated from. + +## Repository Structure + +| Path | Description | +| ---------------------- | ----------------------------------- | +| `__fixtures__/` | Unit Test Fixtures | +| `__tests__/` | Unit Tests | +| `.devcontainer/` | Development Container Configuration | +| `.github/` | GitHub Configuration | +| `.licenses/` | License Information | +| `.vscode/` | Visual Studio Code Configuration | +| `badges/` | Badges for readme | +| `dist/` | Generated JavaScript Code | +| `src/` | TypeScript Source Code | +| `.licensed.yml` | Licensed Configuration | +| `.markdown-lint.yml` | Markdown Linter Configuration | +| `.node-version` | Node.js Version Configuration | +| `.prettierrc.yml` | Prettier Formatter Configuration | +| `.yaml-lint.yml` | YAML Linter Configuration | +| `action.yml` | GitHub Action Metadata | +| `CODEOWNERS` | Code Owners File | +| `Dockerfile` | Dockerfile for the Action | +| `eslint.config.mjs` | ESLint Configuration | +| `jest.config.js` | Jest Configuration | +| `LICENSE` | License File | +| `package.json` | NPM Package Configuration | +| `README.md` | Project Documentation | +| `rollup.config.ts` | Rollup Bundler Configuration | +| `tsconfig.base.json` | Base TypeScript Configuration | +| `tsconfig.eslint.json` | TypeScript Configuration for ESLint | +| `tsconfig.json` | TypeScript Configuration | + +## Environment Setup + +Install dependencies by running: + +```bash +npm install +``` + +## Testing + +Ensure all unit tests pass by running: + +```bash +npm run test +``` + +Unit tests should exist in the `__tests__` directory. They are powered by +`jest`. Fixtures should be placed in the `__fixtures__` directory. + +## Bundling + +Any time files in the `src` directory are changed, you should run the following +command to bundle the TypeScript code into JavaScript: + +```bash +npm run bundle +``` + +## General Coding Guidelines + +- Follow standard TypeScript and JavaScript coding conventions and best + practices +- Changes should maintain consistency with existing patterns and style +- Document changes clearly and thoroughly, including updates to existing + comments when appropriate +- Do not include basic, unnecessary comments that simply restate what the code + is doing (focus on explaining _why_, not _what_) +- Use consistent error handling patterns throughout the codebase +- Use TypeScript's type system to ensure type safety and clarity +- Keep functions focused and manageable +- Use descriptive variable and function names that clearly convey their purpose +- Use JSDoc comments to document functions, classes, and complex logic +- After doing any refactoring, ensure to run `npm run test` to ensure that all + tests still pass and coverage requirements are met +- When suggesting code changes, always opt for the most maintainable approach. + Try your best to keep the code clean and follow "Don't Repeat Yourself" (DRY) + principles +- Avoid unnecessary complexity and always consider the long-term maintainability + of the code +- When writing unit tests, try to consider edge cases as well as the main path + of success. This will help ensure that the code is robust and can handle + unexpected inputs or situations +- Use the `@actions/core` package for logging over `console` to ensure + compatibility with GitHub Actions logging features + +### Versioning + +GitHub Actions are versioned using branch and tag names. Please ensure the +version in the project's `package.json` is updated to reflect the changes made +in the codebase. The version should follow +[Semantic Versioning](https://semver.org/) principles. + +## Pull Request Guidelines + +When creating a pull request (PR), please ensure that: + +- Keep changes focused and minimal (avoid large changes, or consider breaking + them into separate, smaller PRs) +- Formatting checks pass +- Linting checks pass +- Unit tests pass and coverage requirements are met +- The action has been transpiled to JavaScript and the `dist` directory is + up-to-date with the latest changes in the `src` directory +- If necessary, the `README.md` file is updated to reflect any changes in + functionality or usage + +The body of the PR should include: + +- A summary of the changes +- A special note of any changes to dependencies +- A link to any relevant issues or discussions +- Any additional context that may be helpful for reviewers + +## Code Review Guidelines + +When performing a code review, please follow these guidelines: + +- If there are changes that modify the functionality/usage of the action, + validate that there are changes in the `README.md` file that document the new + or modified functionality diff --git a/.github/prompts/create-release-notes.prompt.md b/.github/prompts/create-release-notes.prompt.md new file mode 100644 index 0000000..d5c7c0a --- /dev/null +++ b/.github/prompts/create-release-notes.prompt.md @@ -0,0 +1,34 @@ +# Create Release Notes + +You are an expert technical writer tasked with creating release notes for +updates to this repository. Your specific task is to generate release notes that +are clear, concise, and useful for developers and users of the project. + +## Guidelines + +Ensure you adhere to the following guidelines when creating release notes: + +- Use a clear and consistent format for the release notes +- Include a summary of the changes made in the release +- Highlight any new features, improvements, or bugfixes +- If applicable, include instructions for upgrading or migrating to the new + version +- Use technical language that is appropriate for the audience, but avoid jargon + that may not be understood by all users +- Ensure that the release notes are easy to read and navigate +- Include relevant issue or PR numbers where applicable +- Use proper Markdown formatting +- Use code blocks for commands, configuration examples, or code changes +- Use note and warning callouts for important information + +## Versioning + +GitHub Actions are versioned using branch and tag names. The version in the +project's `package.json` should reflect the changes made in the codebase and +follow [Semantic Versioning](https://semver.org/) principles. Depending on the +nature of the changes, please make sure to adjust the release notes accordingly: + +- For **major** changes, include a detailed description of the breaking changes + and how users can adapt to them +- For **minor** changes, highlight new features and improvements +- For **patch** changes, focus on bugfixes and minor improvements diff --git a/.github/prompts/unit-test.prompt.md b/.github/prompts/unit-test.prompt.md new file mode 100644 index 0000000..7e2cd35 --- /dev/null +++ b/.github/prompts/unit-test.prompt.md @@ -0,0 +1,84 @@ +# Create Unit Test(s) + +You are an expert software engineer tasked with creating unit tests for the +repository. Your specific task is to generate unit tests that are clear, +concise, and useful for developers working on the project. + +## Guidelines + +Ensure you adhere to the following guidelines when creating unit tests: + +- Use a clear and consistent format for the unit tests +- Include a summary of the functionality being tested +- Use descriptive test names that clearly convey their purpose +- Ensure tests cover both the main path of success and edge cases +- Use proper assertions to validate the expected outcomes +- Use `jest` for writing and running tests +- Place unit tests in the `__tests__` directory +- Use fixtures for any necessary test data, placed in the `__fixtures__` + directory + +## Example + +Use the following as an example of how to structure your unit tests: + +```typescript +/** + * Unit tests for the action's main functionality, src/main.ts + */ +import { jest } from '@jest/globals' +import * as core from '../__fixtures__/core.js' +import { wait } from '../__fixtures__/wait.js' + +// Mocks should be declared before the module being tested is imported. +jest.unstable_mockModule('@actions/core', () => core) +jest.unstable_mockModule('../src/wait.js', () => ({ wait })) + +// The module being tested should be imported dynamically. This ensures that the +// mocks are used in place of any actual dependencies. +const { run } = await import('../src/main.js') + +describe('main.ts', () => { + beforeEach(() => { + // Set the action's inputs as return values from core.getInput(). + core.getInput.mockImplementation(() => '500') + + // Mock the wait function so that it does not actually wait. + wait.mockImplementation(() => Promise.resolve('done!')) + }) + + afterEach(() => { + jest.resetAllMocks() + }) + + it('Sets the time output', async () => { + await run() + + // Verify the time output was set. + expect(core.setOutput).toHaveBeenNthCalledWith( + 1, + 'time', + // Simple regex to match a time string in the format HH:MM:SS. + expect.stringMatching(/^\d{2}:\d{2}:\d{2}/) + ) + }) + + it('Sets a failed status', async () => { + // Clear the getInput mock and return an invalid value. + core.getInput.mockClear().mockReturnValueOnce('this is not a number') + + // Clear the wait mock and return a rejected promise. + wait + .mockClear() + .mockRejectedValueOnce(new Error('milliseconds is not a number')) + + await run() + + // Verify that the action was marked as failed. + expect(core.setFailed).toHaveBeenNthCalledWith( + 1, + 'milliseconds is not a number' + ) + }) +}) +``` diff --git a/.github/workflows/check-dist.yml b/.github/workflows/check-dist.yml index 77da9ee..5c4bd8b 100644 --- a/.github/workflows/check-dist.yml +++ b/.github/workflows/check-dist.yml @@ -26,12 +26,10 @@ jobs: runs-on: ubuntu-latest steps: - # Checkout the repository. - name: Checkout id: checkout uses: actions/checkout@v4 - # Setup Node.js using the version specified in `.node-version`. - name: Setup Node.js id: setup-node uses: actions/setup-node@v4 @@ -39,12 +37,10 @@ jobs: node-version-file: .node-version cache: npm - # Install dependencies using `npm ci`. - name: Install Dependencies id: install run: npm ci - # Build the `dist/` directory. - name: Build dist/ Directory id: build run: npm run bundle diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index cf97a32..e79a14a 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -1,10 +1,10 @@ name: CodeQL on: - push: + pull_request: branches: - main - pull_request: + push: branches: - main schedule: @@ -12,6 +12,7 @@ on: permissions: actions: read + checks: write contents: read security-events: write @@ -24,42 +25,25 @@ jobs: fail-fast: false matrix: language: - - TypeScript + - typescript steps: - name: Checkout id: checkout uses: actions/checkout@v4 - # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL id: initialize uses: github/codeql-action/init@v3 with: + config-file: .github/codeql/codeql-config.yml languages: ${{ matrix.language }} - config-file: ./.github/codeql/codeql-config.yml - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main + source-root: src - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild id: autobuild uses: github/codeql-action/autobuild@v3 - # â„šī¸ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # âœī¸ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - name: Perform CodeQL Analysis id: analyze uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 86ad21b..ef2b507 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -24,14 +24,12 @@ jobs: runs-on: ubuntu-latest steps: - # Checkout the repository. - name: Checkout id: checkout uses: actions/checkout@v4 with: fetch-depth: 0 - # Setup Node.js using the version specified in `.node-version`. - name: Setup Node.js id: setup-node uses: actions/setup-node@v4 @@ -39,12 +37,10 @@ jobs: node-version-file: .node-version cache: npm - # Install dependencies using `npm ci`. - name: Install Dependencies id: install run: npm ci - # Lint the codebase using the `super-linter/super-linter` action. - name: Lint Codebase id: super-linter uses: super-linter/super-linter/slim@v7 diff --git a/.vscode/mcp.json b/.vscode/mcp.json new file mode 100644 index 0000000..7d7a7c0 --- /dev/null +++ b/.vscode/mcp.json @@ -0,0 +1,9 @@ +{ + "servers": { + "github": { + "url": "https://api.githubcopilot.com/mcp/", + "type": "http" + } + }, + "inputs": [] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..390e031 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,15 @@ +{ + "github.copilot.chat.reviewSelection.instructions": [ + { + "text": "Review the code changes carefully before accepting them." + } + ], + "github.copilot.chat.commitMessageGeneration.instructions": [ + { + "text": "Use conventional commit message format." + } + ], + "github.copilot.chat.pullRequestDescriptionGeneration.instructions": [ + { "text": "Always include a list of key changes." } + ] +} diff --git a/README.md b/README.md index cde566f..49d5c72 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ # Create a Container Action with the GitHub Actions Toolkit [![GitHub Super-Linter](https://github.com/actions/container-toolkit-action/actions/workflows/linter.yml/badge.svg)](https://github.com/super-linter/super-linter) -![Check `dist/`](https://github.com/actions/container-toolkit-action/actions/workflows/check-dist.yml/badge.svg) +[![Check dist/](https://github.com/actions/container-toolkit-action/actions/workflows/check-dist.yml/badge.svg)](https://github.com/actions/container-toolkit-action/actions/workflows/check-dist.yml) ![CI](https://github.com/actions/container-toolkit-action/actions/workflows/ci.yml/badge.svg) -[![Code Coverage](./badges/coverage.svg)](./badges/coverage.svg) +[![CodeQL](https://github.com/actions/container-toolkit-action/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/actions/container-toolkit-action/actions/workflows/codeql-analysis.yml) +[![Coverage](./badges/coverage.svg)](./badges/coverage.svg) Use this template to bootstrap the creation of a container action with the GitHub Actions toolkit. :rocket: @@ -38,10 +39,16 @@ need to perform some initial setup steps before you can develop your action. > [!NOTE] > -> You'll need to have reasonably modern versions of +> You'll need to have a reasonably modern version of > [Node.js](https://nodejs.org) and -> [Docker](https://www.docker.com/get-started/) handy (e.g. Node.js v20+ and -> docker engine v20+). +> [Docker](https://www.docker.com/get-started/) handy (Node.js v20.x or later +> and Docker engine v20+ or later should work!). If you are using a version +> manager like [`nodenv`](https://github.com/nodenv/nodenv) or +> [`fnm`](https://github.com/Schniz/fnm), this template has a `.node-version` +> file at the root of the repository that can be used to automatically switch to +> the correct version when you `cd` into the repository. Additionally, this +> `.node-version` file is used by GitHub Actions in any `actions/setup-node` +> actions. 1. :hammer_and_wrench: Install the dependencies @@ -194,14 +201,10 @@ So, what are you waiting for? Go ahead and start customizing your action! npm run all ``` - > [!WARNING] - > - > This step is important! It will run [`ncc`](https://github.com/vercel/ncc) - > to build the final JavaScript action code with all dependencies included. - > If you do not run this step, your action will not work correctly when it is - > used in a workflow. This step also includes the `--license` option for - > `ncc`, which will create a license file for all of the production node - > modules used in your project. + > This step is important! It will run [`rollup`](https://rollupjs.org/) to + > build the final JavaScript action code with all dependencies included. If + > you do not run this step, your action will not work correctly when it is + > used in a workflow. 1. Commit your changes @@ -222,7 +225,7 @@ So, what are you waiting for? Go ahead and start customizing your action! Your action is now published! :rocket: For information about versioning your action, see -[Versioning](https://github.com/actions/toolkit/blob/master/docs/action-versioning.md) +[Versioning](https://github.com/actions/toolkit/blob/main/docs/action-versioning.md) in the GitHub Actions toolkit. ## Validate the Action diff --git a/action.yml b/action.yml index 3735209..5c0ba01 100644 --- a/action.yml +++ b/action.yml @@ -1,18 +1,23 @@ -name: 'The name of your action here' -description: 'Provide a description here' -author: 'Your name or organization here' +name: The name of your action here +description: Provide a description here +author: Your name or organization here + +# Add your action's branding here. This will appear on the GitHub Marketplace. +branding: + icon: heart + color: red # Define your inputs here. inputs: milliseconds: - description: 'Your input description here' + description: Your input description here required: true default: '1000' # Define your outputs here. outputs: time: - description: 'Your output description here' + description: Your output description here runs: using: docker