├── .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 │ ├── repos.columns.json │ └── repos.projects.json ├── main.ts ├── process.test.ts ├── process.ts ├── setup.ts └── utils │ ├── card.test.ts │ ├── card.ts │ ├── column.test.ts │ ├── column.ts │ ├── context.test.ts │ ├── context.ts │ ├── misc.test.ts │ ├── misc.ts │ ├── project.test.ts │ └── project.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/create-project-card-action/issues 3 | [fork]: https://github.com/technote-space/create-project-card-action/fork 4 | [pr]: https://github.com/technote-space/create-project-card-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@v1 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@gh-actions 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@gh-actions 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@v1 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 13 * * 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@v1 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 | # Create Project Card Action 2 | 3 | [![CI Status](https://github.com/technote-space/create-project-card-action/workflows/CI/badge.svg)](https://github.com/technote-space/create-project-card-action/actions) 4 | [![codecov](https://codecov.io/gh/technote-space/create-project-card-action/branch/main/graph/badge.svg)](https://codecov.io/gh/technote-space/create-project-card-action) 5 | [![CodeFactor](https://www.codefactor.io/repository/github/technote-space/create-project-card-action/badge)](https://www.codefactor.io/repository/github/technote-space/create-project-card-action) 6 | [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/technote-space/create-project-card-action/blob/main/LICENSE) 7 | 8 | *Read this in other languages: [English](README.md), [日本語](README.ja.md).* 9 | 10 | Project card を作成する `GitHub Actions` です。 11 | 12 | ## Table of Contents 13 | 14 | 15 | 16 |
17 | Details 18 | 19 | - [使用方法](#%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95) 20 | - [オプション](#%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3) 21 | - [Action イベント詳細](#action-%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E8%A9%B3%E7%B4%B0) 22 | - [対象イベント](#%E5%AF%BE%E8%B1%A1%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88) 23 | - [Author](#author) 24 | 25 |
26 | 27 | 28 | ## 使用方法 29 | e.g. issue_opened.yml 30 | ```yaml 31 | on: 32 | issues: 33 | types: [opened] 34 | name: Issue opened 35 | jobs: 36 | assign: 37 | name: Assign issues to project 38 | runs-on: ubuntu-latest 39 | steps: 40 | - name: Assign issues to project 41 | uses: technote-space/create-project-card-action@v1 42 | with: 43 | PROJECT: Backlog 44 | COLUMN: To do 45 | ``` 46 | 47 | e.g. pr-opened.yml 48 | ```yaml 49 | on: 50 | pull_request: 51 | types: [opened] 52 | name: Pull Request opened 53 | jobs: 54 | assignToProject: 55 | name: Assign PullRequest to Project 56 | runs-on: ubuntu-latest 57 | steps: 58 | - name: Assign PullRequest to Project 59 | uses: technote-space/create-project-card-action@v1 60 | with: 61 | PROJECT: Backlog 62 | COLUMN: To do 63 | ``` 64 | 65 | ## オプション 66 | | name | description | default | required | e.g. | 67 | |:---:|:---|:---:|:---:|:---:| 68 | |PROJECT|プロジェクト名| |true|`Backlog`| 69 | |COLUMN|カラム名| |true|`To do`| 70 | |CHECK_ORG_PROJECT|Organizationプロジェクトをチェックするかどうか
このオプションを使用する場合、`admin` へのアクセス許可が必要です。
`secrets.GITHUB_TOKEN` の代わりに Personal access token を使用してください。|false| |`true`| 71 | |CHECK_USER_PROJECT|Userプロジェクトをチェックするかどうか
このオプションを使用する場合、`repo` へのアクセス許可が必要です。
`secrets.GITHUB_TOKEN` の代わりに Personal access token を使用してください。|false| |`true`| 72 | |GITHUB_TOKEN|アクセストークン|`${{github.token}}`|true|`${{secrets.ACCESS_TOKEN}}`| 73 | 74 | ## Action イベント詳細 75 | ### 対象イベント 76 | | eventName | action | 77 | |:---:|:---:| 78 | |pull_request, pull_request_target|opened, reopened| 79 | |issues|opened, reopened| 80 | 81 | ## Author 82 | [GitHub (Technote)](https://github.com/technote-space) 83 | [Blog](https://technote.space) 84 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Create Project Card Action 2 | 3 | [![CI Status](https://github.com/technote-space/create-project-card-action/workflows/CI/badge.svg)](https://github.com/technote-space/create-project-card-action/actions) 4 | [![codecov](https://codecov.io/gh/technote-space/create-project-card-action/branch/main/graph/badge.svg)](https://codecov.io/gh/technote-space/create-project-card-action) 5 | [![CodeFactor](https://www.codefactor.io/repository/github/technote-space/create-project-card-action/badge)](https://www.codefactor.io/repository/github/technote-space/create-project-card-action) 6 | [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/technote-space/create-project-card-action/blob/main/LICENSE) 7 | 8 | *Read this in other languages: [English](README.md), [日本語](README.ja.md).* 9 | 10 | GitHub actions to create project card. 11 | 12 | ## Table of Contents 13 | 14 | 15 | 16 |
17 | Details 18 | 19 | - [Usage](#usage) 20 | - [Options](#options) 21 | - [Action event details](#action-event-details) 22 | - [Target events](#target-events) 23 | - [Author](#author) 24 | 25 |
26 | 27 | 28 | ## Usage 29 | e.g. issue_opened.yml 30 | ```yaml 31 | on: 32 | issues: 33 | types: [opened] 34 | name: Issue opened 35 | jobs: 36 | assign: 37 | name: Assign issues to project 38 | runs-on: ubuntu-latest 39 | steps: 40 | - name: Assign issues to project 41 | uses: technote-space/create-project-card-action@v1 42 | with: 43 | PROJECT: Backlog 44 | COLUMN: To do 45 | ``` 46 | 47 | e.g. pr-opened.yml 48 | ```yaml 49 | on: 50 | pull_request: 51 | types: [opened] 52 | name: Pull Request opened 53 | jobs: 54 | assignToProject: 55 | name: Assign PullRequest to Project 56 | runs-on: ubuntu-latest 57 | steps: 58 | - name: Assign PullRequest to Project 59 | uses: technote-space/create-project-card-action@v1 60 | with: 61 | PROJECT: Backlog 62 | COLUMN: To do 63 | ``` 64 | 65 | ## Options 66 | | name | description | default | required | e.g. | 67 | |:---:|:---|:---:|:---:|:---:| 68 | |PROJECT|Project name| |true|`Backlog`| 69 | |COLUMN|Column name| |true|`To do`| 70 | |CHECK_ORG_PROJECT|Whether to check org project.
If use this option, full access permission for `admin` is required.
Use personal access token instead of `secrets.GITHUB_TOKEN`.|false| |`true`| 71 | |CHECK_USER_PROJECT|Whether to check user project.
If use this option, full access permission for `repo` is required.
Use personal access token instead of `secrets.GITHUB_TOKEN`.|false| |`true`| 72 | |GITHUB_TOKEN|Access token|`${{github.token}}`|true|`${{secrets.ACCESS_TOKEN}}`| 73 | 74 | ## Action event details 75 | ### Target events 76 | | eventName | action | 77 | |:---:|:---:| 78 | |pull_request, pull_request_target|opened, reopened| 79 | |issues|opened, reopened| 80 | 81 | ## Author 82 | [GitHub (Technote)](https://github.com/technote-space) 83 | [Blog](https://technote.space) 84 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-architect 2 | 3 | # Google Analytics 4 | google_analytics: UA-78163306-3 -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: Create Project Card Action 2 | 3 | description: GitHub actions to create project card. 4 | 5 | author: technote-space 6 | 7 | inputs: 8 | GITHUB_TOKEN: 9 | description: Secret GitHub API token to use for making API requests. 10 | default: ${{ github.token }} 11 | required: false 12 | PROJECT: 13 | description: Project name. 14 | required: true 15 | COLUMN: 16 | description: Column name. 17 | required: true 18 | CHECK_ORG_PROJECT: 19 | description: Whether to check org project. 20 | required: false 21 | CHECK_USER_PROJECT: 22 | description: Whether to check org project. 23 | required: false 24 | 25 | branding: 26 | icon: 'file-plus' 27 | color: 'green' 28 | 29 | runs: 30 | using: node16 31 | main: lib/main.js 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@technote-space/create-project-card-action", 3 | "version": "1.4.2", 4 | "description": "GitHub actions to create project card.", 5 | "keywords": [ 6 | "github", 7 | "github actions" 8 | ], 9 | "homepage": "https://github.com/technote-space/create-project-card-action", 10 | "bugs": { 11 | "url": "https://github.com/technote-space/create-project-card-action/issues" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/technote-space/create-project-card-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 | "prepublishOnly": "[ -n \"$CI\" ] || [ ! -f node_modules/.bin/pinst ] || pinst --disable", 34 | "postpublish": "[ -n \"$CI\" ] || [ ! -f node_modules/.bin/pinst ] || pinst --enable", 35 | "release": "yarn release-ga --test", 36 | "test": "yarn lint && yarn typecheck && yarn cover", 37 | "typecheck": "tsc --noEmit", 38 | "update": "npm_config_yes=true npx npm-check-updates -u --timeout 100000 && yarn install && yarn upgrade && yarn audit" 39 | }, 40 | "devDependencies": { 41 | "@actions/core": "^1.10.0", 42 | "@actions/github": "^5.1.1", 43 | "@commitlint/cli": "^17.6.3", 44 | "@commitlint/config-conventional": "^17.6.3", 45 | "@rollup/plugin-commonjs": "^25.0.0", 46 | "@rollup/plugin-json": "^6.0.0", 47 | "@rollup/plugin-node-resolve": "^15.0.2", 48 | "@rollup/plugin-typescript": "^11.1.1", 49 | "@sindresorhus/tsconfig": "^3.0.1", 50 | "@technote-space/filter-github-action": "^0.6.13", 51 | "@technote-space/github-action-helper": "^5.3.17", 52 | "@technote-space/github-action-log-helper": "^0.2.19", 53 | "@technote-space/github-action-test-helper": "^0.11.17", 54 | "@technote-space/release-github-actions-cli": "^1.9.5", 55 | "@types/node": "^20.2.5", 56 | "@typescript-eslint/eslint-plugin": "^5.59.7", 57 | "@typescript-eslint/parser": "^5.59.7", 58 | "@vitest/coverage-c8": "^0.31.1", 59 | "eslint": "^8.41.0", 60 | "eslint-plugin-import": "^2.27.5", 61 | "husky": "^8.0.3", 62 | "lint-staged": "^13.2.2", 63 | "nock": "^13.3.1", 64 | "pinst": "^3.0.0", 65 | "rollup": "^3.23.0", 66 | "typescript": "^5.0.4", 67 | "vitest": "^0.31.1" 68 | }, 69 | "publishConfig": { 70 | "access": "public" 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /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 | export const TARGET_EVENTS = { 2 | 'issues': ['opened', 'reopened'], 3 | 'pull_request': ['opened', 'reopened'], 4 | }; 5 | export const SLEEP = 800; 6 | -------------------------------------------------------------------------------- /src/fixtures/repos.columns.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "url": "https://api.github.com/projects/columns/367", 4 | "project_url": "https://api.github.com/projects/120", 5 | "cards_url": "https://api.github.com/projects/columns/367/cards", 6 | "id": 345, 7 | "node_id": "MDEzOlByb2plY3RDb2x1bW4zNjc=", 8 | "name": "Test", 9 | "created_at": "2016-09-05T14:18:44Z", 10 | "updated_at": "2016-09-05T14:22:28Z" 11 | }, 12 | { 13 | "url": "https://api.github.com/projects/columns/367", 14 | "project_url": "https://api.github.com/projects/120", 15 | "cards_url": "https://api.github.com/projects/columns/367/cards", 16 | "id": 456, 17 | "node_id": "MDEzOlByb2plY3RDb2x1bW4zNjc=", 18 | "name": "To do", 19 | "created_at": "2016-09-05T14:18:44Z", 20 | "updated_at": "2016-09-05T14:22:28Z" 21 | } 22 | ] 23 | -------------------------------------------------------------------------------- /src/fixtures/repos.projects.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "owner_url": "https://api.github.com/repos/api-playground/projects-test", 4 | "url": "https://api.github.com/projects/1002604", 5 | "html_url": "https://github.com/api-playground/projects-test/projects/1", 6 | "columns_url": "https://api.github.com/projects/1002604/columns", 7 | "id": 123, 8 | "node_id": "MDc6UHJvamVjdDEwMDI2MDQ=", 9 | "name": "Test", 10 | "body": "Developer documentation project for the developer site.", 11 | "number": 1, 12 | "state": "open", 13 | "creator": { 14 | "login": "octocat", 15 | "id": 1, 16 | "node_id": "MDQ6VXNlcjE=", 17 | "avatar_url": "https://github.com/images/error/octocat_happy.gif", 18 | "gravatar_id": "", 19 | "url": "https://api.github.com/users/octocat", 20 | "html_url": "https://github.com/octocat", 21 | "followers_url": "https://api.github.com/users/octocat/followers", 22 | "following_url": "https://api.github.com/users/octocat/following{/other_user}", 23 | "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", 24 | "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", 25 | "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", 26 | "organizations_url": "https://api.github.com/users/octocat/orgs", 27 | "repos_url": "https://api.github.com/users/octocat/repos", 28 | "events_url": "https://api.github.com/users/octocat/events{/privacy}", 29 | "received_events_url": "https://api.github.com/users/octocat/received_events", 30 | "type": "User", 31 | "site_admin": false 32 | }, 33 | "created_at": "2011-04-10T20:09:31Z", 34 | "updated_at": "2014-03-03T18:58:10Z" 35 | }, 36 | { 37 | "owner_url": "https://api.github.com/repos/api-playground/projects-test", 38 | "url": "https://api.github.com/projects/1002604", 39 | "html_url": "https://github.com/api-playground/projects-test/projects/1", 40 | "columns_url": "https://api.github.com/projects/1002604/columns", 41 | "id": 234, 42 | "node_id": "MDc6UHJvamVjdDEwMDI2MDQ=", 43 | "name": "Backlog", 44 | "body": "Developer documentation project for the developer site.", 45 | "number": 2, 46 | "state": "open", 47 | "creator": { 48 | "login": "octocat", 49 | "id": 1, 50 | "node_id": "MDQ6VXNlcjE=", 51 | "avatar_url": "https://github.com/images/error/octocat_happy.gif", 52 | "gravatar_id": "", 53 | "url": "https://api.github.com/users/octocat", 54 | "html_url": "https://github.com/octocat", 55 | "followers_url": "https://api.github.com/users/octocat/followers", 56 | "following_url": "https://api.github.com/users/octocat/following{/other_user}", 57 | "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", 58 | "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", 59 | "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", 60 | "organizations_url": "https://api.github.com/users/octocat/orgs", 61 | "repos_url": "https://api.github.com/users/octocat/repos", 62 | "events_url": "https://api.github.com/users/octocat/events{/privacy}", 63 | "received_events_url": "https://api.github.com/users/octocat/received_events", 64 | "type": "User", 65 | "site_admin": false 66 | }, 67 | "created_at": "2011-04-10T20:09:31Z", 68 | "updated_at": "2014-03-03T18:58:10Z" 69 | } 70 | ] 71 | -------------------------------------------------------------------------------- /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 { execute } from './process'; 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 | await execute(logger, Utils.getOctokit(), context); 21 | }; 22 | 23 | run().catch(error => { 24 | console.log(error); 25 | setFailed(error.message); 26 | }); 27 | -------------------------------------------------------------------------------- /src/process.test.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-magic-numbers */ 2 | import path from 'path'; 3 | import { Context } from '@actions/github/lib/context'; 4 | import { Logger } from '@technote-space/github-action-log-helper'; 5 | import { testEnv, disableNetConnect, getApiFixture, generateContext, getOctokit } from '@technote-space/github-action-test-helper'; 6 | import nock from 'nock'; 7 | import { describe, expect, it } from 'vitest'; 8 | import { execute } from './process'; 9 | 10 | const rootDir = path.resolve(__dirname, '..'); 11 | const fixturesDir = path.resolve(__dirname, 'fixtures'); 12 | const logger = new Logger(); 13 | const octokit = getOctokit(); 14 | const getContext = (payload = {}): Context => generateContext({ 15 | event: 'pull_request', 16 | action: 'opened', 17 | owner: 'hello', 18 | repo: 'world', 19 | }, { 20 | payload, 21 | }); 22 | 23 | describe('execute', () => { 24 | testEnv(rootDir); 25 | disableNetConnect(nock); 26 | 27 | it('should return false 1', async() => { 28 | process.env.INPUT_PROJECT = 'Backlog'; 29 | process.env.INPUT_COLUMN = 'To do'; 30 | expect(await execute(logger, octokit, getContext())).toBe(false); 31 | }); 32 | 33 | it('should return false 2', async() => { 34 | process.env.INPUT_PROJECT = 'Backlog'; 35 | process.env.INPUT_COLUMN = 'To do'; 36 | nock('https://api.github.com') 37 | .persist() 38 | .get('/repos/hello/world/projects?state=open') 39 | .reply(200, getApiFixture(fixturesDir, 'repos.projects')) 40 | .get('/projects/234/columns') 41 | .reply(200, () => []); 42 | 43 | expect(await execute(logger, octokit, getContext({ 44 | repository: { 'has_projects': true }, 45 | }))).toBe(false); 46 | }); 47 | 48 | it('should return true', async() => { 49 | process.env.INPUT_PROJECT = 'Backlog'; 50 | process.env.INPUT_COLUMN = 'To do'; 51 | nock('https://api.github.com') 52 | .persist() 53 | .get('/repos/hello/world/projects?state=open') 54 | .reply(200, getApiFixture(fixturesDir, 'repos.projects')) 55 | .get('/projects/234/columns') 56 | .reply(200, getApiFixture(fixturesDir, 'repos.columns')) 57 | .post('/projects/columns/456/cards') 58 | .reply(201); 59 | 60 | expect(await execute(logger, octokit, getContext({ 61 | repository: { 'has_projects': true }, 62 | }))).toBe(true); 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /src/process.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 { createCards } from './utils/card'; 5 | import { getColumnIds } from './utils/column'; 6 | import { getContentId, getContentType } from './utils/context'; 7 | import { getProjectName, getColumnName } from './utils/misc'; 8 | import { getProjectIds } from './utils/project'; 9 | 10 | export const execute = async(logger: Logger, octokit: Octokit, context: Context): Promise => { 11 | const projectName = getProjectName(); 12 | const columnName = getColumnName(); 13 | logger.startProcess('project: %s, column: %s', projectName, columnName); 14 | 15 | logger.startProcess('Getting target projects...'); 16 | const projectIds = await getProjectIds(projectName, octokit, context); 17 | if (projectIds.length) { 18 | console.log(projectIds); 19 | } else { 20 | logger.warn('There are no target projects.'); 21 | return false; 22 | } 23 | 24 | logger.startProcess('Getting target columns...'); 25 | const columnIds = await getColumnIds(projectIds, columnName, octokit); 26 | if (columnIds.length) { 27 | console.log(columnIds); 28 | } else { 29 | logger.warn('There are no target columns.'); 30 | return false; 31 | } 32 | 33 | logger.startProcess('Creating cards...'); 34 | const results = await createCards(columnIds, getContentId(context), getContentType(context), logger, octokit); 35 | console.log(results); 36 | 37 | return true; 38 | }; 39 | -------------------------------------------------------------------------------- /src/setup.ts: -------------------------------------------------------------------------------- 1 | import { setupGlobal } from '@technote-space/github-action-test-helper'; 2 | import { vi } from 'vitest'; 3 | 4 | setupGlobal(); 5 | 6 | vi.mock('./constant', async() => ({ 7 | ...await vi.importActual<{ SLEEP: number }>('./constant'), 8 | SLEEP: 0, 9 | })); 10 | -------------------------------------------------------------------------------- /src/utils/card.test.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-magic-numbers */ 2 | import { Logger } from '@technote-space/github-action-log-helper'; 3 | import { disableNetConnect, getOctokit, spyOnStdout, stdoutCalledWith } from '@technote-space/github-action-test-helper'; 4 | import nock from 'nock'; 5 | import { describe, expect, it } from 'vitest'; 6 | import { createCards } from './card'; 7 | 8 | const logger = new Logger(); 9 | const octokit = getOctokit(); 10 | 11 | describe('createCards', () => { 12 | disableNetConnect(nock); 13 | 14 | it('should get column ids', async() => { 15 | const mockStdout = spyOnStdout(); 16 | nock('https://api.github.com') 17 | .persist() 18 | .post('/projects/columns/1/cards') 19 | .reply(422, () => 'test1') 20 | .post('/projects/columns/2/cards') 21 | .reply(201) 22 | .post('/projects/columns/3/cards') 23 | .reply(422, () => 'test2'); 24 | 25 | expect(await createCards([1, 2, 3], 123, 'PullRequest', logger, octokit)).toEqual({ 26 | total: 3, 27 | succeeded: 1, 28 | failed: 2, 29 | }); 30 | 31 | stdoutCalledWith(mockStdout, [ 32 | '::warning::test1', 33 | '::warning::test2', 34 | ]); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /src/utils/card.ts: -------------------------------------------------------------------------------- 1 | import type { Octokit } from '@technote-space/github-action-helper/dist/types'; 2 | import type { Logger } from '@technote-space/github-action-log-helper'; 3 | import { Utils } from '@technote-space/github-action-helper'; 4 | import { SLEEP } from '../constant'; 5 | 6 | const createCard = async(columnId: number, contentId: number, contentType: string, logger: Logger, octokit: Octokit): Promise => { 7 | try { 8 | await octokit.rest.projects.createCard({ 9 | 'column_id': columnId, 10 | 'content_id': contentId, 11 | 'content_type': contentType, 12 | }); 13 | } catch (error: any) { // eslint-disable-line @typescript-eslint/no-explicit-any 14 | logger.warn(error.message); 15 | return false; 16 | } finally { 17 | await Utils.sleep(SLEEP); 18 | } 19 | 20 | return true; 21 | }; 22 | 23 | export const createCards = async(columnIds: Array, contentId: number, contentType: string, logger: Logger, octokit: Octokit): Promise<{ total: number; succeeded: number; failed: number }> => { 24 | const results: Array = []; 25 | for (const columnId of columnIds) { 26 | results.push(await createCard(columnId, contentId, contentType, logger, octokit)); 27 | } 28 | 29 | return { 30 | total: results.length, 31 | succeeded: results.filter(result => result).length, 32 | failed: results.filter(result => !result).length, 33 | }; 34 | }; 35 | -------------------------------------------------------------------------------- /src/utils/column.test.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-magic-numbers */ 2 | import path from 'path'; 3 | import { disableNetConnect, getApiFixture, getOctokit } from '@technote-space/github-action-test-helper'; 4 | import nock from 'nock'; 5 | import { describe, expect, it } from 'vitest'; 6 | import { getColumnIds } from './column'; 7 | 8 | const fixturesDir = path.resolve(__dirname, '../fixtures'); 9 | const octokit = getOctokit(); 10 | 11 | describe('getColumnIds', () => { 12 | disableNetConnect(nock); 13 | 14 | it('should get column ids', async() => { 15 | nock('https://api.github.com') 16 | .persist() 17 | .get('/projects/1/columns') 18 | .reply(200, getApiFixture(fixturesDir, 'repos.columns')) 19 | .get('/projects/2/columns') 20 | .reply(200, () => []) 21 | .get('/projects/3/columns') 22 | .reply(200, () => []); 23 | 24 | expect(await getColumnIds([1, 2, 3], 'To do', octokit)).toEqual([456]); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /src/utils/column.ts: -------------------------------------------------------------------------------- 1 | import type { Octokit } from '@technote-space/github-action-helper/dist/types'; 2 | import { Utils } from '@technote-space/github-action-helper'; 3 | import { SLEEP } from '../constant'; 4 | 5 | export const getColumnIds = async(projectIds: Array, columnName: string, octokit: Octokit): Promise> => { 6 | const columnIds: Array = []; 7 | for (const projectId of projectIds) { 8 | const columnId = (await octokit.paginate( 9 | octokit.rest.projects.listColumns, 10 | { 'project_id': projectId }, 11 | )).find(item => item.name === columnName)?.id; 12 | if (undefined !== columnId) { 13 | columnIds.push(columnId); 14 | } 15 | await Utils.sleep(SLEEP); 16 | } 17 | 18 | return columnIds; 19 | }; 20 | -------------------------------------------------------------------------------- /src/utils/context.test.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-magic-numbers */ 2 | import { Context } from '@actions/github/lib/context'; 3 | import { generateContext } from '@technote-space/github-action-test-helper'; 4 | import { describe, expect, it } from 'vitest'; 5 | import { getContentId, getContentType } from './context'; 6 | 7 | const getContext = (event: string, payload = {}): Context => generateContext({ 8 | event, 9 | action: 'opened', 10 | owner: 'hello', 11 | repo: 'world', 12 | }, { 13 | payload, 14 | }); 15 | 16 | describe('getContentId', () => { 17 | it('should get pr id', () => { 18 | expect(getContentId(getContext('pull_request', { 19 | 'pull_request': { 20 | id: 123, 21 | }, 22 | }))).toBe(123); 23 | }); 24 | 25 | it('should get issue id', () => { 26 | expect(getContentId(getContext('issues', { 27 | issue: { 28 | id: 123, 29 | }, 30 | }))).toBe(123); 31 | }); 32 | 33 | it('should not get content id', () => { 34 | expect(getContentId(getContext('push'))).toBe(0); 35 | expect(getContentId(getContext('pull_request'))).toBe(0); 36 | }); 37 | }); 38 | 39 | describe('getContentType', () => { 40 | it('should return PullRequest', () => { 41 | expect(getContentType(getContext('pull_request', { 42 | 'pull_request': { 43 | id: 123, 44 | }, 45 | }))).toBe('PullRequest'); 46 | }); 47 | 48 | it('should return Issue', () => { 49 | expect(getContentType(getContext('issues', { 50 | issue: { 51 | id: 123, 52 | }, 53 | }))).toBe('Issue'); 54 | expect(getContentType(getContext('issues'))).toBe('Issue'); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /src/utils/context.ts: -------------------------------------------------------------------------------- 1 | import type { Context } from '@actions/github/lib/context'; 2 | import { ContextHelper } from '@technote-space/github-action-helper'; 3 | 4 | // eslint-disable-next-line no-magic-numbers 5 | export const getContentId = (context: Context): number => (ContextHelper.isPr(context) ? context.payload.pull_request?.id : context.payload.issue?.id) ?? 0; 6 | 7 | export const getContentType = (context: Context): string => ContextHelper.isPr(context) ? 'PullRequest' : 'Issue'; 8 | -------------------------------------------------------------------------------- /src/utils/misc.test.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-magic-numbers */ 2 | import path from 'path'; 3 | import { testEnv } from '@technote-space/github-action-test-helper'; 4 | import { describe, expect, it } from 'vitest'; 5 | import { getProjectName, getColumnName, isActive } from './misc'; 6 | 7 | const rootDir = path.resolve(__dirname, '../..'); 8 | 9 | describe('getProjectName', () => { 10 | testEnv(rootDir); 11 | 12 | it('should return project name', () => { 13 | process.env.INPUT_PROJECT = 'Backlog'; 14 | expect(getProjectName()).toBe('Backlog'); 15 | }); 16 | 17 | it('should throw error', () => { 18 | expect(() => getProjectName()).toThrow(); 19 | }); 20 | }); 21 | 22 | describe('getColumnName', () => { 23 | testEnv(rootDir); 24 | 25 | it('should return column name', () => { 26 | process.env.INPUT_COLUMN = 'To do'; 27 | expect(getColumnName()).toBe('To do'); 28 | }); 29 | 30 | it('should throw error', () => { 31 | expect(() => getColumnName()).toThrow(); 32 | }); 33 | }); 34 | 35 | describe('isActive', () => { 36 | testEnv(rootDir); 37 | 38 | it('should return true 1', () => { 39 | process.env.INPUT_CHECK_ORG_PROJECT = 'true'; 40 | expect(isActive('ORG')).toBe(true); 41 | }); 42 | 43 | it('should return true 2', () => { 44 | process.env.INPUT_CHECK_USER_PROJECT = '1'; 45 | expect(isActive('USER')).toBe(true); 46 | }); 47 | 48 | it('should return false 1', () => { 49 | expect(isActive('ORG')).toBe(false); 50 | }); 51 | 52 | it('should return false 2', () => { 53 | process.env.INPUT_CHECK_ORG_PROJECT = 'false'; 54 | expect(isActive('ORG')).toBe(false); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /src/utils/misc.ts: -------------------------------------------------------------------------------- 1 | import { getInput } from '@actions/core' ; 2 | import { Utils } from '@technote-space/github-action-helper'; 3 | 4 | export const getProjectName = (): string => getInput('PROJECT', { required: true }); 5 | export const getColumnName = (): string => getInput('COLUMN', { required: true }); 6 | export const isActive = (target: string): boolean => Utils.getBoolValue(getInput(`CHECK_${target}_PROJECT`)); 7 | -------------------------------------------------------------------------------- /src/utils/project.test.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-magic-numbers */ 2 | import path from 'path'; 3 | import { Context } from '@actions/github/lib/context'; 4 | import { testEnv, disableNetConnect, getApiFixture, generateContext, getOctokit } from '@technote-space/github-action-test-helper'; 5 | import nock from 'nock'; 6 | import { describe, expect, it } from 'vitest'; 7 | import { getRepoProject, getOrgProject, getUserProject, getProjectIds } from './project'; 8 | 9 | const fixturesDir = path.resolve(__dirname, '../fixtures'); 10 | const octokit = getOctokit(); 11 | const getContext = (payload = {}): Context => generateContext({ 12 | event: 'pull_request', 13 | action: 'opened', 14 | owner: 'hello', 15 | repo: 'world', 16 | }, { 17 | payload, 18 | }); 19 | 20 | describe('getRepoProject', () => { 21 | disableNetConnect(nock); 22 | 23 | it('should return undefined 1', async() => { 24 | expect(await getRepoProject('Backlog', octokit, getContext())).toBeUndefined(); 25 | }); 26 | 27 | it('should return undefined 2', async() => { 28 | expect(await getRepoProject('Backlog', octokit, getContext({ 29 | repository: { 'has_projects': false }, 30 | }))).toBeUndefined(); 31 | }); 32 | 33 | it('should return undefined 3', async() => { 34 | nock('https://api.github.com') 35 | .persist() 36 | .get('/repos/hello/world/projects?state=open') 37 | .reply(200, getApiFixture(fixturesDir, 'repos.projects')); 38 | 39 | expect(await getRepoProject('abc', octokit, getContext({ 40 | repository: { 'has_projects': true }, 41 | }))).toBeUndefined(); 42 | }); 43 | 44 | it('should return repo project', async() => { 45 | nock('https://api.github.com') 46 | .persist() 47 | .get('/repos/hello/world/projects?state=open') 48 | .reply(200, getApiFixture(fixturesDir, 'repos.projects')); 49 | 50 | expect(await getRepoProject('Backlog', octokit, getContext({ 51 | repository: { 'has_projects': true }, 52 | }))).toBe(234); 53 | }); 54 | }); 55 | 56 | describe('getOrgProject', () => { 57 | testEnv(); 58 | disableNetConnect(nock); 59 | 60 | it('should return undefined 1', async() => { 61 | expect(await getOrgProject('Backlog', octokit, getContext())).toBeUndefined(); 62 | }); 63 | 64 | it('should return undefined 2', async() => { 65 | process.env.INPUT_CHECK_ORG_PROJECT = 'true'; 66 | expect(await getOrgProject('Backlog', octokit, getContext())).toBeUndefined(); 67 | }); 68 | 69 | it('should return undefined 3', async() => { 70 | process.env.INPUT_CHECK_ORG_PROJECT = 'true'; 71 | nock('https://api.github.com') 72 | .persist() 73 | .get('/orgs/hello/projects?state=open') 74 | .reply(200, getApiFixture(fixturesDir, 'repos.projects')); 75 | 76 | expect(await getOrgProject('abc', octokit, getContext({ 77 | organization: {}, 78 | }))).toBeUndefined(); 79 | }); 80 | 81 | it('should return org project', async() => { 82 | process.env.INPUT_CHECK_ORG_PROJECT = 'true'; 83 | nock('https://api.github.com') 84 | .persist() 85 | .get('/orgs/hello/projects?state=open') 86 | .reply(200, getApiFixture(fixturesDir, 'repos.projects')); 87 | 88 | expect(await getOrgProject('Backlog', octokit, getContext({ 89 | organization: {}, 90 | }))).toBe(234); 91 | }); 92 | }); 93 | 94 | describe('getUserProject', () => { 95 | testEnv(); 96 | disableNetConnect(nock); 97 | 98 | it('should return undefined 1', async() => { 99 | expect(await getUserProject('Backlog', octokit, getContext())).toBeUndefined(); 100 | }); 101 | 102 | it('should return undefined 2', async() => { 103 | process.env.INPUT_CHECK_USER_PROJECT = 'true'; 104 | expect(await getUserProject('Backlog', octokit, getContext({ 105 | organization: {}, 106 | }))).toBeUndefined(); 107 | }); 108 | 109 | it('should return undefined 3', async() => { 110 | process.env.INPUT_CHECK_USER_PROJECT = 'true'; 111 | nock('https://api.github.com') 112 | .persist() 113 | .get('/users/hello/projects?state=open') 114 | .reply(200, getApiFixture(fixturesDir, 'repos.projects')); 115 | 116 | expect(await getUserProject('abc', octokit, getContext())).toBeUndefined(); 117 | }); 118 | 119 | it('should return user project', async() => { 120 | process.env.INPUT_CHECK_USER_PROJECT = 'true'; 121 | nock('https://api.github.com') 122 | .persist() 123 | .get('/users/hello/projects?state=open') 124 | .reply(200, getApiFixture(fixturesDir, 'repos.projects')); 125 | 126 | expect(await getUserProject('Backlog', octokit, getContext())).toBe(234); 127 | }); 128 | }); 129 | 130 | describe('getProjectIds', () => { 131 | testEnv(); 132 | disableNetConnect(nock); 133 | 134 | it('should get project ids', async() => { 135 | process.env.INPUT_CHECK_ORG_PROJECT = 'true'; 136 | nock('https://api.github.com') 137 | .persist() 138 | .get('/orgs/hello/projects?state=open') 139 | .reply(200, getApiFixture(fixturesDir, 'repos.projects')); 140 | 141 | expect(await getProjectIds('Backlog', octokit, getContext({ 142 | organization: {}, 143 | }))).toEqual([234]); 144 | }); 145 | }); 146 | -------------------------------------------------------------------------------- /src/utils/project.ts: -------------------------------------------------------------------------------- 1 | import type { Context } from '@actions/github/lib/context'; 2 | import type { Octokit } from '@technote-space/github-action-helper/dist/types'; 3 | import { isActive } from './misc'; 4 | 5 | // eslint-disable-next-line camelcase 6 | export const getRepoProject = async(projectName: string, octokit: Octokit, context: Context): Promise => context.payload.repository?.has_projects ? (await octokit.paginate( 7 | octokit.rest.projects.listForRepo, 8 | { ...context.repo, state: 'open' }, 9 | )).find(item => item.name === projectName)?.id : undefined; 10 | 11 | export const getOrgProject = async(projectName: string, octokit: Octokit, context: Context): Promise => isActive('ORG') && 'organization' in context.payload ? (await octokit.paginate( 12 | octokit.rest.projects.listForOrg, 13 | { org: context.repo.owner, state: 'open' }, 14 | )).find(item => item.name === projectName)?.id : undefined; 15 | 16 | export const getUserProject = async(projectName: string, octokit: Octokit, context: Context): Promise => isActive('USER') && !('organization' in context.payload) ? (await octokit.paginate( 17 | octokit.rest.projects.listForUser, 18 | { username: context.repo.owner, state: 'open' }, 19 | )).find(item => item.name === projectName)?.id : undefined; 20 | 21 | export const getProjectIds = async(projectName: string, octokit: Octokit, context: Context): Promise> => { 22 | const projectIds: Array = []; 23 | for (const generator of [getRepoProject, getOrgProject, getUserProject]) { 24 | const projectId = await generator(projectName, octokit, context); 25 | if (undefined !== projectId) { 26 | projectIds.push(projectId); 27 | } 28 | } 29 | 30 | return projectIds; 31 | }; 32 | -------------------------------------------------------------------------------- /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/] 16 | }, 17 | }, 18 | }); 19 | --------------------------------------------------------------------------------