├── .commitlintrc ├── .editorconfig ├── .eslintrc ├── .github ├── CODEOWNERS ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── card-labeler.yml ├── config.yml ├── labeler.yml ├── no-response.yml ├── pr-labeler.yml ├── pull_request_template.md ├── release-drafter.yml ├── stale.yml ├── workflow-settings.json └── workflows │ ├── add-release-tag.yml │ ├── add-test-tag.yml │ ├── check-warnings.yml │ ├── ci.yml │ ├── issue-opened.yml │ ├── pr-opened.yml │ ├── pr-updated.yml │ ├── project-card-moved.yml │ ├── sync-workflows.yml │ ├── toc.yml │ └── update-dependencies.yml ├── .gitignore ├── .husky ├── .gitignore ├── commit-msg └── pre-commit ├── .lintstagedrc ├── .releasegarc ├── LICENSE ├── README.ja.md ├── README.md ├── _config.yml ├── action.yml ├── package.json ├── rollup.config.mjs ├── src ├── constant.ts ├── fixtures │ ├── package-test1.json │ ├── package-test2.json │ ├── package-test3.json │ ├── repos.git.blobs.json │ ├── repos.git.commits.get.json │ ├── repos.git.commits.json │ ├── repos.git.refs.json │ └── repos.git.trees.json ├── main.ts ├── setup.ts └── utils │ ├── command.test.ts │ ├── command.ts │ ├── misc.test.ts │ ├── misc.ts │ ├── package.test.ts │ └── package.ts ├── tsconfig.json ├── vite.config.ts └── yarn.lock /.commitlintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "@commitlint/config-conventional" 4 | ] 5 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | trim_trailing_whitespace = true 8 | indent_style = space 9 | indent_size = 2 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "eslint:recommended", 4 | "plugin:@typescript-eslint/recommended", 5 | "plugin:@typescript-eslint/eslint-recommended" 6 | ], 7 | "plugins": [ 8 | "@typescript-eslint", 9 | "import" 10 | ], 11 | "parser": "@typescript-eslint/parser", 12 | "parserOptions": { 13 | "sourceType": "module", 14 | "ecmaVersion": 2018 15 | }, 16 | "env": { 17 | "node": true, 18 | "jest": true, 19 | "es6": true, 20 | "browser": true 21 | }, 22 | "settings": { 23 | "react": { 24 | "version": "latest" 25 | } 26 | }, 27 | "rules": { 28 | "camelcase": [ 29 | "error", 30 | { 31 | "properties": "always" 32 | } 33 | ], 34 | "quotes": [ 35 | "error", 36 | "single", 37 | "avoid-escape" 38 | ], 39 | "key-spacing": [ 40 | "error", 41 | { 42 | "singleLine": { 43 | "beforeColon": false, 44 | "afterColon": true 45 | }, 46 | "multiLine": { 47 | "beforeColon": false, 48 | "afterColon": true 49 | } 50 | } 51 | ], 52 | "eqeqeq": "error", 53 | "block-scoped-var": "error", 54 | "complexity": [ 55 | "error", 56 | { 57 | "maximum": 20 58 | } 59 | ], 60 | "default-case": "error", 61 | "dot-location": [ 62 | "error", 63 | "property" 64 | ], 65 | "guard-for-in": "error", 66 | "no-eval": "error", 67 | "block-spacing": "error", 68 | "brace-style": "error", 69 | "comma-spacing": [ 70 | "error", 71 | { 72 | "before": false, 73 | "after": true 74 | } 75 | ], 76 | "indent": [ 77 | "error", 78 | 2, 79 | { 80 | "SwitchCase": 1 81 | } 82 | ], 83 | "space-before-function-paren": [ 84 | "error", 85 | "never" 86 | ], 87 | "space-before-blocks": "error", 88 | "prefer-const": "error", 89 | "no-var": "error", 90 | "arrow-body-style": "off", 91 | "arrow-spacing": "error", 92 | "strict": [ 93 | "error" 94 | ], 95 | "no-warning-comments": [ 96 | "warn", 97 | { 98 | "terms": [ 99 | "todo", 100 | "fixme", 101 | "hack" 102 | ], 103 | "location": "anywhere" 104 | } 105 | ], 106 | "semi": [ 107 | "error" 108 | ], 109 | "sort-imports": 0, 110 | "import/order": [2, { 111 | "groups": ["type", "builtin", "external", "internal", "parent", "sibling", "index", "object"], 112 | "alphabetize": { "order": "asc", "caseInsensitive": true } 113 | }], 114 | "@typescript-eslint/no-non-null-assertion": "off" 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @technote-space 2 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at technote.space@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | [issues]: https://github.com/technote-space/package-version-check-action/issues 3 | [fork]: https://github.com/technote-space/package-version-check-action/fork 4 | [pr]: https://github.com/technote-space/package-version-check-action/compare 5 | [eslint]: https://eslint.org/ 6 | [jest]: https://jestjs.io/ 7 | [code-of-conduct]: CODE_OF_CONDUCT.md 8 | 9 | When contributing to this repository, please first discuss the change you wish to make via [issue][issues] with the owners of this repository before making a change. 10 | 11 | Please note we have a [Contributor Code of Conduct][code-of-conduct], please follow it in all your interactions with the project. 12 | 13 | ## Submitting a pull request 14 | 15 | 1. [Fork][fork] and clone the repository 16 | 1. Make sure the tests pass on your machine: `yarn test`, which contains 17 | - [`ESLint`][eslint] 18 | - [`Jest`][jest] 19 | 1. Create a new branch: `git checkout -b my-branch-name` 20 | 1. Make your change, add tests, and make sure the tests still pass. 21 | 1. Push to your fork and [submit a pull request][pr]. 22 | 1. Pat your self on the back and wait for your pull request to be reviewed and merged. 23 | 24 | Here are a few things you can do that will increase the likelihood of your pull request being accepted: 25 | - Write and update tests. 26 | - Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as separate pull requests. 27 | - Write a [good commit message](https://github.com/erlang/otp/wiki/writing-good-commit-messages). 28 | 29 | Work in Progress pull request are also welcome to get feedback early on, or if there is something blocked you. 30 | 31 | ## Resources 32 | 33 | - [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/) 34 | - [Using Pull Requests](https://help.github.com/articles/about-pull-requests/) 35 | - [GitHub Help](https://help.github.com) 36 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | custom: https://paypal.me/technote0space -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: 'technote-space' 7 | 8 | --- 9 | 10 | ## Describe the bug: バグの概要 11 | 12 | 13 | 14 | ## To Reproduce: 再現手順 15 | Steps to reproduce the behavior: 16 | 1. Go to '...' 17 | 2. Click on '....' 18 | 3. Scroll down to '....' 19 | 4. See error 20 | 21 | ## Expected behavior: 期待する動作 22 | 23 | 24 | 25 | ## Screenshots: スクリーンショット 26 | 27 | 28 | 29 | ## Operating environment: バグが発生した環境 30 | - Version of software 31 | - OS: [e.g. Windows10] 32 | - Browser: [e.g. Chrome, Safari] 33 | - etc. 34 | 35 | ## Additional context: 補足 36 | 37 | 38 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: 'technote-space' 7 | 8 | --- 9 | 10 | ## Please describe your suggestion: 提案の概要 11 | 12 | 13 | 14 | ## Describe the solution you'd like: 考えうる解決方法 15 | 16 | 17 | 18 | ## Describe alternatives you've considered: 考えうる代替案 19 | 20 | 21 | 22 | ## Additional context: 補足 23 | 24 | 25 | -------------------------------------------------------------------------------- /.github/card-labeler.yml: -------------------------------------------------------------------------------- 1 | Backlog: 2 | 'In progress': 3 | - 'Status: In Progress' 4 | -------------------------------------------------------------------------------- /.github/config.yml: -------------------------------------------------------------------------------- 1 | # Configuration for request-info - https://github.com/behaviorbot/request-info 2 | 3 | # *Required* Comment to reply with 4 | requestInfoReplyComment: > 5 | :clap: We would appreciate it if you could provide us with more info about this issue/pr! 6 | 7 | # *OPTIONAL* default titles to check against for lack of descriptiveness 8 | # MUST BE ALL LOWERCASE 9 | requestInfoDefaultTitles: 10 | - update readme.md 11 | - updates 12 | - update 13 | 14 | # *OPTIONAL* Label to be added to Issues and Pull Requests with insufficient information given 15 | requestInfoLabelToAdd: "Status: More Information Needed" 16 | 17 | 18 | 19 | 20 | # Configuration for welcome - https://github.com/behaviorbot/welcome 21 | 22 | # Configuration for new-issue-welcome - https://github.com/behaviorbot/new-issue-welcome 23 | 24 | # Comment to be posted to on first time issues 25 | newIssueWelcomeComment: > 26 | :raised_hands: Thanks for opening your first issue here! Be sure to follow the issue template! 27 | 28 | # Configuration for new-pr-welcome - https://github.com/behaviorbot/new-pr-welcome 29 | 30 | # Comment to be posted to on PRs from first time contributors in your repository 31 | newPRWelcomeComment: > 32 | :raised_hands: Thanks for opening this pull request! Please check out our contributing guidelines. 33 | 34 | # Configuration for first-pr-merge - https://github.com/behaviorbot/first-pr-merge 35 | 36 | # Comment to be posted to on pull requests merged by a first time user 37 | firstPRMergeComment: > 38 | :tada: Congrats on merging your first pull request! We here at behaviorbot are proud of you! 39 | 40 | 41 | 42 | # Configuration for todo - https://github.com/jasonetco/todo 43 | todo: 44 | - label: "Type: Todo" -------------------------------------------------------------------------------- /.github/labeler.yml: -------------------------------------------------------------------------------- 1 | javascript: 2 | - '**/*.js' 3 | typescript: 4 | - '**/*.ts' 5 | php: 6 | - '**/*.php' 7 | python: 8 | - '**/*.py' 9 | cpp: 10 | - '**/*.cpp' 11 | - '**/*.cxx' 12 | - '**/*.cc' 13 | - '**/*.cp' 14 | 15 | 'Type: Testing': 16 | - '**/tests/*' 17 | - '**/test/*' 18 | - '**/__tests__/*' 19 | 20 | 'Type: Documentation': 21 | - '**/*.md' 22 | 23 | 'Type: CI/CD': 24 | - '.github/workflows/*.yml' 25 | - '.circleci/*' 26 | - '.travis.yml' 27 | -------------------------------------------------------------------------------- /.github/no-response.yml: -------------------------------------------------------------------------------- 1 | # Configuration for probot-no-response - https://github.com/probot/no-response 2 | 3 | # Number of days of inactivity before an Issue is closed for lack of response 4 | daysUntilClose: 14 5 | # Label requiring a response 6 | responseRequiredLabel: "Status: More Information Needed" 7 | # Comment to post when closing an Issue for lack of response. Set to `false` to disable 8 | closeComment: > 9 | This issue has been automatically closed because there has been no response 10 | to our request for more information from the original author. With only the 11 | information that is currently in the issue, we don't have enough information 12 | to take action. Please reach out if you have or find the answers we need so 13 | that we can investigate further. 14 | -------------------------------------------------------------------------------- /.github/pr-labeler.yml: -------------------------------------------------------------------------------- 1 | 'Type: Feature': ['feature/*', 'feat/*'] 2 | 'Type: Bug': fix/* 3 | 'Type: Maintenance': ['patch/*', 'chore/*'] 4 | 'Type: Release': release/* 5 | 'Type: Refactoring': ['refactor/*', 'refactoring/*'] 6 | 'Type: Documentation': ['docs/*', 'doc/*'] 7 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Description: 概要 2 | 3 | 4 | 5 | ## Changes: 変更内容 6 | 7 | 8 | 9 | 10 | 11 | 12 | ## Expected Impact: 影響範囲 13 | 14 | 15 | 16 | ## Operating Requirements: 動作要件 17 | 18 | 19 | 20 | ## Additional context: 補足 21 | 22 | 23 | -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | # Config for https://github.com/apps/release-drafter 2 | name-template: 'v$NEXT_PATCH_VERSION' 3 | tag-template: 'v$NEXT_PATCH_VERSION' 4 | categories: 5 | - title: ':rocket: Features' 6 | labels: 7 | - 'Type: Feature' 8 | - 'Type: Refactoring' 9 | - title: ':bug: Bug Fixes' 10 | labels: 11 | - 'Type: Bug' 12 | - 'Type: Security' 13 | - title: ':wrench: Maintenance' 14 | labels: 15 | - 'Type: Maintenance' 16 | - 'Type: CI/CD' 17 | - title: ':green_book: Docs' 18 | labels: 19 | - 'Type: Documentation' 20 | - title: ':white_check_mark: Tested' 21 | labels: 22 | - 'Type: Testing' 23 | - title: ':sparkles: All Changes' 24 | labels: 25 | - 'Type: Release' 26 | exclude-labels: 27 | - 'dependencies' 28 | template: | 29 | ## What’s Changed 30 | 31 | $CHANGES 32 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 180 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 30 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - "Priority: Critical" 8 | - "Type: Security" 9 | # Label to use when marking an issue as stale 10 | staleLabel: "Status: Abandoned" 11 | # Comment to post when marking an issue as stale. Set to `false` to disable 12 | markComment: > 13 | This issue has been automatically marked as stale because it has not had 14 | recent activity. It will be closed if no further activity occurs. Thank you 15 | for your contributions. 16 | # Comment to post when closing a stale issue. Set to `false` to disable 17 | closeComment: false -------------------------------------------------------------------------------- /.github/workflow-settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "EXCLUDE_MESSAGES": [ 3 | "update package version", 4 | "update packages", 5 | "update wp version", 6 | "trigger workflow", 7 | "update TOC" 8 | ], 9 | "PROJECT": "Backlog", 10 | "ISSUE_COLUMN": "To do", 11 | "PR_COLUMN": "In progress", 12 | "PR_BODY_TITLE": "## Changes", 13 | "TOC_FOLDING": "1", 14 | "TOC_MAX_HEADER_LEVEL": "3", 15 | "TOC_TITLE": "Details", 16 | "TOC_CREATE_PR": "true", 17 | "TOC_TARGET_PATHS": "README*.md", 18 | "BRANCH_PREFIX": "release/", 19 | "ANNOTATION_EXCLUDE_PATTERNS": [ 20 | ">> warning ", 21 | ">> hint: ", 22 | "Cloning into", 23 | "has unmet peer dependency", 24 | "has incorrect peer dependency", 25 | "Using version", 26 | "ci-helper", 27 | "tests/bootstrap.php" 28 | ], 29 | "CHANGE_TEMPLATE": "- [ ] ${TITLE} (#${NUMBER}) @${AUTHOR}" 30 | } 31 | -------------------------------------------------------------------------------- /.github/workflows/add-release-tag.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: 3 | branches: 4 | - master 5 | - main 6 | - develop/v* 7 | types: [closed] 8 | 9 | concurrency: 10 | group: ${{ github.workflow }}-${{ github.ref }} 11 | 12 | name: Add release tag 13 | 14 | jobs: 15 | tag: 16 | name: Add release tag 17 | runs-on: ubuntu-latest 18 | timeout-minutes: 3 19 | if: github.event.pull_request.merged == true && github.event.pull_request.head.user.id == github.event.pull_request.base.user.id && startsWith(github.head_ref, 'release/') 20 | steps: 21 | - uses: technote-space/load-config-action@v1 22 | with: 23 | CONFIG_FILENAME: workflow-settings.json, workflow-details.json 24 | IGNORE_WARNING: 'true' 25 | - name: Get version 26 | uses: technote-space/get-next-version-action@v1 27 | with: 28 | EXCLUDE_MESSAGES: ${{ env.EXCLUDE_MESSAGES }} 29 | if: "! startsWith(github.head_ref, 'release/v')" 30 | - name: Get version 31 | run: echo "NEXT_VERSION=${HEAD_REF#release/}" >> $GITHUB_ENV 32 | env: 33 | HEAD_REF: ${{ github.head_ref }} 34 | if: startsWith(github.head_ref, 'release/v') 35 | - uses: actions/github-script@v3 36 | with: 37 | github-token: ${{ secrets.ACCESS_TOKEN }} 38 | script: | 39 | github.git.createRef({ 40 | owner: context.repo.owner, 41 | repo: context.repo.repo, 42 | ref: `refs/tags/${process.env.NEXT_VERSION}`, 43 | sha: context.sha 44 | }) 45 | if: env.NEXT_VERSION 46 | - uses: actions/github-script@v3 47 | with: 48 | github-token: ${{ secrets.ACCESS_TOKEN }} 49 | script: | 50 | github.git.createRef({ 51 | owner: context.repo.owner, 52 | repo: context.repo.repo, 53 | ref: `refs/heads/release/next-${process.env.NEXT_VERSION}`, 54 | sha: context.sha 55 | }) 56 | if: env.NEXT_VERSION 57 | -------------------------------------------------------------------------------- /.github/workflows/add-test-tag.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: 3 | types: [synchronize] 4 | 5 | concurrency: 6 | group: ${{ github.workflow }}-${{ github.ref }} 7 | 8 | name: Add test tag 9 | 10 | jobs: 11 | tag: 12 | name: Add test tag 13 | runs-on: ubuntu-latest 14 | timeout-minutes: 3 15 | if: github.event.pull_request.head.user.id == github.event.pull_request.base.user.id && startsWith(github.head_ref, 'release/') 16 | steps: 17 | - uses: technote-space/load-config-action@v1 18 | with: 19 | CONFIG_FILENAME: workflow-settings.json, workflow-details.json 20 | IGNORE_WARNING: 'true' 21 | - uses: actions/checkout@v3 22 | - uses: technote-space/get-git-comment-action@v1 23 | - name: Get version 24 | uses: technote-space/get-next-version-action@v1 25 | with: 26 | EXCLUDE_MESSAGES: ${{ env.EXCLUDE_MESSAGES }} 27 | if: "! startsWith(github.head_ref, 'release/v') && (contains(env.COMMIT_MESSAGE, 'chore: update dependencies') || contains(env.COMMIT_MESSAGE, 'chore: update npm dependencies'))" 28 | - name: Get version 29 | run: echo "NEXT_VERSION=${HEAD_REF#release/}" >> $GITHUB_ENV 30 | env: 31 | HEAD_REF: ${{ github.head_ref }} 32 | if: "startsWith(github.head_ref, 'release/v') && (contains(env.COMMIT_MESSAGE, 'chore: update dependencies') || contains(env.COMMIT_MESSAGE, 'chore: update npm dependencies'))" 33 | - name: Get tag name 34 | run: echo "TAG_NAME=${NEXT_VERSION}.${RUN_ID}" >> $GITHUB_ENV 35 | env: 36 | HEAD_REF: ${{ github.head_ref }} 37 | RUN_ID: ${{ github.run_id }} 38 | if: env.NEXT_VERSION 39 | - uses: actions/github-script@v3 40 | with: 41 | github-token: ${{ secrets.ACCESS_TOKEN }} 42 | script: | 43 | github.git.createRef({ 44 | owner: context.repo.owner, 45 | repo: context.repo.repo, 46 | ref: `refs/tags/test/${process.env.TAG_NAME}`, 47 | sha: context.payload.pull_request.head.sha 48 | }) 49 | if: env.TAG_NAME 50 | -------------------------------------------------------------------------------- /.github/workflows/check-warnings.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_run: 3 | workflows: 4 | - CI 5 | - Sync workflows 6 | - Update dependencies 7 | - Broken Link Check 8 | types: 9 | - completed 10 | 11 | name: Check Warnings 12 | 13 | jobs: 14 | annotations: 15 | name: Annotations 16 | runs-on: ubuntu-latest 17 | timeout-minutes: 3 18 | steps: 19 | - uses: technote-space/load-config-action@v1 20 | with: 21 | CONFIG_FILENAME: workflow-settings.json, workflow-details.json 22 | IGNORE_WARNING: 'true' 23 | - uses: technote-space/download-annotations-action@v2 24 | id: annotations 25 | with: 26 | TARGET_RUN_ID: ${{ github.event.workflow_run.id }} 27 | INCLUDE_LEVELS: warning 28 | EXCLUDE_MESSAGE_PATTERNS: ${{ env.ANNOTATION_EXCLUDE_PATTERNS }} 29 | - name: Build attachments 30 | run: | 31 | arr1='[{"fields":[{"title":"repo","value":"","short":true},{"title":"action","value":"<${{ github.event.workflow_run.html_url }}|summary>","short":true}]}]' 32 | arr2=$(echo '${{ steps.annotations.outputs.messages }}' | jq -c 'map({"color":"warning","text":"```\(.)```"})') 33 | echo "SLACK_ATTACHMENTS=$(jq --argjson arr1 "$arr1" --argjson arr2 "$arr2" -nc '$arr1 + $arr2')" >> $GITHUB_ENV 34 | if: steps.annotations.outputs.number > 0 35 | - uses: 8398a7/action-slack@v3 36 | with: 37 | status: custom 38 | fields: repo 39 | custom_payload: | 40 | { 41 | text: "Warning annotations", 42 | attachments: ${{ env.SLACK_ATTACHMENTS }} 43 | } 44 | env: 45 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} 46 | if: steps.annotations.outputs.number > 0 && env.SLACK_WEBHOOK_URL 47 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | on: push 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.ref }} 5 | 6 | name: CI 7 | 8 | jobs: 9 | eslint: 10 | name: ESLint 11 | runs-on: ubuntu-latest 12 | timeout-minutes: 5 13 | env: 14 | LINT: 1 15 | steps: 16 | - name: Set running flag 17 | run: echo "RUNNING=1" >> $GITHUB_ENV 18 | - uses: actions/checkout@v3 19 | - uses: technote-space/get-git-comment-action@v1 20 | - uses: technote-space/get-diff-action@v6 21 | with: 22 | PATTERNS: +(src|__tests__)/**/*.+(js|ts) 23 | FILES: | 24 | yarn.lock 25 | .eslintrc 26 | if: "! contains(env.COMMIT_MESSAGE, '[skip ci]') && ! contains(env.COMMIT_MESSAGE, '[ci skip]')" 27 | - name: Set running flag 28 | run: echo "RUNNING=" >> $GITHUB_ENV 29 | if: "! env.GIT_DIFF" 30 | 31 | - uses: actions/setup-node@v3 32 | with: 33 | node-version: 16 34 | cache: yarn 35 | if: env.RUNNING 36 | - name: Install Package dependencies 37 | run: yarn install 38 | if: env.RUNNING 39 | - name: Check code style 40 | run: yarn eslint ${{ env.GIT_DIFF_FILTERED }} 41 | if: env.RUNNING && !env.MATCHED_FILES 42 | - name: Check code style 43 | run: yarn lint 44 | if: env.RUNNING && env.MATCHED_FILES 45 | 46 | cover: 47 | name: Coverage 48 | needs: eslint 49 | runs-on: ${{matrix.os}} 50 | timeout-minutes: 10 51 | strategy: 52 | matrix: 53 | os: [ubuntu-20.04, ubuntu-22.04, ubuntu-latest, macos-latest] 54 | steps: 55 | - name: Set running flag 56 | run: echo "RUNNING=1" >> $GITHUB_ENV 57 | - uses: actions/checkout@v3 58 | - uses: technote-space/get-git-comment-action@v1 59 | - uses: technote-space/get-diff-action@v6 60 | with: 61 | PATTERNS: +(src|__tests__)/**/*.+(js|ts|snap) 62 | FILES: | 63 | yarn.lock 64 | jest.config.js 65 | vite.config.ts 66 | if: "! contains(env.COMMIT_MESSAGE, '[skip ci]') && ! contains(env.COMMIT_MESSAGE, '[ci skip]')" 67 | - name: Set running flag 68 | run: echo "RUNNING=" >> $GITHUB_ENV 69 | if: "! env.GIT_DIFF" 70 | - name: Set running flag 71 | if: "matrix.os == 'ubuntu-latest' && ! startsWith(github.ref, 'refs/tags/') && github.event.base_ref == format('refs/heads/{0}', github.event.repository.default_branch)" 72 | run: echo "RUNNING=1" >> $GITHUB_ENV 73 | - name: Set running flag 74 | if: "matrix.os == 'ubuntu-latest' && ! startsWith(github.ref, 'refs/tags/') && startsWith(github.base_ref, 'refs/heads/develop/v')" 75 | run: echo "RUNNING=1" >> $GITHUB_ENV 76 | - name: Set running flag 77 | if: matrix.os == 'ubuntu-latest' && startsWith(github.ref, 'refs/tags/v') 78 | run: echo "RUNNING=1" >> $GITHUB_ENV 79 | - name: Set running flag 80 | run: | 81 | if [[ ! -f package.json ]] || ! < package.json jq -r '.scripts | keys[]' | grep -qe '^cover$'; then 82 | echo "RUNNING=" >> $GITHUB_ENV 83 | fi 84 | 85 | - uses: actions/setup-node@v3 86 | with: 87 | node-version: 16 88 | cache: yarn 89 | if: env.RUNNING 90 | - name: Install Package dependencies 91 | run: yarn install 92 | if: env.RUNNING 93 | - name: Run tests 94 | run: yarn cover 95 | if: env.RUNNING 96 | - name: Codecov 97 | run: | 98 | if [ -n "$CODECOV_TOKEN" ]; then 99 | curl -s https://codecov.io/bash | bash -s -- -t $CODECOV_TOKEN -f $COVERAGE_FILE 100 | fi 101 | env: 102 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 103 | COVERAGE_FILE: ./coverage/lcov.info 104 | if: env.RUNNING && matrix.os == 'ubuntu-latest' 105 | 106 | release: 107 | name: Release GitHub Actions 108 | needs: cover 109 | runs-on: ubuntu-latest 110 | timeout-minutes: 5 111 | if: startsWith(github.ref, 'refs/tags/') 112 | steps: 113 | - uses: actions/checkout@v3 114 | - uses: actions/setup-node@v3 115 | with: 116 | node-version: 16 117 | cache: yarn 118 | 119 | - uses: technote-space/load-config-action@v1 120 | with: 121 | CONFIG_FILENAME: workflow-settings.json, workflow-details.json 122 | IGNORE_WARNING: 'true' 123 | - name: Release GitHub Actions 124 | uses: technote-space/release-github-actions@v8 125 | with: 126 | OUTPUT_BUILD_INFO_FILENAME: build.json 127 | TEST_TAG_PREFIX: test/ 128 | ORIGINAL_TAG_PREFIX: original/ 129 | CLEAN_TEST_TAG: true 130 | DELETE_NODE_MODULES: ${{ env.RELEASE_GA_DELETE_NODE_MODULES }} 131 | 132 | package: 133 | name: Publish Package 134 | needs: cover 135 | runs-on: ubuntu-latest 136 | timeout-minutes: 5 137 | if: startsWith(github.ref, 'refs/tags/v') 138 | strategy: 139 | matrix: 140 | target: ['npm', 'gpr'] 141 | steps: 142 | - name: Set running flag 143 | run: echo "RUNNING=1" >> $GITHUB_ENV 144 | - name: Set running flag 145 | run: | 146 | if [ -z "$NPM_AUTH_TOKEN" ]; then 147 | echo "RUNNING=" >> $GITHUB_ENV 148 | fi 149 | env: 150 | NPM_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} 151 | - uses: actions/checkout@v3 152 | if: env.RUNNING 153 | - name: Check package version 154 | uses: technote-space/package-version-check-action@gh-actions 155 | with: 156 | COMMIT_DISABLED: 1 157 | if: env.RUNNING 158 | - name: Set running flag 159 | run: npx can-npm-publish || echo "RUNNING=" >> $GITHUB_ENV 160 | if: env.RUNNING && matrix.target == 'npm' 161 | - name: Set running flag 162 | run: | 163 | LATEST=`npm view . version` 2> /dev/null || : 164 | CURRENT=`cat package.json | jq -r .version` 165 | if [ "$LATEST" = "$CURRENT" ]; then 166 | echo "RUNNING=" >> $GITHUB_ENV 167 | fi 168 | env: 169 | NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 170 | if: env.RUNNING && matrix.target == 'gpr' 171 | 172 | - name: Setup Node.js 173 | uses: actions/setup-node@v3 174 | with: 175 | node-version: 16 176 | registry-url: https://registry.npmjs.org/ 177 | cache: yarn 178 | if: env.RUNNING && matrix.target == 'npm' 179 | - name: Setup Node.js 180 | uses: actions/setup-node@v3 181 | with: 182 | node-version: 16 183 | registry-url: https://npm.pkg.github.com 184 | cache: yarn 185 | if: env.RUNNING && matrix.target == 'gpr' 186 | - name: Install Package dependencies 187 | run: yarn install 188 | if: env.RUNNING 189 | - name: Build 190 | run: yarn build 191 | if: env.RUNNING 192 | - name: Publish 193 | run: | 194 | npm config set //registry.npmjs.org/:_authToken=$NPM_AUTH_TOKEN 195 | npm publish 196 | env: 197 | NPM_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} 198 | if: env.RUNNING && matrix.target == 'npm' 199 | - name: Publish 200 | run: | 201 | npm publish 202 | env: 203 | NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 204 | if: env.RUNNING && matrix.target == 'gpr' 205 | 206 | publishRelease: 207 | name: Create Release 208 | needs: [release, package] 209 | runs-on: ubuntu-latest 210 | timeout-minutes: 5 211 | steps: 212 | - name: Get version 213 | run: echo "TAG_NAME=${HEAD_REF#refs/tags/}" >> $GITHUB_ENV 214 | env: 215 | HEAD_REF: ${{ github.ref }} 216 | - name: Create Release 217 | id: drafter 218 | uses: technote-space/release-drafter@v6 219 | with: 220 | GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} 221 | DRAFT: false 222 | NAME: ${{ env.TAG_NAME }} 223 | TAG: ${{ env.TAG_NAME }} 224 | - uses: 8398a7/action-slack@v3 225 | with: 226 | status: ${{ job.status }} 227 | text: ${{ format('<{0}>', steps.drafter.outputs.html_url) }} 228 | env: 229 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} 230 | if: success() && env.SLACK_WEBHOOK_URL 231 | 232 | slack: 233 | name: Slack 234 | needs: publishRelease 235 | runs-on: ubuntu-latest 236 | timeout-minutes: 3 237 | if: always() 238 | steps: 239 | - uses: technote-space/workflow-conclusion-action@v3 240 | - uses: 8398a7/action-slack@v3 241 | with: 242 | status: failure 243 | env: 244 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} 245 | if: env.WORKFLOW_CONCLUSION == 'failure' && env.SLACK_WEBHOOK_URL 246 | -------------------------------------------------------------------------------- /.github/workflows/issue-opened.yml: -------------------------------------------------------------------------------- 1 | on: 2 | issues: 3 | types: [opened] 4 | 5 | name: Issue opened 6 | 7 | jobs: 8 | assign: 9 | name: Assign issues to project 10 | runs-on: ubuntu-latest 11 | timeout-minutes: 3 12 | steps: 13 | - uses: technote-space/load-config-action@v1 14 | with: 15 | CONFIG_FILENAME: workflow-settings.json, workflow-details.json 16 | IGNORE_WARNING: 'true' 17 | - uses: technote-space/create-project-card-action@v1 18 | with: 19 | PROJECT: ${{ env.PROJECT }} 20 | COLUMN: ${{ env.ISSUE_COLUMN }} 21 | 22 | assignAuthor: 23 | name: Assign author to issue 24 | runs-on: ubuntu-latest 25 | timeout-minutes: 3 26 | steps: 27 | - uses: technote-space/assign-author@v1 28 | -------------------------------------------------------------------------------- /.github/workflows/pr-opened.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request_target: 3 | types: [opened] 4 | 5 | name: Pull Request opened 6 | 7 | jobs: 8 | assignToProject: 9 | name: Assign PullRequest to Project 10 | runs-on: ubuntu-latest 11 | timeout-minutes: 3 12 | steps: 13 | - uses: technote-space/load-config-action@v1 14 | with: 15 | CONFIG_FILENAME: workflow-settings.json, workflow-details.json 16 | IGNORE_WARNING: 'true' 17 | - uses: technote-space/create-project-card-action@v1 18 | with: 19 | PROJECT: ${{ env.PROJECT }} 20 | COLUMN: ${{ env.PR_COLUMN }} 21 | GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} 22 | 23 | assignAuthor: 24 | name: Assign author to PR 25 | runs-on: ubuntu-latest 26 | timeout-minutes: 3 27 | steps: 28 | - uses: technote-space/assign-author@v1 29 | 30 | addLabelsByBranch: 31 | name: PR Labeler 32 | runs-on: ubuntu-latest 33 | timeout-minutes: 3 34 | steps: 35 | - uses: technote-space/pr-labeler-action@v4 36 | -------------------------------------------------------------------------------- /.github/workflows/pr-updated.yml: -------------------------------------------------------------------------------- 1 | on: pull_request_target 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.ref }} 5 | 6 | name: Pull Request updated 7 | 8 | jobs: 9 | triage: 10 | name: Pull Request Labeler 11 | runs-on: ubuntu-latest 12 | timeout-minutes: 3 13 | if: "! startsWith(github.head_ref, 'release/')" 14 | steps: 15 | - uses: actions/labeler@v2 16 | with: 17 | repo-token: ${{ secrets.GITHUB_TOKEN }} 18 | 19 | history: 20 | name: Pull Request Body 21 | runs-on: ubuntu-latest 22 | timeout-minutes: 3 23 | if: github.event.pull_request.head.user.id == github.event.pull_request.base.user.id 24 | steps: 25 | - uses: technote-space/load-config-action@v1 26 | with: 27 | CONFIG_FILENAME: workflow-settings.json, workflow-details.json 28 | IGNORE_WARNING: 'true' 29 | - uses: technote-space/pr-commit-body-action@v1 30 | with: 31 | EXCLUDE_MESSAGES: ${{ env.EXCLUDE_MESSAGES }} 32 | TITLE: ${{ env.PR_BODY_TITLE }} 33 | LINK_ISSUE_KEYWORD: ${{ (startsWith(github.head_ref, 'release/') && 'closes') || '' }} 34 | FILTER_PR: true 35 | CHANGE_TEMPLATE: ${{ env.CHANGE_TEMPLATE }} 36 | 37 | manageRelease: 38 | name: Manage release 39 | runs-on: ubuntu-latest 40 | timeout-minutes: 3 41 | if: "github.event.pull_request.head.user.id == github.event.pull_request.base.user.id && startsWith(github.head_ref, 'release/') && ! startsWith(github.head_ref, 'release/v')" 42 | steps: 43 | - uses: technote-space/load-config-action@v1 44 | with: 45 | CONFIG_FILENAME: workflow-settings.json, workflow-details.json 46 | IGNORE_WARNING: 'true' 47 | - uses: technote-space/release-type-action@v1 48 | with: 49 | EXCLUDE_MESSAGES: ${{ env.EXCLUDE_MESSAGES }} 50 | GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} 51 | 52 | checkVersion: 53 | name: Check package version 54 | runs-on: ubuntu-latest 55 | timeout-minutes: 3 56 | if: "github.event.action == 'synchronize' && github.event.pull_request.head.user.id == github.event.pull_request.base.user.id && startsWith(github.head_ref, 'release/')" 57 | steps: 58 | - uses: technote-space/load-config-action@v1 59 | with: 60 | CONFIG_FILENAME: workflow-settings.json, workflow-details.json 61 | IGNORE_WARNING: 'true' 62 | - name: Set running flag 63 | run: echo "RUNNING=1" >> $GITHUB_ENV 64 | - uses: actions/checkout@v3 65 | with: 66 | ref: ${{ github.head_ref }} 67 | - name: Set running flag 68 | run: | 69 | if [[ ! -f package.json ]] || [[ $(< package.json jq -r '.version == null') == 'true' ]]; then 70 | echo "RUNNING=" >> $GITHUB_ENV 71 | fi 72 | 73 | - name: Sort 74 | run: npx sort-package-json 75 | if: env.RUNNING 76 | - name: Get version 77 | uses: technote-space/get-next-version-action@v1 78 | with: 79 | EXCLUDE_MESSAGES: ${{ env.EXCLUDE_MESSAGES }} 80 | if: "env.RUNNING && ! startsWith(github.head_ref, 'release/v')" 81 | - name: Get version 82 | run: echo "NEXT_VERSION=${HEAD_REF#release/}" >> $GITHUB_ENV 83 | env: 84 | HEAD_REF: ${{ github.head_ref }} 85 | if: env.RUNNING && startsWith(github.head_ref, 'release/v') 86 | - name: Check package version 87 | uses: technote-space/package-version-check-action@gh-actions 88 | with: 89 | GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} 90 | BRANCH_PREFIX: release/ 91 | NEXT_VERSION: ${{ env.NEXT_VERSION }} 92 | if: env.NEXT_VERSION 93 | 94 | checkPublish: 95 | name: Check publish 96 | runs-on: ubuntu-latest 97 | timeout-minutes: 3 98 | if: "github.event.pull_request.head.user.id == github.event.pull_request.base.user.id && startsWith(github.head_ref, 'release/')" 99 | steps: 100 | - name: Set running flag 101 | run: echo "RUNNING=1" >> $GITHUB_ENV 102 | - name: Set running flag 103 | run: | 104 | if [ -z "$NPM_AUTH_TOKEN" ]; then 105 | echo "RUNNING=" >> $GITHUB_ENV 106 | fi 107 | env: 108 | NPM_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} 109 | 110 | - uses: actions/checkout@v3 111 | with: 112 | ref: ${{ github.head_ref }} 113 | if: env.RUNNING 114 | - uses: technote-space/can-npm-publish-action@v1 115 | if: env.RUNNING 116 | -------------------------------------------------------------------------------- /.github/workflows/project-card-moved.yml: -------------------------------------------------------------------------------- 1 | on: 2 | project_card: 3 | types: [created, moved] 4 | 5 | name: Project Card Event 6 | 7 | jobs: 8 | triage: 9 | name: Auto card labeler 10 | runs-on: ubuntu-latest 11 | timeout-minutes: 3 12 | steps: 13 | - uses: technote-space/auto-card-labeler@v1 14 | -------------------------------------------------------------------------------- /.github/workflows/sync-workflows.yml: -------------------------------------------------------------------------------- 1 | on: 2 | schedule: 3 | - cron: 0 11 * * 4 4 | repository_dispatch: 5 | types: [sync-workflows] 6 | workflow_dispatch: 7 | 8 | name: Sync workflows 9 | jobs: 10 | release: 11 | name: Sync workflows 12 | runs-on: ubuntu-latest 13 | timeout-minutes: 5 14 | steps: 15 | - name: Sync workflows 16 | uses: technote-space/create-pr-action@v2 17 | with: 18 | GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} 19 | EXECUTE_COMMANDS: | 20 | rm -rdf .github/workflows/.tmp 21 | mkdir -p .github/workflows/.tmp 22 | git clone --depth=1 https://github.com/technote-space/github-actions-workflows.git .github/workflows/.tmp/workflows 23 | 24 | bash .github/workflows/.tmp/workflows/gh-actions/copy.sh 25 | sed -i 's/cron:.\+$/cron: 0 3 * * 2,6/' .github/workflows/update-dependencies.yml 26 | 27 | rm -rdf .github/workflows/.tmp 28 | COMMIT_MESSAGE: 'chore: sync workflows' 29 | PR_BRANCH_PREFIX: chore/ 30 | PR_BRANCH_NAME: 'chore-sync-workflows' 31 | PR_TITLE: 'chore: sync workflows' 32 | ONLY_DEFAULT_BRANCH: true 33 | -------------------------------------------------------------------------------- /.github/workflows/toc.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: 3 | types: [opened, synchronize, reopened, closed] 4 | 5 | concurrency: 6 | group: ${{ github.workflow }}-${{ github.ref }} 7 | 8 | name: TOC Generator 9 | 10 | jobs: 11 | toc: 12 | if: github.event.pull_request.head.user.id == github.event.pull_request.base.user.id 13 | name: TOC Generator 14 | runs-on: ubuntu-latest 15 | timeout-minutes: 3 16 | steps: 17 | - uses: technote-space/load-config-action@v1 18 | with: 19 | CONFIG_FILENAME: workflow-settings.json, workflow-details.json 20 | IGNORE_WARNING: 'true' 21 | - uses: technote-space/toc-generator@v4 22 | with: 23 | GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} 24 | TARGET_BRANCH_PREFIX: ${{ env.BRANCH_PREFIX }} 25 | FOLDING: ${{ env.TOC_FOLDING }} 26 | MAX_HEADER_LEVEL: ${{ env.TOC_MAX_HEADER_LEVEL }} 27 | TOC_TITLE: ${{ env.TOC_TITLE }} 28 | CREATE_PR: ${{ env.TOC_CREATE_PR }} 29 | TARGET_PATHS: ${{ env.TOC_TARGET_PATHS }} 30 | FOOTER: ${{ env.TOC_FOOTER }} 31 | -------------------------------------------------------------------------------- /.github/workflows/update-dependencies.yml: -------------------------------------------------------------------------------- 1 | on: 2 | schedule: 3 | - cron: 0 3 * * 2,6 4 | pull_request: 5 | types: [opened, reopened, closed] 6 | repository_dispatch: 7 | types: [update-deps] 8 | workflow_dispatch: 9 | 10 | concurrency: 11 | group: ${{ github.workflow }}-${{ github.ref }} 12 | 13 | name: Update dependencies 14 | jobs: 15 | update: 16 | name: Update npm dependencies 17 | runs-on: ubuntu-latest 18 | timeout-minutes: 10 19 | if: "! startsWith(github.head_ref, 'release/v')" 20 | steps: 21 | - name: Set running flag 22 | run: echo "RUNNING1=" >> $GITHUB_ENV 23 | - name: Set running flag 24 | run: echo "RUNNING1=1" >> $GITHUB_ENV 25 | if: github.event.pull_request.head.user.id == github.event.pull_request.base.user.id 26 | - uses: technote-space/load-config-action@v1 27 | if: env.RUNNING1 28 | with: 29 | CONFIG_FILENAME: workflow-settings.json, workflow-details.json 30 | IGNORE_WARNING: 'true' 31 | - name: Update dependencies 32 | if: env.RUNNING1 33 | id: update_deps 34 | uses: technote-space/create-pr-action@v2 35 | with: 36 | GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} 37 | EXECUTE_COMMANDS: | 38 | npx npm-check-updates -u --packageFile package.json 39 | yarn install 40 | yarn upgrade 41 | yarn audit 42 | COMMIT_MESSAGE: 'chore: update npm dependencies' 43 | PR_DEFAULT_BRANCH_PREFIX: release/ 44 | PR_DEFAULT_BRANCH_NAME: next-${CURRENT_VERSION} 45 | PR_DEFAULT_BRANCH_TITLE: 'feat: release' 46 | TARGET_BRANCH_PREFIX: release/ 47 | AUTO_MERGE_THRESHOLD_DAYS: 14 48 | 49 | - name: Set running flag 50 | run: echo "RUNNING2=" >> $GITHUB_ENV 51 | - name: Set running flag 52 | run: echo "RUNNING2=1" >> $GITHUB_ENV 53 | if: env.RUNNING1 && steps.update_deps.outputs.result != 'succeeded' && github.event_name == 'pull_request' && github.event.action != 'closed' && startsWith(github.head_ref, 'release/') 54 | - uses: actions/checkout@v3 55 | if: env.RUNNING2 56 | - name: Set running flag 57 | run: | 58 | if [[ ! -f package.json ]] || [[ $(< package.json jq -r '.version == null') == 'true' ]]; then 59 | echo "RUNNING2=" >> $GITHUB_ENV 60 | fi 61 | - name: Sort 62 | run: npx sort-package-json 63 | if: env.RUNNING2 64 | - name: Get version 65 | uses: technote-space/get-next-version-action@v1 66 | with: 67 | EXCLUDE_MESSAGES: ${{ env.EXCLUDE_MESSAGES }} 68 | if: "env.RUNNING2 && ! startsWith(github.head_ref, 'release/v')" 69 | - name: Get version 70 | run: echo "NEXT_VERSION=${HEAD_REF#release/}" >> $GITHUB_ENV 71 | env: 72 | HEAD_REF: ${{ github.head_ref }} 73 | if: env.RUNNING2 && startsWith(github.head_ref, 'release/v') 74 | - name: Check package version 75 | uses: technote-space/package-version-check-action@gh-actions 76 | with: 77 | GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} 78 | BRANCH_PREFIX: release/ 79 | NEXT_VERSION: ${{ env.NEXT_VERSION }} 80 | if: env.NEXT_VERSION 81 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /.vscode 3 | /node_modules 4 | /coverage 5 | /lib 6 | /.work 7 | .eslintcache 8 | .env 9 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | yarn commitlint -- --edit $1 5 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | yarn lint-staged 5 | -------------------------------------------------------------------------------- /.lintstagedrc: -------------------------------------------------------------------------------- 1 | { 2 | "*.{js,jsx,ts,tsx}": "yarn lint:fix" 3 | } -------------------------------------------------------------------------------- /.releasegarc: -------------------------------------------------------------------------------- 1 | { 2 | "inputs": { 3 | "OUTPUT_BUILD_INFO_FILENAME": "build.json", 4 | "TEST_TAG_PREFIX": "test/", 5 | "CLEAN_TEST_TAG": "true" 6 | } 7 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 Technote 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.ja.md: -------------------------------------------------------------------------------- 1 | # Package Version Check Action 2 | 3 | [![CI Status](https://github.com/technote-space/package-version-check-action/workflows/CI/badge.svg)](https://github.com/technote-space/package-version-check-action/actions) 4 | [![codecov](https://codecov.io/gh/technote-space/package-version-check-action/branch/master/graph/badge.svg)](https://codecov.io/gh/technote-space/package-version-check-action) 5 | [![CodeFactor](https://www.codefactor.io/repository/github/technote-space/package-version-check-action/badge)](https://www.codefactor.io/repository/github/technote-space/package-version-check-action) 6 | [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/technote-space/package-version-check-action/blob/master/LICENSE) 7 | 8 | *Read this in other languages: [English](README.md), [日本語](README.ja.md).* 9 | 10 | npmパッケージ公開前にパッケージのバージョンをチェックする`GitHub Actions`です。 11 | 12 | ## Table of Contents 13 | 14 | 15 | 16 |
17 | Details 18 | 19 | - [スクリーンショット](#%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88) 20 | - [使用方法](#%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95) 21 | - [プッシュ時に使用](#%E3%83%97%E3%83%83%E3%82%B7%E3%83%A5%E6%99%82%E3%81%AB%E4%BD%BF%E7%94%A8) 22 | - [リリースプロセスで使用](#%E3%83%AA%E3%83%AA%E3%83%BC%E3%82%B9%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9%E3%81%A7%E4%BD%BF%E7%94%A8) 23 | - [オプション](#%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3) 24 | - [BRANCH_PREFIX](#branch_prefix) 25 | - [COMMIT_DISABLED](#commit_disabled) 26 | - [COMMIT_MESSAGE](#commit_message) 27 | - [PACKAGE_NAME](#package_name) 28 | - [PACKAGE_DIR](#package_dir) 29 | - [TEST_TAG_PREFIX](#test_tag_prefix) 30 | - [NEXT_VERSION](#next_version) 31 | - [Action イベント詳細](#action-%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E8%A9%B3%E7%B4%B0) 32 | - [対象イベント](#%E5%AF%BE%E8%B1%A1%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88) 33 | - [Conditions](#conditions) 34 | - [動機](#%E5%8B%95%E6%A9%9F) 35 | - [補足](#%E8%A3%9C%E8%B6%B3) 36 | - [コミット](#%E3%82%B3%E3%83%9F%E3%83%83%E3%83%88) 37 | - [Tags](#tags) 38 | - [このアクションを使用しているリポジトリの例](#%E3%81%93%E3%81%AE%E3%82%A2%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA%E3%81%AE%E4%BE%8B) 39 | - [Author](#author) 40 | 41 |
42 | 43 | 44 | ## スクリーンショット 45 | 1. `GitHub Action` 実行中 46 | 47 | ![Running](https://raw.githubusercontent.com/technote-space/package-version-check-action/images/screenshot-1.png) 48 | 49 | 1. package.json のバージョンを更新 (ブランチが保護されていない場合) 50 | 51 | ![Updated](https://raw.githubusercontent.com/technote-space/package-version-check-action/images/screenshot-2.png) 52 | 53 | ## 使用方法 54 | ### プッシュ時に使用 55 | 例:`.github/workflows/check_version.yml` 56 | ```yaml 57 | on: push 58 | name: Check package version 59 | jobs: 60 | checkVersion: 61 | name: Check package version 62 | runs-on: ubuntu-latest 63 | steps: 64 | - uses: actions/checkout@v2 65 | 66 | # Use this GitHub Action 67 | - name: Check package version 68 | uses: technote-space/package-version-check-action@v1 69 | with: 70 | BRANCH_PREFIX: release/ 71 | ``` 72 | 73 | ### リリースプロセスで使用 74 | 例:`.github/workflows/release.yml` 75 | ```yaml 76 | on: 77 | push: 78 | tags: 79 | - 'v*' 80 | name: Publish Package 81 | jobs: 82 | release: 83 | name: Publish Package 84 | runs-on: ubuntu-latest 85 | steps: 86 | - name: Checkout 87 | uses: actions/checkout@v2 88 | 89 | # Use this GitHub Action 90 | - name: Check package version 91 | uses: technote-space/package-version-check-action@v1 92 | with: 93 | COMMIT_DISABLED: 1 94 | 95 | - name: Install Package dependencies 96 | run: yarn install 97 | - name: Build 98 | run: yarn build 99 | - name: Publish 100 | run: | 101 | npm config set //registry.npmjs.org/:_authToken=$NPM_AUTH_TOKEN 102 | npm publish 103 | env: 104 | NPM_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} 105 | ``` 106 | [対象イベントの詳細](#action-%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E8%A9%B3%E7%B4%B0) 107 | 108 | ## オプション 109 | ### BRANCH_PREFIX 110 | ブランチプリフィックス 111 | default: `''` 112 | 例:`release/` 113 | 114 | ### COMMIT_DISABLED 115 | コミットが無効かどうか 116 | default: `''` 117 | 118 | ### COMMIT_MESSAGE 119 | パッケージバージョン更新用コミットのメッセージ 120 | default: `'feat: update package version'` 121 | 122 | ### PACKAGE_NAME 123 | パッケージファイル名 124 | default: `'package.json'` 125 | 126 | ### PACKAGE_DIR 127 | パッケージファイルが置かれたディレクトリ 128 | default: `''` 129 | 130 | ### TEST_TAG_PREFIX 131 | テスト用タグのプリフィックス 132 | default: `''` 133 | 例:`'test/'` 134 | 135 | ### NEXT_VERSION 136 | 次のバージョンを指定 137 | default: `''` 138 | e.g. `'v1.2.3'` 139 | 140 | ## Action イベント詳細 141 | ### 対象イベント 142 | | eventName: action | condition | 143 | |:---:|:---:| 144 | |push: *|[condition1](#condition1)| 145 | |release: published|[condition1](#condition1)| 146 | |pull_request, pull_request_target: opened, reopened, synchronize|[condition2](#condition2)| 147 | |created: *|[condition3](#condition3)| 148 | 149 | ### Conditions 150 | #### condition1 151 | - tags 152 | - semantic versioning tag (例:`v1.2.3`) 153 | - branches 154 | - `${BRANCH_PREFIX}${tag}` 155 | - tag: semantic versioning tag (例:`v1.2.3`) 156 | - 例:branch: `release/v1.2.3` 157 | #### condition2 158 | - branches 159 | - `${BRANCH_PREFIX}${tag}` 160 | - tag: semantic versioning tag (例:`v1.2.3`) 161 | - 例:branch: `release/v1.2.3` 162 | #### condition3 163 | - tags 164 | - semantic versioning tag (例:`v1.2.3`) 165 | 166 | ## 動機 167 | package.jsonバージョンの更新を忘れると、npmパッケージの公開は失敗します。 168 | 169 | ![Failed](https://raw.githubusercontent.com/technote-space/package-version-check-action/images/screenshot-4.png) 170 | 171 | タグのプッシュでアクションを起動していた場合、 172 | 173 | 1. プッシュしたタグを削除 174 | 1. package.json のバージョンを更新 175 | 1. コミットして再度タグを付与 176 | 1. プッシュ 177 | 178 | を再度行う必要があり、非常に面倒です。 179 | 180 | この `GitHub Action` は、タグ名に基づいてpackage.jsonのバージョンを自動的に更新します。 181 | したがって、package.json のバージョンについて心配する必要はありません。 182 | 183 | また、ブランチが保護されていない場合、このアクションは変更をコミットします。 184 | ブランチが保護されている場合、このアクションは package.json のバージョンを更新するだけです。 185 | 186 | ## 補足 187 | ### コミット 188 | コミットは『タグ付きのデフォルトブランチ(通常はmaster)』または『`${BRANCH_PREFIX}`から始まるブランチ』へのプッシュ時のみ有効です。 189 | 190 | GitHub Actions で提供される`GITHUB_TOKEN`は連続するイベントを作成する権限がありません。 191 | したがって、プッシュによってトリガーされるビルドアクションなどは実行されません。 192 | 193 | ![GITHUB_TOKEN](https://raw.githubusercontent.com/technote-space/package-version-check-action/images/no_access_token.png) 194 | 195 | これはブランチプロテクションを設定していると問題になる場合があります。 196 | 197 | もしアクションをトリガーしたい場合は代わりに`personal access token`を使用してください。 198 | 1. public_repo または repo の権限で [Personal access token](https://docs.github.com/ja/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) を生成 199 | (repo はプライベートリポジトリで必要です) 200 | 1. [ACCESS_TOKENとして保存](https://docs.github.com/ja/actions/security-guides/encrypted-secrets) 201 | 1. `GITHUB_TOKEN`の代わりに`ACCESS_TOKEN`を使用するように設定 202 | 例:`.github/workflows/check_version.yml` 203 | ```yaml 204 | on: push 205 | name: Check package version 206 | jobs: 207 | checkVersion: 208 | name: Check package version 209 | runs-on: ubuntu-latest 210 | steps: 211 | - uses: actions/checkout@v2 212 | 213 | # Use this GitHub Action 214 | - name: Check package version 215 | uses: technote-space/package-version-check-action@v1 216 | with: 217 | GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} 218 | BRANCH_PREFIX: release/ 219 | ``` 220 | 221 | ![ACCESS_TOKEN](https://raw.githubusercontent.com/technote-space/package-version-check-action/images/with_access_token.png) 222 | 223 | ### Tags 224 | タグ名は [Semantic Versioning](https://semver.org/) に従っている必要があります。 225 | 226 | ## このアクションを使用しているリポジトリの例 227 | - [GitHub Action Helper](https://github.com/technote-space/github-action-helper) 228 | - [pr-updated.yml](https://github.com/technote-space/github-action-helper/blob/master/.github/workflows/pr-updated.yml) 229 | - [ci.yml](https://github.com/technote-space/github-action-helper/blob/master/.github/workflows/ci.yml) 230 | - [GitHub Action Config Helper](https://github.com/technote-space/github-action-config-helper) 231 | - [pr-updated.yml](https://github.com/technote-space/github-action-config-helper/blob/master/.github/workflows/pr-updated.yml) 232 | - [ci.yml](https://github.com/technote-space/github-action-config-helper/blob/master/.github/workflows/ci.yml) 233 | - [GitHub Action Test Helper](https://github.com/technote-space/github-action-test-helper) 234 | - [pr-updated.yml](https://github.com/technote-space/github-action-test-helper/blob/master/.github/workflows/pr-updated.yml) 235 | - [ci.yml](https://github.com/technote-space/github-action-test-helper/blob/master/.github/workflows/ci.yml) 236 | - [Filter GitHub Action](https://github.com/technote-space/filter-github-action) 237 | - [pr-updated.yml](https://github.com/technote-space/filter-github-action/blob/master/.github/workflows/pr-updated.yml) 238 | - [ci.yml](https://github.com/technote-space/filter-github-action/blob/master/.github/workflows/ci.yml) 239 | - [jQuery Marker Animation](https://github.com/technote-space/jquery.marker-animation) 240 | - [pr-updated.yml](https://github.com/technote-space/jquery.marker-animation/blob/master/.github/workflows/pr-updated.yml) 241 | - [ci.yml](https://github.com/technote-space/jquery.marker-animation/blob/master/.github/workflows/ci.yml) 242 | - [Gutenberg Utils](https://github.com/technote-space/gutenberg-utils) 243 | - [pr-updated.yml](https://github.com/technote-space/gutenberg-utils/blob/master/.github/workflows/pr-updated.yml) 244 | - [ci.yml](https://github.com/technote-space/gutenberg-utils/blob/master/.github/workflows/ci.yml) 245 | - [Register Grouped Format Type](https://github.com/technote-space/register-grouped-format-type) 246 | - [pr-updated.yml](https://github.com/technote-space/register-grouped-format-type/blob/master/.github/workflows/pr-updated.yml) 247 | - [ci.yml](https://github.com/technote-space/register-grouped-format-type/blob/master/.github/workflows/ci.yml) 248 | 249 | ## Author 250 | [GitHub (Technote)](https://github.com/technote-space) 251 | [Blog](https://technote.space) 252 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Package Version Check Action 2 | 3 | [![CI Status](https://github.com/technote-space/package-version-check-action/workflows/CI/badge.svg)](https://github.com/technote-space/package-version-check-action/actions) 4 | [![codecov](https://codecov.io/gh/technote-space/package-version-check-action/branch/master/graph/badge.svg)](https://codecov.io/gh/technote-space/package-version-check-action) 5 | [![CodeFactor](https://www.codefactor.io/repository/github/technote-space/package-version-check-action/badge)](https://www.codefactor.io/repository/github/technote-space/package-version-check-action) 6 | [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/technote-space/package-version-check-action/blob/master/LICENSE) 7 | 8 | *Read this in other languages: [English](README.md), [日本語](README.ja.md).* 9 | 10 | This is a `GitHub Actions` to check package version before publish npm. 11 | 12 | ## Table of Contents 13 | 14 | 15 | 16 |
17 | Details 18 | 19 | - [Screenshots](#screenshots) 20 | - [Usage](#usage) 21 | - [Use when push](#use-when-push) 22 | - [Use in the release process](#use-in-the-release-process) 23 | - [Options](#options) 24 | - [BRANCH_PREFIX](#branch_prefix) 25 | - [COMMIT_DISABLED](#commit_disabled) 26 | - [COMMIT_MESSAGE](#commit_message) 27 | - [PACKAGE_NAME](#package_name) 28 | - [PACKAGE_DIR](#package_dir) 29 | - [TEST_TAG_PREFIX](#test_tag_prefix) 30 | - [NEXT_VERSION](#next_version) 31 | - [Action event details](#action-event-details) 32 | - [Target events](#target-events) 33 | - [Conditions](#conditions) 34 | - [Motivation](#motivation) 35 | - [Addition](#addition) 36 | - [Commit](#commit) 37 | - [Tags](#tags) 38 | - [Example repositories using this Action](#example-repositories-using-this-action) 39 | - [Author](#author) 40 | 41 |
42 | 43 | 44 | ## Screenshots 45 | 1. Running `GitHub Action` 46 | 47 | ![Running](https://raw.githubusercontent.com/technote-space/package-version-check-action/images/screenshot-1.png) 48 | 49 | 1. Updated version of package.json and commit (if branch is not protected) 50 | 51 | ![Updated](https://raw.githubusercontent.com/technote-space/package-version-check-action/images/screenshot-2.png) 52 | 53 | ## Usage 54 | ### Use when push 55 | e.g. `.github/workflows/check_version.yml` 56 | ```yaml 57 | on: push 58 | name: Check package version 59 | jobs: 60 | checkVersion: 61 | name: Check package version 62 | runs-on: ubuntu-latest 63 | steps: 64 | - uses: actions/checkout@v2 65 | 66 | # Use this GitHub Action 67 | - name: Check package version 68 | uses: technote-space/package-version-check-action@v1 69 | with: 70 | BRANCH_PREFIX: release/ 71 | ``` 72 | 73 | ### Use in the release process 74 | e.g. `.github/workflows/release.yml` 75 | ```yaml 76 | on: 77 | push: 78 | tags: 79 | - 'v*' 80 | name: Publish Package 81 | jobs: 82 | release: 83 | name: Publish Package 84 | runs-on: ubuntu-latest 85 | steps: 86 | - name: Checkout 87 | uses: actions/checkout@v2 88 | 89 | # Use this GitHub Action 90 | - name: Check package version 91 | uses: technote-space/package-version-check-action@v1 92 | with: 93 | COMMIT_DISABLED: 1 94 | 95 | - name: Install Package dependencies 96 | run: yarn install 97 | - name: Build 98 | run: yarn build 99 | - name: Publish 100 | run: | 101 | npm config set //registry.npmjs.org/:_authToken=$NPM_AUTH_TOKEN 102 | npm publish 103 | env: 104 | NPM_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} 105 | ``` 106 | [More details of target event](#action-event-details) 107 | 108 | ## Options 109 | ### BRANCH_PREFIX 110 | Branch name prefix. 111 | default: `''` 112 | e.g. `release/` 113 | 114 | ### COMMIT_DISABLED 115 | Whether commit is disabled. 116 | default: `''` 117 | 118 | ### COMMIT_MESSAGE 119 | Commit message of update package version commit. 120 | default: `'feat: update package version'` 121 | 122 | ### PACKAGE_NAME 123 | Package file name. 124 | default: `'package.json'` 125 | 126 | ### PACKAGE_DIR 127 | Package directory. 128 | default: `''` 129 | 130 | ### TEST_TAG_PREFIX 131 | Prefix for test tag. 132 | default: `''` 133 | e.g. `'test/'` 134 | 135 | ### NEXT_VERSION 136 | Specify next version. 137 | default: `''` 138 | e.g. `'v1.2.3'` 139 | 140 | ## Action event details 141 | ### Target events 142 | | eventName: action | condition | 143 | |:---:|:---:| 144 | |push: *|[condition1](#condition1)| 145 | |release: published|[condition1](#condition1)| 146 | |pull_request, pull_request_target: opened, reopened, synchronize|[condition2](#condition2)| 147 | |created: *|[condition3](#condition3)| 148 | 149 | ### Conditions 150 | #### condition1 151 | - tags 152 | - semantic versioning tag (e.g. `v1.2.3`) 153 | - branches 154 | - `${BRANCH_PREFIX}${tag}` 155 | - tag: semantic versioning tag (e.g. `v1.2.3`) 156 | - e.g. branch: `release/v1.2.3` 157 | #### condition2 158 | - branches 159 | - `${BRANCH_PREFIX}${tag}` 160 | - tag: semantic versioning tag (e.g. `v1.2.3`) 161 | - e.g. branch: `release/v1.2.3` 162 | #### condition3 163 | - tags 164 | - semantic versioning tag (e.g. `v1.2.3`) 165 | 166 | ## Motivation 167 | If you forget to update the package.json version, publishing the npm package will fail. 168 | 169 | ![Failed](https://raw.githubusercontent.com/technote-space/package-version-check-action/images/screenshot-4.png) 170 | 171 | If you are invoking an action by pushing a tag, you have to do following steps again. 172 | 173 | 1. Delete pushed tag 174 | 1. Update package.json version 175 | 1. Commit and tag again 176 | 1. Push 177 | 178 | This is very troublesome. 179 | 180 | This `GitHub Action` updates the version in package.json based on the tag name automatically. 181 | So you don't have to worry about the version in package.json. 182 | 183 | This action also commits the change if the branch is not protected. 184 | If the branch is protected, this action just update the version in package.json. 185 | 186 | ![Not commit](https://raw.githubusercontent.com/technote-space/package-version-check-action/images/screenshot-3.png) 187 | 188 | ## Addition 189 | ### Commit 190 | Commit is valid when pushing to `default branch with tag` or `branch starting with ${BRANCH_PREFIX}`. 191 | 192 | The `GITHUB_TOKEN` that is provided as a part of `GitHub Actions` doesn't have authorization to create any successive events. 193 | So it won't spawn actions which triggered by push. 194 | 195 | ![GITHUB_TOKEN](https://raw.githubusercontent.com/technote-space/package-version-check-action/images/no_access_token.png) 196 | 197 | This can be a problem if you have branch protection configured. 198 | 199 | If you want to trigger actions, use a personal access token instead. 200 | 1. Generate a [personal access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) with the public_repo or repo scope. 201 | (repo is required for private repositories). 202 | 1. [Save as ACCESS_TOKEN](https://docs.github.com/en/actions/security-guides/encrypted-secrets) 203 | 1. Add input to use `ACCESS_TOKEN` instead of `GITHUB_TOKEN`. 204 | e.g. `.github/workflows/check_version.yml` 205 | ```yaml 206 | on: push 207 | name: Check package version 208 | jobs: 209 | checkVersion: 210 | name: Check package version 211 | runs-on: ubuntu-latest 212 | steps: 213 | - uses: actions/checkout@v2 214 | 215 | # Use this GitHub Action 216 | - name: Check package version 217 | uses: technote-space/package-version-check-action@v1 218 | with: 219 | GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} 220 | BRANCH_PREFIX: release/ 221 | ``` 222 | 223 | ![ACCESS_TOKEN](https://raw.githubusercontent.com/technote-space/package-version-check-action/images/with_access_token.png) 224 | 225 | ### Tags 226 | Tag name format must be [Semantic Versioning](https://semver.org/). 227 | 228 | ## Example repositories using this Action 229 | - [GitHub Action Helper](https://github.com/technote-space/github-action-helper) 230 | - [pr-updated.yml](https://github.com/technote-space/github-action-helper/blob/master/.github/workflows/pr-updated.yml) 231 | - [ci.yml](https://github.com/technote-space/github-action-helper/blob/master/.github/workflows/ci.yml) 232 | - [GitHub Action Config Helper](https://github.com/technote-space/github-action-config-helper) 233 | - [pr-updated.yml](https://github.com/technote-space/github-action-config-helper/blob/master/.github/workflows/pr-updated.yml) 234 | - [ci.yml](https://github.com/technote-space/github-action-config-helper/blob/master/.github/workflows/ci.yml) 235 | - [GitHub Action Test Helper](https://github.com/technote-space/github-action-test-helper) 236 | - [pr-updated.yml](https://github.com/technote-space/github-action-test-helper/blob/master/.github/workflows/pr-updated.yml) 237 | - [ci.yml](https://github.com/technote-space/github-action-test-helper/blob/master/.github/workflows/ci.yml) 238 | - [Filter GitHub Action](https://github.com/technote-space/filter-github-action) 239 | - [pr-updated.yml](https://github.com/technote-space/filter-github-action/blob/master/.github/workflows/pr-updated.yml) 240 | - [ci.yml](https://github.com/technote-space/filter-github-action/blob/master/.github/workflows/ci.yml) 241 | - [jQuery Marker Animation](https://github.com/technote-space/jquery.marker-animation) 242 | - [pr-updated.yml](https://github.com/technote-space/jquery.marker-animation/blob/master/.github/workflows/pr-updated.yml) 243 | - [ci.yml](https://github.com/technote-space/jquery.marker-animation/blob/master/.github/workflows/ci.yml) 244 | - [Gutenberg Utils](https://github.com/technote-space/gutenberg-utils) 245 | - [pr-updated.yml](https://github.com/technote-space/gutenberg-utils/blob/master/.github/workflows/pr-updated.yml) 246 | - [ci.yml](https://github.com/technote-space/gutenberg-utils/blob/master/.github/workflows/ci.yml) 247 | - [Register Grouped Format Type](https://github.com/technote-space/register-grouped-format-type) 248 | - [pr-updated.yml](https://github.com/technote-space/register-grouped-format-type/blob/master/.github/workflows/pr-updated.yml) 249 | - [ci.yml](https://github.com/technote-space/register-grouped-format-type/blob/master/.github/workflows/ci.yml) 250 | 251 | ## Author 252 | [GitHub (Technote)](https://github.com/technote-space) 253 | [Blog](https://technote.space) 254 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-architect 2 | 3 | # Google Analytics 4 | google_analytics: UA-78163306-3 -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | # https://help.github.com/ja/articles/metadata-syntax-for-github-actions 2 | name: Package Version Check Action 3 | 4 | description: GitHub Action to check package version before publish. 5 | 6 | author: technote-space 7 | 8 | inputs: 9 | GITHUB_TOKEN: 10 | description: Secret GitHub API token to use for making API requests. 11 | default: ${{ github.token }} 12 | required: false 13 | BRANCH_PREFIX: 14 | description: Branch name prefix. 15 | default: '' 16 | required: false 17 | COMMIT_DISABLED: 18 | description: Whether commit is disabled. 19 | default: '' 20 | required: false 21 | COMMIT_MESSAGE: 22 | description: Commit message of update package version commit. 23 | default: 'feat: update package version' 24 | required: false 25 | PACKAGE_NAME: 26 | description: Package file name. 27 | default: 'package.json' 28 | required: false 29 | PACKAGE_DIR: 30 | description: Package directory. 31 | default: '' 32 | required: false 33 | TEST_TAG_PREFIX: 34 | description: Tag name prefix for test 35 | default: '' 36 | required: false 37 | NEXT_VERSION: 38 | description: Specify next version 39 | default: '' 40 | required: false 41 | 42 | outputs: 43 | sha: 44 | description: commit sha 45 | 46 | branding: 47 | icon: 'package' 48 | color: 'orange' 49 | 50 | runs: 51 | using: node16 52 | main: lib/main.js 53 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@technote-space/package-version-check-action", 3 | "version": "1.9.3", 4 | "description": "GitHub Action to check package version before publish.", 5 | "keywords": [ 6 | "github", 7 | "github actions" 8 | ], 9 | "homepage": "https://github.com/technote-space/package-version-check-action", 10 | "bugs": { 11 | "url": "https://github.com/technote-space/package-version-check-action/issues" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/technote-space/package-version-check-action.git" 16 | }, 17 | "license": "MIT", 18 | "author": { 19 | "name": "Technote", 20 | "email": "technote.space@gmail.com", 21 | "url": "https://technote.space" 22 | }, 23 | "files": [ 24 | "lib", 25 | "action.yml" 26 | ], 27 | "scripts": { 28 | "build": "rm -rdf lib && rollup -c", 29 | "cover": "vitest run --coverage", 30 | "postinstall": "[ -n \"$CI\" ] || [ ! -f node_modules/.bin/husky ] || husky install", 31 | "lint": "eslint 'src/**/*.ts' --cache", 32 | "lint:fix": "eslint --fix 'src/**/*.ts'", 33 | "release": "yarn release-ga --test", 34 | "test": "yarn lint && yarn typecheck && yarn cover", 35 | "typecheck": "tsc --noEmit", 36 | "update": "npm_config_yes=true npx npm-check-updates -u --timeout 100000 && yarn install && yarn upgrade && yarn audit" 37 | }, 38 | "devDependencies": { 39 | "@actions/core": "^1.10.0", 40 | "@actions/github": "^5.1.1", 41 | "@commitlint/cli": "^17.6.5", 42 | "@commitlint/config-conventional": "^17.6.5", 43 | "@rollup/plugin-commonjs": "^25.0.0", 44 | "@rollup/plugin-json": "^6.0.0", 45 | "@rollup/plugin-node-resolve": "^15.1.0", 46 | "@rollup/plugin-typescript": "^11.1.1", 47 | "@sindresorhus/tsconfig": "^3.0.1", 48 | "@technote-space/filter-github-action": "^0.6.13", 49 | "@technote-space/github-action-helper": "^5.3.17", 50 | "@technote-space/github-action-log-helper": "^0.2.19", 51 | "@technote-space/github-action-test-helper": "^0.11.17", 52 | "@technote-space/release-github-actions-cli": "^1.9.5", 53 | "@types/node": "^20.2.5", 54 | "@typescript-eslint/eslint-plugin": "^5.59.8", 55 | "@typescript-eslint/parser": "^5.59.8", 56 | "@vitest/coverage-c8": "^0.31.2", 57 | "eslint": "^8.41.0", 58 | "eslint-plugin-import": "^2.27.5", 59 | "husky": "^8.0.3", 60 | "lint-staged": "^13.2.2", 61 | "nock": "^13.3.1", 62 | "replace-in-file": "^7.0.1", 63 | "rollup": "^3.23.0", 64 | "typescript": "^5.0.4", 65 | "vitest": "^0.31.2" 66 | }, 67 | "publishConfig": { 68 | "access": "public" 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import pluginCommonjs from '@rollup/plugin-commonjs'; 2 | import pluginJson from '@rollup/plugin-json'; 3 | import pluginNodeResolve from '@rollup/plugin-node-resolve'; 4 | import pluginTypescript from '@rollup/plugin-typescript'; 5 | 6 | export default { 7 | input: 'src/main.ts', 8 | output: { 9 | file: 'lib/main.js', 10 | format: 'cjs', 11 | }, 12 | plugins: [ 13 | pluginTypescript(), 14 | pluginNodeResolve(), 15 | pluginCommonjs(), 16 | pluginJson(), 17 | ], 18 | }; 19 | -------------------------------------------------------------------------------- /src/constant.ts: -------------------------------------------------------------------------------- 1 | import { Context } from '@actions/github/lib/context'; 2 | import { isValidContext, isValidTagNameContext } from './utils/misc'; 3 | 4 | export const TARGET_EVENTS = { 5 | 'create': [ 6 | (context: Context): boolean => isValidTagNameContext(context), 7 | ], 8 | 'pull_request': [ 9 | [ 10 | 'opened', 11 | (context: Context): boolean => isValidContext(context), 12 | ], 13 | [ 14 | 'reopened', 15 | (context: Context): boolean => isValidContext(context), 16 | ], 17 | [ 18 | 'synchronize', 19 | (context: Context): boolean => isValidContext(context), 20 | ], 21 | ], 22 | 'release': [ 23 | [ 24 | 'published', 25 | (context: Context): boolean => isValidContext(context), 26 | ], 27 | ], 28 | 'push': [ 29 | (context: Context): boolean => isValidContext(context), 30 | ], 31 | }; 32 | -------------------------------------------------------------------------------- /src/fixtures/package-test1.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "version": "0.0.1", 4 | "description": "test" 5 | } 6 | -------------------------------------------------------------------------------- /src/fixtures/package-test2.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "version": "0.0.2" 4 | } 5 | -------------------------------------------------------------------------------- /src/fixtures/package-test3.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "version": "v0.0.3", 4 | "description": "test" 5 | } 6 | -------------------------------------------------------------------------------- /src/fixtures/repos.git.blobs.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://api.github.com/repos/hello/world/git/blobs/3a0f86fb8db8eea7ccbb9a95f325ddbedfb25e15", 3 | "sha": "3a0f86fb8db8eea7ccbb9a95f325ddbedfb25e15" 4 | } -------------------------------------------------------------------------------- /src/fixtures/repos.git.commits.get.json: -------------------------------------------------------------------------------- 1 | { 2 | "sha": "7638417db6d59f3c431d3e1f261cc637155684cd", 3 | "url": "https://api.github.com/repos/hello/world/git/commits/7638417db6d59f3c431d3e1f261cc637155684cd", 4 | "author": { 5 | "date": "2014-11-07T22:01:45Z", 6 | "name": "Monalisa Octocat", 7 | "email": "octocat@github.com" 8 | }, 9 | "committer": { 10 | "date": "2014-11-07T22:01:45Z", 11 | "name": "Monalisa Octocat", 12 | "email": "octocat@github.com" 13 | }, 14 | "message": "added readme, because im a good github citizen", 15 | "tree": { 16 | "url": "https://api.github.com/repos/hello/world/git/trees/691272480426f78a0138979dd3ce63b77f706feb", 17 | "sha": "691272480426f78a0138979dd3ce63b77f706feb" 18 | }, 19 | "parents": [ 20 | { 21 | "url": "https://api.github.com/repos/hello/world/git/commits/1acc419d4d6a9ce985db7be48c6349a0475975b5", 22 | "sha": "1acc419d4d6a9ce985db7be48c6349a0475975b5" 23 | } 24 | ], 25 | "verification": { 26 | "verified": false, 27 | "reason": "unsigned", 28 | "signature": null, 29 | "payload": null 30 | } 31 | } -------------------------------------------------------------------------------- /src/fixtures/repos.git.commits.json: -------------------------------------------------------------------------------- 1 | { 2 | "sha": "7638417db6d59f3c431d3e1f261cc637155684cd", 3 | "node_id": "MDY6Q29tbWl0NzYzODQxN2RiNmQ1OWYzYzQzMWQzZTFmMjYxY2M2MzcxNTU2ODRjZA==", 4 | "url": "https://api.github.com/repos/hello/world/git/commits/7638417db6d59f3c431d3e1f261cc637155684cd", 5 | "author": { 6 | "date": "2014-11-07T22:01:45Z", 7 | "name": "Monalisa Octocat", 8 | "email": "octocat@github.com" 9 | }, 10 | "committer": { 11 | "date": "2014-11-07T22:01:45Z", 12 | "name": "Monalisa Octocat", 13 | "email": "octocat@github.com" 14 | }, 15 | "message": "my commit message", 16 | "tree": { 17 | "url": "https://api.github.com/repos/hello/world/git/trees/827efc6d56897b048c772eb4087f854f46256132", 18 | "sha": "827efc6d56897b048c772eb4087f854f46256132" 19 | }, 20 | "parents": [ 21 | { 22 | "url": "https://api.github.com/repos/hello/world/git/commits/7d1b31e74ee336d15cbd21741bc88a537ed063a0", 23 | "sha": "7d1b31e74ee336d15cbd21741bc88a537ed063a0" 24 | } 25 | ], 26 | "verification": { 27 | "verified": false, 28 | "reason": "unsigned", 29 | "signature": null, 30 | "payload": null 31 | } 32 | } -------------------------------------------------------------------------------- /src/fixtures/repos.git.refs.json: -------------------------------------------------------------------------------- 1 | { 2 | "ref": "refs/heads/featureA", 3 | "node_id": "MDM6UmVmcmVmcy9oZWFkcy9mZWF0dXJlQQ==", 4 | "url": "https://api.github.com/repos/hello/world/git/refs/heads/featureA", 5 | "object": { 6 | "type": "commit", 7 | "sha": "aa218f56b14c9653891f9e74264a383fa43fefbd", 8 | "url": "https://api.github.com/repos/hello/world/git/commits/aa218f56b14c9653891f9e74264a383fa43fefbd" 9 | } 10 | } -------------------------------------------------------------------------------- /src/fixtures/repos.git.trees.json: -------------------------------------------------------------------------------- 1 | { 2 | "sha": "cd8274d15fa3ae2ab983129fb037999f264ba9a7", 3 | "url": "https://api.github.com/repos/hello/world/trees/cd8274d15fa3ae2ab983129fb037999f264ba9a7", 4 | "tree": [ 5 | { 6 | "path": "file.rb", 7 | "mode": "100644", 8 | "type": "blob", 9 | "size": 132, 10 | "sha": "7c258a9869f33c1e1e1f74fbb32f07c86cb5a75b", 11 | "url": "https://api.github.com/repos/hello/world/git/blobs/7c258a9869f33c1e1e1f74fbb32f07c86cb5a75b" 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from 'path'; 2 | import { setFailed } from '@actions/core'; 3 | import { Context } from '@actions/github/lib/context'; 4 | import { isTargetEvent } from '@technote-space/filter-github-action'; 5 | import { ContextHelper, Utils } from '@technote-space/github-action-helper'; 6 | import { Logger } from '@technote-space/github-action-log-helper'; 7 | import { TARGET_EVENTS } from './constant'; 8 | import { updatePackageVersion, commit } from './utils/package'; 9 | 10 | const run = async(): Promise => { 11 | const logger = new Logger(); 12 | const context = new Context(); 13 | ContextHelper.showActionInfo(resolve(__dirname, '..'), logger, context); 14 | 15 | if (!isTargetEvent(TARGET_EVENTS, context)) { 16 | logger.info('This is not target event.'); 17 | return; 18 | } 19 | 20 | if (await updatePackageVersion(context, logger)) { 21 | await commit(Utils.getOctokit(), context, logger); 22 | } 23 | }; 24 | 25 | run().catch(error => { 26 | console.log(error); 27 | setFailed(error.message); 28 | }); 29 | -------------------------------------------------------------------------------- /src/setup.ts: -------------------------------------------------------------------------------- 1 | import { setupGlobal } from '@technote-space/github-action-test-helper'; 2 | 3 | setupGlobal(); 4 | -------------------------------------------------------------------------------- /src/utils/command.test.ts: -------------------------------------------------------------------------------- 1 | import { Logger } from '@technote-space/github-action-log-helper'; 2 | import { setChildProcessParams } from '@technote-space/github-action-test-helper'; 3 | import { describe, expect, it } from 'vitest'; 4 | import { getBranchesByTag } from './command'; 5 | 6 | const logger = new Logger(); 7 | 8 | describe('getBranchesByTag', () => { 9 | it('should empty', async() => { 10 | setChildProcessParams({ stdout: '' }); 11 | expect(await getBranchesByTag('', logger)).toEqual([]); 12 | }); 13 | 14 | it('should get branches', async() => { 15 | setChildProcessParams({ stdout: 'develop\nfeature/test\nremotes/origin/master\n' }); 16 | expect(await getBranchesByTag('', logger)).toEqual([ 17 | 'develop', 18 | 'feature/test', 19 | 'master', 20 | ]); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /src/utils/command.ts: -------------------------------------------------------------------------------- 1 | import type { Logger } from '@technote-space/github-action-log-helper'; 2 | import { Command } from '@technote-space/github-action-helper'; 3 | 4 | export const getBranchesByTag = async(tagName: string, logger: Logger): Promise => (await (new Command(logger)).execAsync({ command: `git branch -a --contains ${tagName} | cut -b 3-` })).stdout 5 | .trim() 6 | .split(/\r?\n/) 7 | .filter(item => item) 8 | .map(item => item.replace(/^remotes\/origin\//, '')); 9 | -------------------------------------------------------------------------------- /src/utils/misc.test.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-magic-numbers */ 2 | import path from 'path'; 3 | import { isTargetEvent } from '@technote-space/filter-github-action'; 4 | import { Logger } from '@technote-space/github-action-log-helper'; 5 | import { generateContext, testEnv } from '@technote-space/github-action-test-helper'; 6 | import { describe, expect, it } from 'vitest'; 7 | import { TARGET_EVENTS } from '../constant'; 8 | import { 9 | getPackageDir, 10 | getPackageFileName, 11 | getPackagePath, 12 | getPackageData, 13 | getPackageVersion, 14 | isTestTag, 15 | getTestTag, 16 | isValidTagName, 17 | isRequiredUpdate, 18 | getPackageVersionToUpdate, 19 | getReplaceResultMessages, 20 | getCommitMessage, 21 | getTagName, 22 | } from './misc'; 23 | 24 | const rootDir = path.resolve(__dirname, '../..'); 25 | const logger = new Logger(); 26 | 27 | describe('isTargetEvent', () => { 28 | testEnv(rootDir); 29 | 30 | it('should return true 1', () => { 31 | expect(isTargetEvent(TARGET_EVENTS, generateContext({ 32 | event: 'push', 33 | ref: 'refs/tags/v1.2.3', 34 | }))).toBe(true); 35 | }); 36 | 37 | it('should return true 2', () => { 38 | process.env.INPUT_BRANCH_PREFIX = 'release/'; 39 | expect(isTargetEvent(TARGET_EVENTS, generateContext({ 40 | event: 'push', 41 | ref: 'refs/heads/release/v1.2.3', 42 | }))).toBe(true); 43 | }); 44 | 45 | it('should return true 3', () => { 46 | expect(isTargetEvent(TARGET_EVENTS, generateContext({ 47 | event: 'release', 48 | action: 'published', 49 | }, { 50 | payload: { 51 | release: { 52 | 'tag_name': 'v1.2.3', 53 | }, 54 | }, 55 | }))).toBe(true); 56 | }); 57 | 58 | it('should return true 4', () => { 59 | process.env.INPUT_NEXT_VERSION = 'v1.2.3'; 60 | expect(isTargetEvent(TARGET_EVENTS, generateContext({ 61 | event: 'pull_request', 62 | action: 'synchronize', 63 | }, { 64 | payload: {}, 65 | }))).toBe(true); 66 | }); 67 | 68 | it('should return true 5', () => { 69 | expect(isTargetEvent(TARGET_EVENTS, generateContext({ 70 | event: 'create', 71 | ref: 'refs/tags/v1.2.3', 72 | }))).toBe(true); 73 | }); 74 | 75 | it('should return true 6', () => { 76 | process.env.INPUT_BRANCH_PREFIX = 'release/'; 77 | expect(isTargetEvent(TARGET_EVENTS, generateContext({ 78 | event: 'pull_request', 79 | action: 'opened', 80 | ref: 'refs/pull/123/merge', 81 | }, { 82 | payload: { 83 | 'pull_request': { 84 | head: { 85 | ref: 'release/v1.2.3', 86 | }, 87 | }, 88 | }, 89 | }))).toBe(true); 90 | }); 91 | 92 | it('should return true 7', () => { 93 | process.env.INPUT_NEXT_VERSION = 'v1.2.3'; 94 | expect(isTargetEvent(TARGET_EVENTS, generateContext({ 95 | event: 'push', 96 | ref: 'refs/master', 97 | }))).toBe(true); 98 | }); 99 | 100 | it('should return true 8', () => { 101 | process.env.INPUT_NEXT_VERSION = 'v1.2.3'; 102 | expect(isTargetEvent(TARGET_EVENTS, generateContext({ 103 | event: 'pull_request', 104 | action: 'reopened', 105 | }, { 106 | payload: {}, 107 | }))).toBe(true); 108 | }); 109 | 110 | it('should return false 1', () => { 111 | process.env.INPUT_BRANCH_PREFIX = 'release/'; 112 | expect(isTargetEvent(TARGET_EVENTS, generateContext({ 113 | event: 'pull_request', 114 | action: 'opened', 115 | ref: 'refs/tags/test', 116 | }, { 117 | payload: { 118 | 'pull_request': { 119 | head: { 120 | ref: 'feature/new-feature', 121 | }, 122 | }, 123 | }, 124 | }))).toBe(false); 125 | }); 126 | 127 | it('should return false 2', () => { 128 | expect(isTargetEvent(TARGET_EVENTS, generateContext({ 129 | event: 'push', 130 | ref: 'refs/tags/test', 131 | }))).toBe(false); 132 | }); 133 | 134 | it('should return false 3', () => { 135 | process.env.INPUT_BRANCH_PREFIX = 'release'; 136 | expect(isTargetEvent(TARGET_EVENTS, generateContext({ 137 | event: 'push', 138 | ref: 'refs/heads/release/v1.2.3', 139 | }))).toBe(false); 140 | }); 141 | 142 | it('should return false 4', () => { 143 | expect(isTargetEvent(TARGET_EVENTS, generateContext({ 144 | event: 'release', 145 | action: 'published', 146 | }, { 147 | payload: { 148 | release: { 149 | 'tag_name': 'abc', 150 | }, 151 | }, 152 | }))).toBe(false); 153 | }); 154 | 155 | it('should return false 5', () => { 156 | expect(isTargetEvent(TARGET_EVENTS, generateContext({ 157 | event: 'release', 158 | action: 'created', 159 | ref: 'refs/tags/v1.2.3', 160 | }, { 161 | payload: { 162 | release: { 163 | 'tag_name': 'v1.2.3', 164 | }, 165 | }, 166 | }))).toBe(false); 167 | }); 168 | 169 | it('should return false 6', () => { 170 | expect(isTargetEvent(TARGET_EVENTS, generateContext({ 171 | event: 'create', 172 | ref: 'refs/heads/v1.2.3', 173 | }))).toBe(false); 174 | }); 175 | 176 | it('should return false 7', () => { 177 | process.env.INPUT_BRANCH_PREFIX = 'release/'; 178 | expect(isTargetEvent(TARGET_EVENTS, generateContext({ 179 | event: 'pull_request', 180 | action: 'closed', 181 | ref: 'refs/pull/123/merge', 182 | }, { 183 | payload: { 184 | 'pull_request': { 185 | head: { 186 | ref: 'release/v1.2.3', 187 | }, 188 | }, 189 | }, 190 | }))).toBe(false); 191 | }); 192 | 193 | it('should return false 8', () => { 194 | process.env.INPUT_NEXT_VERSION = 'abc'; 195 | expect(isTargetEvent(TARGET_EVENTS, generateContext({ 196 | event: 'push', 197 | ref: 'refs/master', 198 | }))).toBe(false); 199 | }); 200 | }); 201 | 202 | describe('getPackageDir', () => { 203 | testEnv(rootDir); 204 | 205 | it('should get package dir', () => { 206 | process.env.INPUT_PACKAGE_DIR = 'package-dir'; 207 | process.env.GITHUB_WORKSPACE = 'test'; 208 | 209 | expect(getPackageDir()).toBe('package-dir'); 210 | }); 211 | 212 | it('should get default package dir', () => { 213 | process.env.GITHUB_WORKSPACE = 'test'; 214 | 215 | expect(getPackageDir()).toBe('test'); 216 | }); 217 | }); 218 | 219 | describe('getPackageFileName', () => { 220 | testEnv(rootDir); 221 | 222 | it('should get package file name', () => { 223 | process.env.INPUT_PACKAGE_NAME = 'test.json'; 224 | expect(getPackageFileName()).toBe('test.json'); 225 | }); 226 | 227 | it('should get default package file name', () => { 228 | expect(getPackageFileName()).toBe('package.json'); 229 | }); 230 | }); 231 | 232 | describe('getPackagePath', () => { 233 | testEnv(rootDir); 234 | 235 | it('should get package path', () => { 236 | process.env.GITHUB_WORKSPACE = 'test'; 237 | 238 | const dir = path.resolve(__dirname, '..', '..'); 239 | expect(getPackagePath()).toBe(`${dir}/test/package.json`); 240 | }); 241 | }); 242 | 243 | describe('getPackageData', () => { 244 | testEnv(rootDir); 245 | 246 | it('should get package data', () => { 247 | process.env.INPUT_PACKAGE_DIR = 'src/fixtures'; 248 | process.env.INPUT_PACKAGE_NAME = 'package-test1.json'; 249 | expect(getPackageData()).toEqual({ 250 | 'name': 'test', 251 | 'version': '0.0.1', 252 | 'description': 'test', 253 | }); 254 | }); 255 | }); 256 | 257 | describe('getPackageVersion', () => { 258 | testEnv(rootDir); 259 | 260 | it('should get package version 1', () => { 261 | process.env.INPUT_PACKAGE_DIR = 'src/fixtures'; 262 | process.env.INPUT_PACKAGE_NAME = 'package-test1.json'; 263 | expect(getPackageVersion()).toBe('0.0.1'); 264 | }); 265 | 266 | it('should get package version 2', () => { 267 | process.env.INPUT_PACKAGE_DIR = 'src/fixtures'; 268 | process.env.INPUT_PACKAGE_NAME = 'package-test2.json'; 269 | expect(getPackageVersion()).toBe('0.0.2'); 270 | }); 271 | 272 | it('should get package version 3', () => { 273 | process.env.INPUT_PACKAGE_DIR = 'src/fixtures'; 274 | process.env.INPUT_PACKAGE_NAME = 'package-test3.json'; 275 | expect(getPackageVersion()).toBe('v0.0.3'); 276 | }); 277 | }); 278 | 279 | describe('isTestTag', () => { 280 | testEnv(rootDir); 281 | 282 | it('should return true', () => { 283 | process.env.INPUT_TEST_TAG_PREFIX = 'test/'; 284 | expect(isTestTag('test/v1.2.3')).toBe(true); 285 | }); 286 | 287 | it('should return false', () => { 288 | process.env.INPUT_TEST_TAG_PREFIX = 'test/'; 289 | expect(isTestTag('v1.2.3')).toBe(false); 290 | }); 291 | }); 292 | 293 | describe('getTestTag', () => { 294 | testEnv(rootDir); 295 | 296 | it('should get test tag', () => { 297 | process.env.INPUT_TEST_TAG_PREFIX = 'test/'; 298 | expect(getTestTag('test/v1.2.3')).toBe('v1.2.3'); 299 | }); 300 | }); 301 | 302 | describe('isValidTagName', () => { 303 | testEnv(rootDir); 304 | 305 | it('should return true 1', () => { 306 | expect(isValidTagName('1.2.3')).toBe(true); 307 | expect(isValidTagName('v1.2.3')).toBe(true); 308 | }); 309 | 310 | it('should return true 2', () => { 311 | process.env.INPUT_TEST_TAG_PREFIX = 'test/'; 312 | expect(isValidTagName('test/1.2.3')).toBe(true); 313 | expect(isValidTagName('test/v1.2.3')).toBe(true); 314 | }); 315 | 316 | it('should return false 1', () => { 317 | expect(isValidTagName('test/1.2.3')).toBe(false); 318 | expect(isValidTagName('test/v1.2.3')).toBe(false); 319 | expect(isValidTagName('.2.3')).toBe(false); 320 | expect(isValidTagName('abc')).toBe(false); 321 | expect(isValidTagName('')).toBe(false); 322 | }); 323 | 324 | it('should return false 2', () => { 325 | process.env.INPUT_TEST_TAG_PREFIX = 'test/'; 326 | expect(isValidTagName('.2.3')).toBe(false); 327 | expect(isValidTagName('abc')).toBe(false); 328 | expect(isValidTagName('')).toBe(false); 329 | }); 330 | }); 331 | 332 | describe('isRequiredUpdate', () => { 333 | it('should return false', () => { 334 | expect(isRequiredUpdate('0.0.1', '0.0.1')).toBe(false); 335 | expect(isRequiredUpdate('v0.0.1', '0.0.1')).toBe(false); 336 | expect(isRequiredUpdate('0.0.1', 'v0.0.1')).toBe(false); 337 | expect(isRequiredUpdate('v0.0.1', 'v0.0.1')).toBe(false); 338 | }); 339 | 340 | it('should return true', () => { 341 | expect(isRequiredUpdate('0.0.1', '0.0.2')).toBe(true); 342 | expect(isRequiredUpdate('0.0.1', 'v0.0.2')).toBe(true); 343 | expect(isRequiredUpdate('0.0.1', 'v0.1.0')).toBe(true); 344 | }); 345 | }); 346 | 347 | describe('getPackageVersionToUpdate', () => { 348 | testEnv(rootDir); 349 | 350 | it('should get version', () => { 351 | expect(getPackageVersionToUpdate('1.2.3')).toBe('1.2.3'); 352 | expect(getPackageVersionToUpdate('v1.2.3')).toBe('1.2.3'); 353 | }); 354 | 355 | it('should get version', () => { 356 | process.env.INPUT_TEST_TAG_PREFIX = 'test/'; 357 | 358 | expect(getPackageVersionToUpdate('test/1.2.3')).toBe('1.2.3'); 359 | expect(getPackageVersionToUpdate('test/v1.2.3')).toBe('1.2.3'); 360 | }); 361 | }); 362 | 363 | describe('getReplaceResultMessages', () => { 364 | it('should return empty', () => { 365 | expect(getReplaceResultMessages([], logger)).toEqual([]); 366 | }); 367 | 368 | it('should get messages', () => { 369 | const messages = getReplaceResultMessages([ 370 | { 371 | file: 'test1', 372 | hasChanged: true, 373 | }, 374 | { 375 | file: 'test2', 376 | hasChanged: false, 377 | }, 378 | ], logger); 379 | 380 | expect(messages).toHaveLength(2); 381 | expect(messages[0]).toContain('test1'); 382 | expect(messages[1]).toContain('test2'); 383 | }); 384 | }); 385 | 386 | describe('getCommitMessage', () => { 387 | testEnv(rootDir); 388 | 389 | it('should get commit message', () => { 390 | process.env.INPUT_COMMIT_MESSAGE = 'test message'; 391 | 392 | expect(getCommitMessage()).toBe('test message'); 393 | }); 394 | 395 | it('should get default commit message', () => { 396 | expect(getCommitMessage()).toBe('feat: update package version'); 397 | }); 398 | }); 399 | 400 | describe('getTagName', () => { 401 | testEnv(rootDir); 402 | 403 | it('should get tag name', () => { 404 | expect(getTagName(generateContext({ 405 | event: 'push', 406 | ref: 'refs/tags/test', 407 | }))).toBe('test'); 408 | }); 409 | 410 | it('should get tag name from branch', () => { 411 | process.env.INPUT_BRANCH_PREFIX = 'release/'; 412 | expect(getTagName(generateContext({ 413 | event: 'push', 414 | ref: 'refs/heads/release/v1.2.3', 415 | }))).toBe('v1.2.3'); 416 | }); 417 | }); 418 | -------------------------------------------------------------------------------- /src/utils/misc.ts: -------------------------------------------------------------------------------- 1 | import type { Context } from '@actions/github/lib/context'; 2 | import type { Logger } from '@technote-space/github-action-log-helper'; 3 | import type { ReplaceResult } from 'replace-in-file'; 4 | import fs from 'fs'; 5 | import path from 'path'; 6 | import { getInput } from '@actions/core' ; 7 | import { Utils, ContextHelper } from '@technote-space/github-action-helper'; 8 | 9 | const { getWorkspace, isValidSemanticVersioning, getBoolValue, getPrefixRegExp } = Utils; 10 | 11 | const normalizeVersion = (version: string): string => Utils.normalizeVersion(version) ?? ''; 12 | 13 | export const getPackageDir = (): string => getInput('PACKAGE_DIR') || getWorkspace(); 14 | 15 | export const getBranchPrefix = (): string => getInput('BRANCH_PREFIX'); 16 | 17 | const getBranchPrefixRegExp = (): RegExp => getPrefixRegExp(getBranchPrefix()); 18 | 19 | const getVersionFromBranch = (branch: string): string => branch.replace(getBranchPrefixRegExp(), ''); 20 | 21 | export const isValidBranch = (branch: string): boolean => !!getBranchPrefix() && getBranchPrefixRegExp().test(branch) && isValidSemanticVersioning(getVersionFromBranch(branch)); 22 | 23 | export const getPackageFileName = (): string => getInput('PACKAGE_NAME', { required: true }); 24 | 25 | export const getPackagePath = (): string => path.resolve(getPackageDir(), getPackageFileName()); 26 | 27 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 28 | export const getPackageData = (): any => JSON.parse(fs.readFileSync(getPackagePath(), { encoding: 'utf-8' })); 29 | 30 | export const getPackageVersion = (): string => getPackageData()['version']; 31 | 32 | export const getTestTagPrefix = (): string => getInput('TEST_TAG_PREFIX'); 33 | 34 | const getTestTagPrefixRegExp = (): RegExp => getPrefixRegExp(getTestTagPrefix()); 35 | 36 | export const isTestTag = (tagName: string): boolean => !!getTestTagPrefix() && getTestTagPrefixRegExp().test(tagName); 37 | 38 | export const getTestTag = (tagName: string): string => tagName.replace(getTestTagPrefixRegExp(), ''); 39 | 40 | export const getPackageVersionToUpdate = (tagName: string): string => normalizeVersion(isTestTag(tagName) ? getTestTag(tagName) : tagName); 41 | 42 | export const isRequiredUpdate = (packageVersion: string, tagName: string): boolean => normalizeVersion(packageVersion) !== getPackageVersionToUpdate(tagName); 43 | 44 | export const isValidTagName = (tagName: string): boolean => isValidSemanticVersioning(getPackageVersionToUpdate(tagName)); 45 | 46 | export const getReplaceResultMessages = (results: ReplaceResult[], logger: Logger): string[] => results.map(result => `${result.hasChanged ? logger.c('✔', { color: 'green' }) : logger.c('✖', { color: 'red' })} ${result.file}`); 47 | 48 | export const getCommitMessage = (): string => getInput('COMMIT_MESSAGE', { required: true }); 49 | 50 | export const isCommitDisabled = (): boolean => getBoolValue(getInput('COMMIT_DISABLED')); 51 | 52 | export const getDefaultBranch = (context: Context): string | undefined => context.payload.repository ? context.payload.repository.default_branch : undefined; 53 | 54 | export const getBranch = (context: Context): string => ContextHelper.isPr(context) ? Utils.getPrBranch(context) : Utils.getBranch(context); 55 | 56 | export const getNextVersion = (): string => { 57 | const version = getInput('NEXT_VERSION'); 58 | if (isValidTagName(version)) { 59 | return version; 60 | } 61 | 62 | return ''; 63 | }; 64 | 65 | export const isSpecifiedNextVersion = (): boolean => !!getNextVersion(); 66 | 67 | export const getTagName = (context: Context): string => { 68 | const nextVersion = getNextVersion(); 69 | if (nextVersion) { 70 | return nextVersion; 71 | } 72 | 73 | const tagName = ContextHelper.getTagName(context); 74 | if (tagName) { 75 | return tagName; 76 | } 77 | 78 | return getVersionFromBranch(getBranch(context)); 79 | }; 80 | 81 | export const isValidTagNameContext = (context: Context): boolean => isValidTagName(ContextHelper.getTagName(context)); 82 | 83 | export const isValidBranchContext = (context: Context): boolean => isValidBranch(getBranch(context)); 84 | 85 | export const isValidContext = (context: Context): boolean => isSpecifiedNextVersion() || isValidTagNameContext(context) || isValidBranchContext(context); 86 | -------------------------------------------------------------------------------- /src/utils/package.test.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-magic-numbers */ 2 | import path from 'path'; 3 | import { Logger } from '@technote-space/github-action-log-helper'; 4 | import { 5 | getContext, 6 | testEnv, 7 | disableNetConnect, 8 | getApiFixture, 9 | spyOnStdout, 10 | stdoutCalledWith, 11 | spyOnExportVariable, 12 | exportVariableCalledWith, 13 | spyOnSetOutput, 14 | setOutputCalledWith, 15 | setChildProcessParams, 16 | testFs, 17 | getOctokit, 18 | } from '@technote-space/github-action-test-helper'; 19 | import nock from 'nock'; 20 | import replaceInFile from 'replace-in-file'; 21 | import { beforeEach, describe, expect, it, vi } from 'vitest'; 22 | import { 23 | updatePackageVersion, 24 | getUpdateBranch, 25 | commit, 26 | } from './package'; 27 | 28 | const setExists = testFs(true); 29 | const rootDir = path.resolve(__dirname, '../..'); 30 | const logger = new Logger(); 31 | const octokit = getOctokit(); 32 | 33 | beforeEach(() => { 34 | Logger.resetForTesting(); 35 | }); 36 | 37 | describe('updatePackageVersion', () => { 38 | testEnv(rootDir); 39 | 40 | it('should return false 1', async() => { 41 | setExists(false); 42 | process.env.INPUT_PACKAGE_DIR = 'src/fixtures'; 43 | process.env.INPUT_PACKAGE_NAME = 'package-test1.json'; 44 | const mockStdout = spyOnStdout(); 45 | 46 | expect(await updatePackageVersion(getContext({ 47 | eventName: 'push', 48 | ref: 'refs/tags/v0.0.1', 49 | }), logger)).toBe(false); 50 | 51 | stdoutCalledWith(mockStdout, [ 52 | '::group::Updating package version...', 53 | '::warning::File [package-test1.json] not found.', 54 | '::warning::Please checkout before call this GitHub Action.', 55 | ]); 56 | }); 57 | 58 | it('should return false 2', async() => { 59 | process.env.INPUT_PACKAGE_DIR = 'src/fixtures'; 60 | process.env.INPUT_PACKAGE_NAME = 'package-test1.json'; 61 | const mockStdout = spyOnStdout(); 62 | 63 | expect(await updatePackageVersion(getContext({ 64 | eventName: 'push', 65 | ref: 'refs/tags/v0.0.1', 66 | }), logger)).toBe(false); 67 | 68 | stdoutCalledWith(mockStdout, [ 69 | '::group::Updating package version...', 70 | '> target version: v0.0.1', 71 | '> current version: 0.0.1', 72 | '> No need to update.', 73 | ]); 74 | }); 75 | 76 | it('should return false 3', async() => { 77 | process.env.INPUT_PACKAGE_DIR = 'src/fixtures'; 78 | process.env.INPUT_PACKAGE_NAME = 'package-test1.json'; 79 | process.env.INPUT_NEXT_VERSION = 'v0.0.1'; 80 | const mockStdout = spyOnStdout(); 81 | 82 | expect(await updatePackageVersion(getContext({ 83 | eventName: 'push', 84 | }), logger)).toBe(false); 85 | 86 | stdoutCalledWith(mockStdout, [ 87 | '::group::Updating package version...', 88 | '> target version: v0.0.1', 89 | '> current version: 0.0.1', 90 | '> No need to update.', 91 | ]); 92 | }); 93 | 94 | it('should return true 1', async() => { 95 | process.env.INPUT_PACKAGE_DIR = 'src/fixtures'; 96 | process.env.INPUT_PACKAGE_NAME = 'package-test1.json'; 97 | const mockStdout = spyOnStdout(); 98 | 99 | const fn = vi.fn(() => ([ 100 | { file: 'test1', hasChanged: true }, 101 | { file: 'test2', hasChanged: false }, 102 | ])); 103 | const replaceInFileMock = vi.spyOn(replaceInFile, 'replaceInFile').mockImplementation(fn); 104 | 105 | expect(await updatePackageVersion(getContext({ 106 | eventName: 'push', 107 | ref: 'refs/tags/v0.0.2', 108 | }), logger)).toBe(true); 109 | 110 | stdoutCalledWith(mockStdout, [ 111 | '::group::Updating package version...', 112 | '> target version: v0.0.2', 113 | '> current version: 0.0.1', 114 | ' >> \x1b[32;40m✔\x1b[0m test1', 115 | ' >> \x1b[31;40m✖\x1b[0m test2', 116 | ]); 117 | 118 | expect(replaceInFileMock).toBeCalledTimes(1); 119 | expect(replaceInFileMock).toBeCalledWith({ 120 | files: path.resolve(__dirname, '..', 'fixtures', 'package-test1.json'), 121 | from: /"version"\s*:\s*"(v?).+?"\s*(,?)$/gm, 122 | to: '"version": "$10.0.2"$2', 123 | }); 124 | }); 125 | 126 | it('should return true 2', async() => { 127 | process.env.INPUT_PACKAGE_DIR = 'src/fixtures'; 128 | process.env.INPUT_PACKAGE_NAME = 'package-test1.json'; 129 | process.env.INPUT_NEXT_VERSION = 'v0.0.3'; 130 | const mockStdout = spyOnStdout(); 131 | 132 | const fn = vi.fn(() => ([])); 133 | const replaceInFileMock = vi.spyOn(replaceInFile, 'replaceInFile').mockImplementation(fn); 134 | 135 | expect(await updatePackageVersion(getContext({ 136 | eventName: 'push', 137 | ref: 'refs/tags/v0.0.2', 138 | }), logger)).toBe(true); 139 | 140 | stdoutCalledWith(mockStdout, [ 141 | '::group::Updating package version...', 142 | '> target version: v0.0.3', 143 | '> current version: 0.0.1', 144 | ]); 145 | 146 | expect(replaceInFileMock).toBeCalledTimes(1); 147 | expect(replaceInFileMock).toBeCalledWith({ 148 | files: path.resolve(__dirname, '..', 'fixtures', 'package-test1.json'), 149 | from: /"version"\s*:\s*"(v?).+?"\s*(,?)$/gm, 150 | to: '"version": "$10.0.3"$2', 151 | }); 152 | }); 153 | 154 | it('should return true 3', async() => { 155 | process.env.INPUT_PACKAGE_DIR = 'src/fixtures'; 156 | process.env.INPUT_PACKAGE_NAME = 'package-test1.json'; 157 | process.env.INPUT_NEXT_VERSION = '1.0.0-rc.1'; 158 | const mockStdout = spyOnStdout(); 159 | 160 | const fn = vi.fn(() => ([])); 161 | const replaceInFileMock = vi.spyOn(replaceInFile, 'replaceInFile').mockImplementation(fn); 162 | 163 | expect(await updatePackageVersion(getContext({ 164 | eventName: 'push', 165 | ref: 'refs/tags/v0.0.2', 166 | }), logger)).toBe(true); 167 | 168 | stdoutCalledWith(mockStdout, [ 169 | '::group::Updating package version...', 170 | '> target version: 1.0.0-rc.1', 171 | '> current version: 0.0.1', 172 | ]); 173 | 174 | expect(replaceInFileMock).toBeCalledTimes(1); 175 | expect(replaceInFileMock).toBeCalledWith({ 176 | files: path.resolve(__dirname, '..', 'fixtures', 'package-test1.json'), 177 | from: /"version"\s*:\s*"(v?).+?"\s*(,?)$/gm, 178 | to: '"version": "$11.0.0-rc.1"$2', 179 | }); 180 | }); 181 | 182 | it('should return true 4', async() => { 183 | process.env.INPUT_PACKAGE_DIR = 'src/fixtures'; 184 | process.env.INPUT_PACKAGE_NAME = 'package-test1.json'; 185 | process.env.INPUT_NEXT_VERSION = 'v3.0.0+f2eed76'; 186 | const mockStdout = spyOnStdout(); 187 | 188 | const fn = vi.fn(() => ([])); 189 | const replaceInFileMock = vi.spyOn(replaceInFile, 'replaceInFile').mockImplementation(fn); 190 | 191 | expect(await updatePackageVersion(getContext({ 192 | eventName: 'push', 193 | ref: 'refs/tags/v0.0.2', 194 | }), logger)).toBe(true); 195 | 196 | stdoutCalledWith(mockStdout, [ 197 | '::group::Updating package version...', 198 | '> target version: v3.0.0+f2eed76', 199 | '> current version: 0.0.1', 200 | ]); 201 | 202 | expect(replaceInFileMock).toBeCalledTimes(1); 203 | expect(replaceInFileMock).toBeCalledWith({ 204 | files: path.resolve(__dirname, '..', 'fixtures', 'package-test1.json'), 205 | from: /"version"\s*:\s*"(v?).+?"\s*(,?)$/gm, 206 | to: '"version": "$13.0.0+f2eed76"$2', 207 | }); 208 | }); 209 | 210 | it('should return true 5', async() => { 211 | process.env.INPUT_PACKAGE_DIR = 'src/fixtures'; 212 | process.env.INPUT_PACKAGE_NAME = 'package-test1.json'; 213 | process.env.INPUT_NEXT_VERSION = 'v1.0-beta+exp.sha.5114f85'; 214 | const mockStdout = spyOnStdout(); 215 | 216 | const fn = vi.fn(() => ([])); 217 | const replaceInFileMock = vi.spyOn(replaceInFile, 'replaceInFile').mockImplementation(fn); 218 | 219 | expect(await updatePackageVersion(getContext({ 220 | eventName: 'push', 221 | ref: 'refs/tags/v0.0.2', 222 | }), logger)).toBe(true); 223 | 224 | stdoutCalledWith(mockStdout, [ 225 | '::group::Updating package version...', 226 | '> target version: v1.0-beta+exp.sha.5114f85', 227 | '> current version: 0.0.1', 228 | ]); 229 | 230 | expect(replaceInFileMock).toBeCalledTimes(1); 231 | expect(replaceInFileMock).toBeCalledWith({ 232 | files: path.resolve(__dirname, '..', 'fixtures', 'package-test1.json'), 233 | from: /"version"\s*:\s*"(v?).+?"\s*(,?)$/gm, 234 | to: '"version": "$11.0.0-beta+exp.sha.5114f85"$2', 235 | }); 236 | }); 237 | }); 238 | 239 | describe('getUpdateBranch', () => { 240 | testEnv(rootDir); 241 | const logger = new Logger(); 242 | 243 | it('should return false 1', async() => { 244 | expect(await getUpdateBranch(logger, getContext({ 245 | eventName: 'push', 246 | ref: 'refs/tags/test', 247 | }))).toBe(false); 248 | }); 249 | 250 | it('should return false 2', async() => { 251 | setChildProcessParams({ stdout: '' }); 252 | 253 | expect(await getUpdateBranch(logger, getContext({ 254 | eventName: 'push', 255 | ref: 'refs/tags/test', 256 | payload: { 257 | repository: { 258 | 'default_branch': 'master', 259 | }, 260 | }, 261 | }))).toBe(false); 262 | }); 263 | 264 | it('should get default branch', async() => { 265 | setChildProcessParams({ stdout: 'remotes/origin/master' }); 266 | 267 | expect(await getUpdateBranch(logger, getContext({ 268 | eventName: 'push', 269 | ref: 'refs/tags/test', 270 | payload: { 271 | repository: { 272 | 'default_branch': 'master', 273 | }, 274 | }, 275 | }))).toBe('master'); 276 | }); 277 | 278 | it('should get branch 1', async() => { 279 | expect(await getUpdateBranch(logger, getContext({ 280 | eventName: 'push', 281 | ref: 'refs/heads/release/v1.2.3', 282 | }))).toBe('release/v1.2.3'); 283 | }); 284 | 285 | it('should get branch 2', async() => { 286 | process.env.INPUT_BRANCH_PREFIX = 'release/'; 287 | setChildProcessParams({ stdout: '' }); 288 | 289 | expect(await getUpdateBranch(logger, getContext({ 290 | eventName: 'pull_request', 291 | ref: 'refs/pull/123/merge', 292 | payload: { 293 | repository: { 294 | 'default_branch': 'master', 295 | }, 296 | 'pull_request': { 297 | head: { 298 | ref: 'feature/new-feature', 299 | }, 300 | }, 301 | }, 302 | }))).toBe('feature/new-feature'); 303 | }); 304 | }); 305 | 306 | describe('commit', () => { 307 | testEnv(rootDir); 308 | disableNetConnect(nock); 309 | 310 | it('should do nothing', async() => { 311 | process.env.INPUT_COMMIT_DISABLED = '1'; 312 | const mockStdout = spyOnStdout(); 313 | 314 | expect(await commit(octokit, getContext({ 315 | ref: 'refs/tags/test', 316 | repo: { 317 | owner: 'hello', 318 | repo: 'world', 319 | }, 320 | }), logger)).toBe(true); 321 | 322 | stdoutCalledWith(mockStdout, [ 323 | '::group::Committing...', 324 | '> Commit is disabled.', 325 | ]); 326 | }); 327 | 328 | it('should return false 1', async() => { 329 | process.env.INPUT_COMMIT_DISABLED = ''; 330 | const mockStdout = spyOnStdout(); 331 | 332 | expect(await commit(octokit, getContext({ 333 | ref: 'refs/tags/test', 334 | repo: { 335 | owner: 'hello', 336 | repo: 'world', 337 | }, 338 | }), logger)).toBe(false); 339 | 340 | stdoutCalledWith(mockStdout, [ 341 | '::group::Committing...', 342 | '::warning::Failed to get default branch name.', 343 | ]); 344 | }); 345 | 346 | it('should return false 2', async() => { 347 | process.env.INPUT_COMMIT_DISABLED = '0'; 348 | setChildProcessParams({ stdout: 'develop\nfeature/test\n' }); 349 | const mockStdout = spyOnStdout(); 350 | 351 | expect(await commit(octokit, getContext({ 352 | ref: 'refs/tags/test', 353 | repo: { 354 | owner: 'hello', 355 | repo: 'world', 356 | }, 357 | payload: { 358 | repository: { 359 | 'default_branch': 'master', 360 | }, 361 | }, 362 | }), logger)).toBe(false); 363 | 364 | stdoutCalledWith(mockStdout, [ 365 | '::group::Committing...', 366 | '[command]git branch -a --contains test | cut -b 3-', 367 | ' >> develop', 368 | ' >> feature/test', 369 | '> This is not default branch.', 370 | ]); 371 | }); 372 | 373 | it('should call helper commit', async() => { 374 | process.env.INPUT_COMMIT_DISABLED = 'false'; 375 | setChildProcessParams({ stdout: 'master\nfeature/test\n' }); 376 | process.env.INPUT_PACKAGE_DIR = 'src/fixtures'; 377 | process.env.INPUT_PACKAGE_NAME = 'package-test1.json'; 378 | const mockStdout = spyOnStdout(); 379 | const mockEnv = spyOnExportVariable(); 380 | const mockOutput = spyOnSetOutput(); 381 | 382 | nock('https://api.github.com') 383 | .persist() 384 | .post('/repos/hello/world/git/blobs') 385 | .reply(201, () => { 386 | return getApiFixture(path.resolve(__dirname, '..', 'fixtures'), 'repos.git.blobs'); 387 | }) 388 | .get('/repos/hello/world/git/commits/7638417db6d59f3c431d3e1f261cc637155684cd') 389 | .reply(200, () => getApiFixture(path.resolve(__dirname, '..', 'fixtures'), 'repos.git.commits.get')) 390 | .post('/repos/hello/world/git/trees') 391 | .reply(201, () => getApiFixture(path.resolve(__dirname, '..', 'fixtures'), 'repos.git.trees')) 392 | .post('/repos/hello/world/git/commits') 393 | .reply(201, () => getApiFixture(path.resolve(__dirname, '..', 'fixtures'), 'repos.git.commits')) 394 | .patch(`/repos/hello/world/git/refs/${encodeURIComponent('heads/master')}`) 395 | .reply(200, () => getApiFixture(path.resolve(__dirname, '..', 'fixtures'), 'repos.git.refs')); 396 | 397 | expect(await commit(octokit, getContext({ 398 | ref: 'refs/tags/test', 399 | repo: { 400 | owner: 'hello', 401 | repo: 'world', 402 | }, 403 | sha: '7638417db6d59f3c431d3e1f261cc637155684cd', 404 | payload: { 405 | repository: { 406 | 'default_branch': 'master', 407 | }, 408 | }, 409 | }), logger)).toBe(true); 410 | 411 | stdoutCalledWith(mockStdout, [ 412 | '::group::Committing...', 413 | '[command]git branch -a --contains test | cut -b 3-', 414 | ' >> master', 415 | ' >> feature/test', 416 | '::endgroup::', 417 | '::group::Creating blobs...', 418 | '::endgroup::', 419 | '::group::Creating tree...', 420 | '::endgroup::', 421 | '::group::Creating commit... [cd8274d15fa3ae2ab983129fb037999f264ba9a7]', 422 | '::endgroup::', 423 | '::group::Updating ref... [heads/master] [7638417db6d59f3c431d3e1f261cc637155684cd]', 424 | '::endgroup::', 425 | ]); 426 | exportVariableCalledWith(mockEnv, [ 427 | { name: 'GITHUB_SHA', val: '7638417db6d59f3c431d3e1f261cc637155684cd' }, 428 | ]); 429 | setOutputCalledWith(mockOutput, [{ name: 'sha', value: '7638417db6d59f3c431d3e1f261cc637155684cd' }]); 430 | }); 431 | }); 432 | -------------------------------------------------------------------------------- /src/utils/package.ts: -------------------------------------------------------------------------------- 1 | import type { Context } from '@actions/github/lib/context'; 2 | import type { Octokit } from '@technote-space/github-action-helper/dist/types'; 3 | import type { Logger } from '@technote-space/github-action-log-helper'; 4 | import fs from 'fs'; 5 | import { setOutput } from '@actions/core'; 6 | import { ApiHelper, ContextHelper } from '@technote-space/github-action-helper'; 7 | import replaceInFile from 'replace-in-file'; 8 | import { getBranchesByTag } from './command'; 9 | import { 10 | getPackageDir, 11 | getPackageFileName, 12 | getPackagePath, 13 | getPackageVersion, 14 | isRequiredUpdate, 15 | getPackageVersionToUpdate, 16 | getReplaceResultMessages, 17 | getCommitMessage, 18 | getDefaultBranch, 19 | isCommitDisabled, 20 | getTagName, 21 | getBranch, 22 | } from './misc'; 23 | 24 | export const updatePackageVersion = async(context: Context, logger: Logger): Promise => { 25 | logger.startProcess('Updating package version...'); 26 | 27 | const path = getPackagePath(); 28 | if (!fs.existsSync(path)) { 29 | logger.warn(`File [${getPackageFileName()}] not found.`); 30 | logger.warn('Please checkout before call this GitHub Action.'); 31 | return false; 32 | } 33 | 34 | const tagName = getTagName(context); 35 | const current = getPackageVersion(); 36 | logger.info('target version: %s', tagName); 37 | logger.info('current version: %s', current); 38 | 39 | if (!isRequiredUpdate(getPackageVersion(), tagName)) { 40 | logger.info('No need to update.'); 41 | return false; 42 | } 43 | 44 | const version = getPackageVersionToUpdate(tagName); 45 | logger.displayStdout(getReplaceResultMessages(await replaceInFile.replaceInFile({ 46 | files: path, 47 | from: /"version"\s*:\s*"(v?).+?"\s*(,?)$/gm, 48 | to: `"version": "$1${version}"$2`, 49 | }), logger)); 50 | 51 | return true; 52 | }; 53 | 54 | export const getUpdateBranch = async(logger: Logger, context: Context): Promise => { 55 | const tagName = ContextHelper.getTagName(context); 56 | if (tagName) { 57 | const branch = getDefaultBranch(context); 58 | if (undefined === branch) { 59 | logger.warn('Failed to get default branch name.'); 60 | return false; 61 | } 62 | 63 | if (!(await getBranchesByTag(tagName, logger)).includes(branch)) { 64 | logger.info('This is not default branch.'); 65 | return false; 66 | } 67 | 68 | return branch; 69 | } 70 | 71 | return getBranch(context); 72 | }; 73 | 74 | export const commit = async(octokit: Octokit, context: Context, logger: Logger): Promise => { 75 | logger.startProcess('Committing...'); 76 | 77 | if (isCommitDisabled()) { 78 | logger.info('Commit is disabled.'); 79 | return true; 80 | } 81 | 82 | const branch = await getUpdateBranch(logger, context); 83 | if (false === branch) { 84 | return false; 85 | } 86 | 87 | const helper = new ApiHelper(octokit, context, logger, { 88 | refForUpdate: `heads/${branch}`, 89 | suppressBPError: true, 90 | }); 91 | await helper.commit(getPackageDir(), getCommitMessage(), [getPackageFileName()]); 92 | setOutput('sha', process.env.GITHUB_SHA + ''); 93 | return true; 94 | }; 95 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@sindresorhus/tsconfig", 3 | "compilerOptions": { 4 | "outDir": "lib", 5 | "target": "ES2021", 6 | "module": "ES2020", 7 | "lib": [ 8 | "ES2021" 9 | ], 10 | "moduleResolution": "node", 11 | "noPropertyAccessFromIndexSignature": false, 12 | "noImplicitAny": false 13 | }, 14 | "include": [ 15 | "src" 16 | ] 17 | } -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { defineConfig } from 'vite'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | test: { 7 | setupFiles: './src/setup.ts', 8 | clearMocks: true, 9 | mockReset: true, 10 | restoreMocks: true, 11 | coverage: { 12 | reporter: ['html', 'lcov', 'text'], 13 | }, 14 | deps: { 15 | inline: [/github-action-test-helper/, /github-action-helper/] 16 | }, 17 | }, 18 | }); 19 | --------------------------------------------------------------------------------