├── .github └── workflows │ └── publish.yml ├── .gitignore ├── LICENSE ├── README.md ├── action.yml ├── package.json ├── src └── index.ts ├── test └── index.test.ts ├── tsconfig.json └── yarn.lock /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish GitHub Action 2 | on: 3 | push: 4 | branches: 5 | - master 6 | 7 | jobs: 8 | publish: 9 | name: Publish 10 | runs-on: ubuntu-18.04 11 | steps: 12 | - uses: actions/checkout@v1 13 | - uses: dylanvann/publish-github-action@v1 14 | with: 15 | github_token: ${{ secrets.GITHUB_TOKEN }} 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | .DS_Store 3 | node_modules 4 | dist 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Dylan Vann 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 all 13 | 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 THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Check Pull Request Title 2 | 3 | ![Version](https://img.shields.io/github/v/release/dylanvann/check-pull-request-title?style=flat-square) 4 | 5 | A GitHub action that checks that a PR title matches a regex patter. 6 | 7 | Could be used for: 8 | 9 | - Enforcing any commit convention. 10 | - Enforcing including a Jira ticket reference in the title. 11 | - Enforcing using [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/). 12 | 13 | This is intended to be used with the [Autosquash](https://github.com/tibdex/autosquash) action so that squashed commit messages follow a convention. 14 | 15 | # Example Workflow 16 | 17 | ```yml 18 | name: 'Jira Check' 19 | on: 20 | pull_request: 21 | types: 22 | # Check title when opened. 23 | - opened 24 | # Check title when new commits are pushed. 25 | # Required to use as a status check. 26 | - synchronize 27 | 28 | jobs: 29 | publish: 30 | runs-on: ubuntu-18.04 31 | steps: 32 | - uses: actions/checkout@v1 33 | - uses: dylanvann/check-pull-request-title@v1 34 | with: 35 | # Match pull request titles in the form UI-1234 - Message. 36 | pattern: '^UI-\d* - ' 37 | ``` 38 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: Jira Check 2 | description: Check that pull request titles contain a Jira issue. 3 | inputs: 4 | pattern: 5 | description: 'A regex pattern to check if a pull request title is valid.' 6 | required: true 7 | runs: 8 | using: node12 9 | main: dist/index.js 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "check-pull-request-title", 3 | "version": "0.1.14", 4 | "license": "MIT", 5 | "author": "Dylan Vann (https://dylanvann.com)", 6 | "files": [ 7 | "action.yml", 8 | "dist/index.js" 9 | ], 10 | "main": "dist/index.js", 11 | "typings": "dist/index.d.ts", 12 | "scripts": { 13 | "build": "ncc build src/index.ts --minify --v8-cache", 14 | "lint": "tsdx lint", 15 | "test": "tsdx test" 16 | }, 17 | "prettier": { 18 | "printWidth": 80, 19 | "semi": false, 20 | "singleQuote": true, 21 | "trailingComma": "all" 22 | }, 23 | "devDependencies": { 24 | "@actions/core": "^1.2.0", 25 | "@actions/github": "^1.1.0", 26 | "@types/jest": "^24.0.22", 27 | "@zeit/ncc": "^0.20.5", 28 | "tsdx": "^0.11.0", 29 | "tslib": "^1.10.0", 30 | "typescript": "^3.7.2" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import * as core from '@actions/core' 2 | import * as github from '@actions/github' 3 | 4 | function run() { 5 | const pattern = core.getInput('pattern') 6 | const regex = new RegExp(pattern) 7 | const title = 8 | github.context.payload && 9 | github.context.payload.pull_request && 10 | github.context.payload.pull_request.title 11 | core.info(title) 12 | const isValid = regex.test(title) 13 | if (!isValid) { 14 | core.setFailed( 15 | `Pull request title "${title}" does not match regex pattern "${pattern}".`, 16 | ) 17 | } 18 | } 19 | 20 | run() 21 | -------------------------------------------------------------------------------- /test/index.test.ts: -------------------------------------------------------------------------------- 1 | test('it runs', () => { 2 | expect(2 + 2).toBe(4) 3 | }) 4 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["src"], 3 | "compilerOptions": { 4 | "target": "ES2019", 5 | "module": "esnext", 6 | "lib": ["ESNext"], 7 | "importHelpers": true, 8 | "declaration": true, 9 | "sourceMap": true, 10 | "rootDir": "src", 11 | "strict": true, 12 | "noImplicitAny": true, 13 | "skipLibCheck": true, 14 | "strictFunctionTypes": true, 15 | "strictNullChecks": true, 16 | "strictPropertyInitialization": true, 17 | "noImplicitThis": true, 18 | "alwaysStrict": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "noImplicitReturns": true, 22 | "noFallthroughCasesInSwitch": true, 23 | "moduleResolution": "node", 24 | "baseUrl": "./", 25 | "paths": { 26 | "*": ["src/*", "node_modules/*"] 27 | }, 28 | "jsx": "react", 29 | "esModuleInterop": true 30 | } 31 | } 32 | --------------------------------------------------------------------------------