diff --git a/.github/workflows/test.yml b/.github/workflows/test_basic.yml similarity index 72% rename from .github/workflows/test.yml rename to .github/workflows/test_basic.yml index 33d2ea4..398394f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test_basic.yml @@ -1,8 +1,8 @@ -name: "Test" +name: "Test Basic" on: pull_request: - branches: [test] + branches: [main, dev] types: [opened, reopened, synchronize] jobs: @@ -16,4 +16,7 @@ jobs: labels-minor: "enhancement" labels-major: "major" labels-patch: "chore, bug" + dry-run: true create-tag: true + path: "src/**" + tag-prefix: "@repo/admin@v{{version}}" diff --git a/.github/workflows/test_monorepo.yml b/.github/workflows/test_monorepo.yml new file mode 100644 index 0000000..33bffb3 --- /dev/null +++ b/.github/workflows/test_monorepo.yml @@ -0,0 +1,48 @@ +name: "Test Monorepo" + +on: + pull_request: + branches: [main, dev] + types: [opened, reopened, synchronize] + +jobs: + update-version: + runs-on: "ubuntu-latest" + steps: + - uses: "actions/checkout@v4" + - name: "Filter paths" + uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + test_monorepo: + - 'src/**' + main: + - '**' + + - name: "Update test-monorepo version" + if: steps.filter.outputs.test_monorepo == 'true' + uses: ./ + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + labels-minor: "enhancement" + labels-major: "major" + labels-patch: "chore, bug" + create-tag: true + skip-commit: true + path: "src/**" + tag-prefix: "@repo/test-monorepo@v{{version}}" + dry-run: true + + - name: "Update main version" + if: steps.filter.outputs.main == 'true' + uses: ./ + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + labels-minor: "enhancement" + labels-major: "major" + labels-patch: "chore, bug" + create-tag: true + skip-commit: true + tag-prefix: "@repo/root@v{{version}}" + dry-run: true diff --git a/.github/workflows/test_push.yml b/.github/workflows/test_push.yml index 92bbc69..e135d7c 100644 --- a/.github/workflows/test_push.yml +++ b/.github/workflows/test_push.yml @@ -1,4 +1,4 @@ -name: "Versioning" +name: "Test Push" on: push: @@ -23,4 +23,5 @@ jobs: labels-major: "major" labels-patch: "chore, bug" create-tag: true + dry-run: true pr-number: ${{ steps.pr.outputs.number }} diff --git a/.husky/pre-commit b/.husky/pre-commit index e69de29..664981c 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -0,0 +1,5 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +npx lint-staged +npm run build \ No newline at end of file diff --git a/.husky/pre-push b/.husky/pre-push deleted file mode 100644 index d6cb288..0000000 --- a/.husky/pre-push +++ /dev/null @@ -1 +0,0 @@ -npm run build diff --git a/.lintstagedrc b/.lintstagedrc new file mode 100644 index 0000000..652f65f --- /dev/null +++ b/.lintstagedrc @@ -0,0 +1,3 @@ +{ + "./src/**/*.{js,ts}": ["prettier --write", "eslint --max-warnings 0"] +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..f2330ac --- /dev/null +++ b/README.md @@ -0,0 +1,174 @@ +# GitHub Action: Versioning + +This GitHub Action automates the versioning process for pull requests in a repository. It checks for specific labels on the pull request to determine whether to increment the version as major, minor, or patch. If a version change is necessary, it updates the `package.json` file in the repository with the new version. + +## How It Works + +1. **Token Retrieval**: The action retrieves the GitHub token from the action inputs. +2. **Pull Request Check**: It checks if the action is triggered by a pull request. +3. **Label Fetching**: The action fetches existing labels from the pull request. +4. **Version Increment Logic**: Based on the labels, it determines the type of version increment: + - **Major**: If a label from the major labels list is found, the major version is incremented. + - **Minor**: If a label from the minor labels list is found, the minor version is incremented. + - **Patch**: If a label from the patch labels list is found, the patch version is incremented. +5. **Version Update**: If a version change is detected, it updates the `package.json` file with the new version. +6. **Commit Changes**: The action commits the changes back to the repository if the `skip-commit` input is not set to true. +7. **Tag Creation**: Optionally, it can create a tag for the new version based on the `create-tag` input. +8. **Path**: Optionally, it can specify the path to the `package.json` file to be updated. +9. **Dry Run**: Optionally, it can run in dry run mode to check if the version will be updated without actually committing the changes. + +## Inputs + +| Input | Required | Default Value | Description | +| -------------- | -------- | -------------- | ------------------------------------------------------------------------ | +| `github-token` | Yes | N/A | The GitHub token for authentication. | +| `pr-number` | No | N/A | The pull request number to check. | +| `labels-minor` | No | N/A | A comma-separated list of labels that trigger a minor version increment. | +| `labels-major` | No | N/A | A comma-separated list of labels that trigger a major version increment. | +| `labels-patch` | No | N/A | A comma-separated list of labels that trigger a patch version increment. | +| `skip-commit` | No | false | If set to true, the action will skip committing changes. | +| `create-tag` | No | false | If set to true, the action will create a tag for the new version. | +| `path` | No | `package.json` | The path to the `package.json` file (default is `package.json`). | +| `dry-run` | No | false | If set to true, the action will not commit changes. | + +## Example Usage + +### Basics + +```yaml +name: "Run on pull request merged" + +on: + pull_request: + +jobs: + update-version: + runs-on: "ubuntu-latest" + steps: + - uses: "actions/checkout@v4" + - uses: "noowah/pr-versioning@v1.2.0" + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + labels-minor: "enhancement" + labels-major: "major" + labels-patch: "chore, bug" +``` + +### Commit bumped version on pull request merged + +```yaml +name: "Run on pull request merged" + +on: + pull_request: + types: [closed] + +jobs: + update-version: + runs-on: "ubuntu-latest" + if: github.event.pull_request.merged == true + steps: + - uses: "actions/checkout@v4" + - uses: "noowah/pr-versioning@v1.2.0" + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + labels-minor: "enhancement" + labels-major: "major" + labels-patch: "chore, bug" +``` + +### Creating a tag on push + +- Because the `push` event does not have a pull request number, this action is not ideal to be use on push event as pull request number is required. +- However, we can get the PR number from the commit message. by using `git log -1 --pretty=%B` to get the commit message and then use `grep -oP '#\K[0-9]+'` to get the PR number. + +```yaml +name: "Run on pull request merged" + +on: + push: + branches: [dev] + +jobs: + update-version: + runs-on: "ubuntu-latest" + steps: + - uses: "actions/checkout@v4" + - name: "Get PR number" + id: pr + run: | + PR_NUMBER=$(git log -1 --pretty=%B | grep -oP '#\K[0-9]+' || echo '') + echo "PR_NUMBER=$PR_NUMBER" + echo "number=$PR_NUMBER" >> $GITHUB_OUTPUT + - uses: "noowah/pr-versioning@v1.2.0" + if: ${{ steps.pr.outputs.number != '' }} + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + labels-minor: "enhancement" + labels-major: "major" + labels-patch: "chore, bug" + create-tag: true + tag-prefix: "v{{version}}" +``` + +--- + +## Monorepo + +Example usage in a monorepo setup: + +- Because monorepo has multiple `package.json` files and if you are to manage each project version, you need to specify the path to the `package.json` file to be updated. +- Filter the paths to be updated by using `paths-filter` action like `dorny/paths-filter` together. +- Then use the `noowah/pr-versioning` action to update the version. +- By using tag-prefix, you can specify the tag prefix for each project. + +```yaml +name: "Test Monorepo" + +on: + pull_request: + branches: [main, dev] + types: [opened, reopened, synchronize] + +jobs: + update-version: + runs-on: "ubuntu-latest" + steps: + - uses: "actions/checkout@v4" + - name: "Filter paths" + uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + test_monorepo: + - 'apps/admin/**' + main: + - 'apps/client/**' + + - name: "Update admin version" + if: steps.filter.outputs.admin == 'true' + uses: ./ + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + labels-minor: "enhancement" + labels-major: "major" + labels-patch: "chore, bug" + create-tag: true + skip-commit: true + path: "apps/admin/**" + tag-prefix: "@repo/admin@v{{version}}" + dry-run: true + + - name: "Update client version" + if: steps.filter.outputs.client == 'true' + uses: ./ + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + labels-minor: "enhancement" + labels-major: "major" + labels-patch: "chore, bug" + create-tag: true + skip-commit: true + tag-prefix: "@repo/client@v{{version}}" + dry-run: true +``` diff --git a/action.yml b/action.yml index a720d17..b9c8441 100644 --- a/action.yml +++ b/action.yml @@ -16,16 +16,30 @@ inputs: description: "The label to update Patch version" required: true skip-commit: + type: boolean description: "Skip commit the changes to the repository" required: false + default: false path: description: "The path to the package.json file" required: false - default: "package.json" create-tag: + type: boolean description: "Create a tag using new version" required: false - default: "true" + default: false + tag-prefix: + description: "Tag prefix" + required: false + default: "v{{version}}" + pr-number: + description: "The pull request number" + required: false + dry-run: + type: boolean + description: "Dry run the action" + required: false + default: false runs: using: "node16" diff --git a/dist/index.js b/dist/index.js index b025668..764c7a5 100644 --- a/dist/index.js +++ b/dist/index.js @@ -55,7 +55,6 @@ async function run() { else { pullRequest = github_1.context.payload.pull_request; } - console.log("pullRequest", pullRequest); if (!pullRequest) return (0, core_1.setFailed)("This action should only be run on a push event or a pull request"); // #region get check & get pr information @@ -81,24 +80,34 @@ async function run() { patchLabels.forEach((label) => console.log(`- ${label}`)); console.groupEnd(); console.log(); // Empty space - const skipCommitInput = (0, core_1.getInput)("skip-commit"); - const skipCommit = skipCommitInput === "true"; - const createTagInput = (0, core_1.getInput)("create-tag"); - const createTag = createTagInput === "false" ? true : Boolean(createTagInput); - console.log("skipCommit", skipCommit); - console.log("createTag", createTag); - console.log("createTag", createTag); + // const skipCommitInput = getInput("skip-commit"); + // const skipCommit = + // skipCommitInput === "true" ? true : Boolean(skipCommitInput); + const skipCommit = Boolean((0, core_1.getInput)("skip-commit") === "true"); + // const createTagInput = getInput("create-tag"); + // const createTag = createTagInput === "false" ? true : Boolean(createTagInput); + const createTag = Boolean((0, core_1.getInput)("create-tag") === "true"); + // const dryRunInput = getInput("dry-run"); + // const dryRun = dryRunInput === "true" ? true : Boolean(dryRunInput); + const dryRun = Boolean((0, core_1.getInput)("dry-run") === "true"); const customPath = (0, core_1.getInput)("path"); - const packageJsonPath = customPath !== null && customPath !== void 0 ? customPath : "package.json"; + const path = customPath + ? customPath.replace(/\/\*\*/g, "") + "/package.json" + : "package.json"; + console.group("\nšŸ”§ Inputs:"); + console.log("- skip-commit:", skipCommit); + console.log("- create-tag:", createTag); + console.log("- dry-run:", dryRun); + console.log("- package.json path:", path); + console.groupEnd(); const { data: currentFile } = await octokit.rest.repos.getContent({ owner: github_1.context.repo.owner, repo: github_1.context.repo.repo, - path: packageJsonPath, + path, ref: pullRequest.head.ref, }); const packageJson = Buffer.from(currentFile.content, "base64").toString("utf-8"); const version = JSON.parse(packageJson).version; - console.log(version); try { // Fetch existing labels from the pull request const { data: pullRequestData } = await octokit.rest.pulls.get({ @@ -107,7 +116,7 @@ async function run() { pull_number: pullRequest.number, }); const existingLabels = pullRequestData.labels.map((label) => label.name); - console.group("Existing labels:"); + console.group("\nLabels detected:"); existingLabels.forEach((label) => console.log(`- ${label}`)); console.groupEnd(); console.log(); // Empty space @@ -119,7 +128,7 @@ async function run() { console.log("šŸŽ‰ Major label found"); newVersion = Number(version.split(".")[0]) + 1 + ".0.0"; } - if (isMinor) { + else if (isMinor) { console.log("šŸš€ Minor label found"); newVersion = version.split(".")[0] + @@ -127,7 +136,7 @@ async function run() { (Number(version.split(".")[1]) + 1) + ".0"; } - if (isPatch) { + else if (isPatch) { console.log("šŸ”§ Patch label found"); newVersion = version.split(".")[0] + @@ -138,32 +147,45 @@ async function run() { } if (newVersion === version) return console.log("No version change detected"); - console.log(`Expected version update: ${version} -> ${newVersion}`); (0, core_1.setOutput)("new-version", newVersion); (0, core_1.setOutput)("pull-request-number", pullRequest.number); + console.log(`- Expected version bump: ${version} -> ${newVersion}`); + if (!!dryRun) { + console.log("\nDry run mode enabled. Skipping actual changes."); + return; + } if (skipCommit) { - console.log("skipping commit"); + console.log(`skip commit: ${skipCommit}`); + console.log(`skipping version bump commit`); console.log(); // Empty space } else { - console.log("packageJsonPath", packageJsonPath); - const packageJson = JSON.parse(await fs_1.default.promises.readFile(packageJsonPath, "utf-8")); + let packageJson; + try { + packageJson = JSON.parse(await fs_1.default.promises.readFile(path, "utf-8")); + } + catch (error) { + return (0, core_1.setFailed)(`Failed to read package.json at path: ${path}`); + } + console.log("project found:", packageJson.name); packageJson.version = newVersion; - await fs_1.default.promises.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2)); + await fs_1.default.promises.writeFile(path, JSON.stringify(packageJson, null, 2)); await octokit.rest.repos.createOrUpdateFileContents({ owner: github_1.context.repo.owner, repo: github_1.context.repo.repo, - path: packageJsonPath, + path, message: `commit version update: ${version} -> ${newVersion}`, content: Buffer.from(JSON.stringify(packageJson, null, 2)).toString("base64"), - branch: pullRequest.head.ref, + branch: pullRequest.base.ref, sha: currentFile.sha, // Use the current file's SHA }); } if (createTag) { - const tagName = !!skipCommit ? version : newVersion; - console.log(`Creating Tag: ${tagName}`); console.log(); // Empty space + const tagPrefix = (0, core_1.getInput)("tag-prefix"); + const tagName = `${tagPrefix.replace("{{version}}", !skipCommit ? newVersion : version)}`; + console.log("- tag-name", tagName); + console.log(`\nCreating Tag: ${tagName}`); // Create a reference to the new tag await octokit.rest.git.createRef({ owner: github_1.context.repo.owner, diff --git a/package-lock.json b/package-lock.json index 88eb961..29887e7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "pr-versioning", + "name": "@noowah/pr-versioning", "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "pr-versioning", + "name": "@noowah/pr-versioning", "version": "1.0.0", "license": "ISC", "dependencies": { @@ -16,6 +16,7 @@ "devDependencies": { "@types/node": "^20.10.6", "husky": "^9.1.7", + "lint-staged": "^13.2.2", "typescript": "^5.7.3" } }, @@ -230,16 +231,248 @@ "ncc": "dist/ncc/cli.js" } }, + "node_modules/ansi-escapes": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-5.0.0.tgz", + "integrity": "sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^1.0.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/before-after-hook": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==" }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cli-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", + "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", + "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz", + "integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/deprecation": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true, + "license": "MIT" + }, + "node_modules/execa": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", + "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^4.3.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": "^14.18.0 || ^16.14.0 || >=18.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/human-signals": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", + "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=14.18.0" + } + }, "node_modules/husky": { "version": "9.1.7", "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", @@ -255,6 +488,203 @@ "url": "https://github.com/sponsors/typicode" } }, + "node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/lint-staged": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-13.3.0.tgz", + "integrity": "sha512-mPRtrYnipYYv1FEE134ufbWpeggNTo+O/UPzngoaKzbzHAthvR55am+8GfHTnqNRQVRRrYQLGW9ZyUoD7DsBHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "5.3.0", + "commander": "11.0.0", + "debug": "4.3.4", + "execa": "7.2.0", + "lilconfig": "2.1.0", + "listr2": "6.6.1", + "micromatch": "4.0.5", + "pidtree": "0.6.0", + "string-argv": "0.3.2", + "yaml": "2.3.1" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/listr2": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-6.6.1.tgz", + "integrity": "sha512-+rAXGHh0fkEWdXBmX+L6mmfmXmXvDGEKzkjxO+8mP3+nI/r/CWznVBvsibXdxda9Zz0OW2e2ikphN3OwCT/jSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^3.1.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^5.0.1", + "rfdc": "^1.3.0", + "wrap-ansi": "^8.1.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "enquirer": ">= 2.3.0 < 3" + }, + "peerDependenciesMeta": { + "enquirer": { + "optional": true + } + } + }, + "node_modules/log-update": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-5.0.1.tgz", + "integrity": "sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^5.0.0", + "cli-cursor": "^4.0.0", + "slice-ansi": "^5.0.0", + "strip-ansi": "^7.0.1", + "wrap-ansi": "^8.0.1" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -263,6 +693,225 @@ "wrappy": "1" } }, + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/restore-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", + "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/tunnel": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", @@ -271,6 +920,19 @@ "node": ">=0.6.11 <=0.7.0 || >=0.7.3" } }, + "node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/typescript": { "version": "5.7.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", @@ -306,10 +968,54 @@ "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz", "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==" }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/yaml": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", + "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 14" + } } } } diff --git a/package.json b/package.json index 4886328..05e113e 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,13 @@ { "name": "@noowah/pr-versioning", "author": "Hawoon JOH (https://github.com/henrynoowah)", - "version": "1.1.3", + "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "build": "tsc && ncc build lib/index.js", - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "prepare": "husky" }, "keywords": [ "github", @@ -17,6 +18,7 @@ "license": "ISC", "devDependencies": { "@types/node": "^20.10.6", + "lint-staged": "^13.2.2", "husky": "^9.1.7", "typescript": "^5.7.3" }, @@ -25,4 +27,4 @@ "@actions/github": "^6.0.0", "@vercel/ncc": "^0.38.3" } -} \ No newline at end of file +} diff --git a/src/index.ts b/src/index.ts index 1887953..40c6674 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,5 @@ import { getInput, setFailed, setOutput } from "@actions/core"; import { context, getOctokit } from "@actions/github"; -import { WebhookPayload } from "@actions/github/lib/interfaces"; import fs from "fs"; /** * Runs the versioning action for a GitHub pull request. @@ -48,8 +47,6 @@ async function run() { pullRequest = context.payload.pull_request; } - console.log("pullRequest", pullRequest); - if (!pullRequest) return setFailed( "This action should only be run on a push event or a pull request" @@ -57,7 +54,6 @@ async function run() { // #region get check & get pr information // #region Pull Request task - const minorLabels = getInput("labels-minor") .split(",") .map((label) => label.trim()); @@ -83,24 +79,35 @@ async function run() { console.groupEnd(); console.log(); // Empty space - const skipCommitInput = getInput("skip-commit"); - const skipCommit = skipCommitInput === "true"; + // const skipCommitInput = getInput("skip-commit"); + // const skipCommit = + // skipCommitInput === "true" ? true : Boolean(skipCommitInput); + const skipCommit: boolean = Boolean(getInput("skip-commit") === "true"); - const createTagInput = getInput("create-tag"); - const createTag = createTagInput === "false" ? true : Boolean(createTagInput); + // const createTagInput = getInput("create-tag"); + // const createTag = createTagInput === "false" ? true : Boolean(createTagInput); + const createTag: boolean = Boolean(getInput("create-tag") === "true"); - console.log("skipCommit", skipCommit); - console.log("createTag", createTag); - console.log("createTag", createTag); + // const dryRunInput = getInput("dry-run"); + // const dryRun = dryRunInput === "true" ? true : Boolean(dryRunInput); + const dryRun: boolean = Boolean(getInput("dry-run") === "true"); const customPath = getInput("path"); - - const packageJsonPath = customPath ?? "package.json"; + const path = customPath + ? customPath.replace(/\/\*\*/g, "") + "/package.json" + : "package.json"; + + console.group("\nšŸ”§ Inputs:"); + console.log("- skip-commit:", skipCommit); + console.log("- create-tag:", createTag); + console.log("- dry-run:", dryRun); + console.log("- package.json path:", path); + console.groupEnd(); const { data: currentFile } = await octokit.rest.repos.getContent({ owner: context.repo.owner, repo: context.repo.repo, - path: packageJsonPath, + path, ref: pullRequest.head.ref, }); @@ -110,8 +117,6 @@ async function run() { ).toString("utf-8"); const version = JSON.parse(packageJson).version; - console.log(version); - try { // Fetch existing labels from the pull request const { data: pullRequestData } = await octokit.rest.pulls.get({ @@ -121,7 +126,7 @@ async function run() { }); const existingLabels = pullRequestData.labels.map((label) => label.name); - console.group("Existing labels:"); + console.group("\nLabels detected:"); existingLabels.forEach((label) => console.log(`- ${label}`)); console.groupEnd(); console.log(); // Empty space @@ -135,16 +140,14 @@ async function run() { if (isMajor) { console.log("šŸŽ‰ Major label found"); newVersion = Number(version.split(".")[0]) + 1 + ".0.0"; - } - if (isMinor) { + } else if (isMinor) { console.log("šŸš€ Minor label found"); newVersion = version.split(".")[0] + "." + (Number(version.split(".")[1]) + 1) + ".0"; - } - if (isPatch) { + } else if (isPatch) { console.log("šŸ”§ Patch label found"); newVersion = version.split(".")[0] + @@ -157,45 +160,55 @@ async function run() { if (newVersion === version) return console.log("No version change detected"); - console.log(`Expected version update: ${version} -> ${newVersion}`); - setOutput("new-version", newVersion); setOutput("pull-request-number", pullRequest.number); + console.log(`- Expected version bump: ${version} -> ${newVersion}`); + + if (!!dryRun) { + console.log("\nDry run mode enabled. Skipping actual changes."); + return; + } + if (skipCommit) { - console.log("skipping commit"); + console.log(`skip commit: ${skipCommit}`); + console.log(`skipping version bump commit`); console.log(); // Empty space } else { - console.log("packageJsonPath", packageJsonPath); - - const packageJson = JSON.parse( - await fs.promises.readFile(packageJsonPath, "utf-8") - ); + let packageJson; + try { + packageJson = JSON.parse(await fs.promises.readFile(path, "utf-8")); + } catch (error) { + return setFailed(`Failed to read package.json at path: ${path}`); + } + console.log("project found:", packageJson.name); packageJson.version = newVersion; - await fs.promises.writeFile( - packageJsonPath, - JSON.stringify(packageJson, null, 2) - ); + await fs.promises.writeFile(path, JSON.stringify(packageJson, null, 2)); await octokit.rest.repos.createOrUpdateFileContents({ owner: context.repo.owner, repo: context.repo.repo, - path: packageJsonPath, + path, message: `commit version update: ${version} -> ${newVersion}`, content: Buffer.from(JSON.stringify(packageJson, null, 2)).toString( "base64" ), - branch: pullRequest.head.ref, + branch: pullRequest.base.ref, sha: (currentFile as any).sha, // Use the current file's SHA }); } if (createTag) { - const tagName = !!skipCommit ? version : newVersion; - - console.log(`Creating Tag: ${tagName}`); console.log(); // Empty space + const tagPrefix = getInput("tag-prefix"); + const tagName = `${tagPrefix.replace( + "{{version}}", + !skipCommit ? newVersion : version + )}`; + console.log("- tag-name", tagName); + console.log(`\nCreating Tag: ${tagName}`); + // Create a reference to the new tag await octokit.rest.git.createRef({ owner: context.repo.owner,