├── .github ├── FUNDING.yml ├── dependabot.yml └── workflows │ ├── codeql.yml │ ├── lint.yml │ └── reject-collab-approvers.yml ├── .gitignore ├── .prettierrc ├── LICENSE ├── README.md ├── action.yml ├── dist └── index.js ├── package-lock.json ├── package.json ├── src └── main.ts └── tsconfig.json /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: peckjon 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | updates: 4 | - package-ecosystem: "npm" 5 | directory: "/" 6 | schedule: 7 | interval: "weekly" 8 | ignore: 9 | - dependency-name: "@types/node" 10 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ "master" ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ "master" ] 20 | schedule: 21 | - cron: '19 14 * * 6' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'javascript' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v3 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v2 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | 52 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 53 | # queries: security-extended,security-and-quality 54 | 55 | 56 | # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). 57 | # If this step fails, then you should remove it and run the build manually (see below) 58 | - name: Autobuild 59 | uses: github/codeql-action/autobuild@v2 60 | 61 | # ℹ️ Command-line programs to run using the OS shell. 62 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 63 | 64 | # If the Autobuild fails above, remove it and uncomment the following three lines. 65 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 66 | 67 | # - run: | 68 | # echo "Run, Build Application using script" 69 | # ./location_of_script_within_repo/buildscript.sh 70 | 71 | - name: Perform CodeQL Analysis 72 | uses: github/codeql-action/analyze@v2 73 | with: 74 | category: "/language:${{matrix.language}}" 75 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | on: [push] 3 | 4 | jobs: 5 | build: 6 | name: Check style 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Check out code 10 | uses: actions/checkout@v1 11 | 12 | - uses: actions/setup-node@v1 13 | with: 14 | node-version: '12.10.*' 15 | 16 | - name: Install dependencies 17 | run: npm ci 18 | 19 | - name: Check style with prettier 20 | run: npm run format-check 21 | 22 | - name: Check build artefact has been checked in 23 | run: npm run build && git diff --quiet 24 | -------------------------------------------------------------------------------- /.github/workflows/reject-collab-approvers.yml: -------------------------------------------------------------------------------- 1 | name: Dismiss code reviews from collaborators 2 | 3 | on: 4 | pull_request_review: 5 | types: [submitted] 6 | 7 | jobs: 8 | approver-vibe-check: 9 | name: Dismiss code reviews from collaborators 10 | runs-on: ubuntu-latest 11 | if: github.event.review.state == 'approved' 12 | steps: 13 | - name: Dismiss code reviews from collaborators 14 | uses: peckjon/reject-pr-approval-from-committer@master 15 | with: 16 | github-token: ${{ secrets.GITHUB_TOKEN }} 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "singleQuote": true 4 | } 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-2024 Jon Peck, Natalie Somersall, James Hu, Cognite AS, Harry Marr 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GitHub Action: do not allow committers on a Pull Request to approve the PR 2 | 3 | While GitHub prevents self-approval of PRs, it doesn't prevent a user from approving a PR they worked on. In some scenarios, this could allow for PRs to be approved with no outside review. 4 | 5 | This action prevents any committers on a Pull Request from approving the PR. It can be used standalone (e.g. triggered by on all submitted Pull Requests in a repo), or as a Required Status Check. 6 | 7 | ## Usage instructions 8 | 9 | Create a workflow file (e.g. `.github/workflows/reject-self-approve.yml`) that contains a step 10 | that has `uses: peckjon/reject-pr-approval-from-committer`. 11 | 12 | The workflow using this action is supposed to be triggered by `pull_request` or `pull_request_target` event. 13 | 14 | Here's an example workflow file: 15 | 16 | ```yaml 17 | name: Prevent committers from approving a PR 18 | 19 | on: 20 | pull_request_review: 21 | types: [submitted] 22 | 23 | jobs: 24 | preventapprove: 25 | name: reject PR approval by committers to the PR 26 | runs-on: ubuntu-latest 27 | if: github.event.review.state == 'approved' 28 | steps: 29 | - name: Dismiss code reviews from collaborators 30 | uses: peckjon/reject-pr-approval-from-committer@master 31 | with: 32 | github-token: ${{ secrets.GITHUB_TOKEN }} 33 | ``` 34 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: 'Dismiss code reviews from collaborators' 2 | description: 'Dismiss code reviews on pull requests from anyone worked on it.' 3 | branding: 4 | icon: 'thumbs-down' 5 | color: 'red' 6 | author: 'peckjon' 7 | inputs: 8 | github-token: 9 | description: 'The GITHUB_TOKEN secret or PAT' 10 | required: true 11 | runs: 12 | using: 'node12' 13 | main: 'dist/index.js' 14 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@peckjon/reject-pr-approval-from-committer", 3 | "version": "1.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "@peckjon/reject-pr-approval-from-committer", 9 | "version": "1.0.0", 10 | "license": "MIT", 11 | "dependencies": { 12 | "@actions/core": "^1.9.1", 13 | "@actions/github": "^5.1.0" 14 | }, 15 | "devDependencies": { 16 | "@types/node": "^14.0.1", 17 | "@zeit/ncc": "^0.22.3", 18 | "prettier": "^2.7.1", 19 | "typescript": "^4.8.3" 20 | } 21 | }, 22 | "node_modules/@actions/core": { 23 | "version": "1.9.1", 24 | "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz", 25 | "integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==", 26 | "dependencies": { 27 | "@actions/http-client": "^2.0.1", 28 | "uuid": "^8.3.2" 29 | } 30 | }, 31 | "node_modules/@actions/github": { 32 | "version": "5.1.0", 33 | "resolved": "https://registry.npmjs.org/@actions/github/-/github-5.1.0.tgz", 34 | "integrity": "sha512-tuI80F7JQIhg77ZTTgUAPpVD7ZnP9oHSPN8xw7LOwtA4vEMbAjWJNbmLBfV7xua7r016GyjzWLuec5cs8f/a8A==", 35 | "dependencies": { 36 | "@actions/http-client": "^2.0.1", 37 | "@octokit/core": "^3.6.0", 38 | "@octokit/plugin-paginate-rest": "^2.17.0", 39 | "@octokit/plugin-rest-endpoint-methods": "^5.13.0" 40 | } 41 | }, 42 | "node_modules/@actions/http-client": { 43 | "version": "2.0.1", 44 | "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz", 45 | "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==", 46 | "dependencies": { 47 | "tunnel": "^0.0.6" 48 | } 49 | }, 50 | "node_modules/@octokit/auth-token": { 51 | "version": "2.5.0", 52 | "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", 53 | "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", 54 | "dependencies": { 55 | "@octokit/types": "^6.0.3" 56 | } 57 | }, 58 | "node_modules/@octokit/core": { 59 | "version": "3.6.0", 60 | "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz", 61 | "integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==", 62 | "dependencies": { 63 | "@octokit/auth-token": "^2.4.4", 64 | "@octokit/graphql": "^4.5.8", 65 | "@octokit/request": "^5.6.3", 66 | "@octokit/request-error": "^2.0.5", 67 | "@octokit/types": "^6.0.3", 68 | "before-after-hook": "^2.2.0", 69 | "universal-user-agent": "^6.0.0" 70 | } 71 | }, 72 | "node_modules/@octokit/endpoint": { 73 | "version": "6.0.12", 74 | "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz", 75 | "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==", 76 | "dependencies": { 77 | "@octokit/types": "^6.0.3", 78 | "is-plain-object": "^5.0.0", 79 | "universal-user-agent": "^6.0.0" 80 | } 81 | }, 82 | "node_modules/@octokit/graphql": { 83 | "version": "4.8.0", 84 | "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz", 85 | "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==", 86 | "dependencies": { 87 | "@octokit/request": "^5.6.0", 88 | "@octokit/types": "^6.0.3", 89 | "universal-user-agent": "^6.0.0" 90 | } 91 | }, 92 | "node_modules/@octokit/openapi-types": { 93 | "version": "11.2.0", 94 | "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.2.0.tgz", 95 | "integrity": "sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA==" 96 | }, 97 | "node_modules/@octokit/plugin-paginate-rest": { 98 | "version": "2.17.0", 99 | "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.17.0.tgz", 100 | "integrity": "sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw==", 101 | "dependencies": { 102 | "@octokit/types": "^6.34.0" 103 | }, 104 | "peerDependencies": { 105 | "@octokit/core": ">=2" 106 | } 107 | }, 108 | "node_modules/@octokit/plugin-rest-endpoint-methods": { 109 | "version": "5.13.0", 110 | "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.13.0.tgz", 111 | "integrity": "sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA==", 112 | "dependencies": { 113 | "@octokit/types": "^6.34.0", 114 | "deprecation": "^2.3.1" 115 | }, 116 | "peerDependencies": { 117 | "@octokit/core": ">=3" 118 | } 119 | }, 120 | "node_modules/@octokit/request": { 121 | "version": "5.6.3", 122 | "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz", 123 | "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==", 124 | "dependencies": { 125 | "@octokit/endpoint": "^6.0.1", 126 | "@octokit/request-error": "^2.1.0", 127 | "@octokit/types": "^6.16.1", 128 | "is-plain-object": "^5.0.0", 129 | "node-fetch": "^2.6.7", 130 | "universal-user-agent": "^6.0.0" 131 | } 132 | }, 133 | "node_modules/@octokit/request-error": { 134 | "version": "2.1.0", 135 | "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz", 136 | "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==", 137 | "dependencies": { 138 | "@octokit/types": "^6.0.3", 139 | "deprecation": "^2.0.0", 140 | "once": "^1.4.0" 141 | } 142 | }, 143 | "node_modules/@octokit/types": { 144 | "version": "6.34.0", 145 | "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.34.0.tgz", 146 | "integrity": "sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw==", 147 | "dependencies": { 148 | "@octokit/openapi-types": "^11.2.0" 149 | } 150 | }, 151 | "node_modules/@types/node": { 152 | "version": "14.18.12", 153 | "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.12.tgz", 154 | "integrity": "sha512-q4jlIR71hUpWTnGhXWcakgkZeHa3CCjcQcnuzU8M891BAWA2jHiziiWEPEkdS5pFsz7H9HJiy8BrK7tBRNrY7A==", 155 | "dev": true 156 | }, 157 | "node_modules/@zeit/ncc": { 158 | "version": "0.22.3", 159 | "resolved": "https://registry.npmjs.org/@zeit/ncc/-/ncc-0.22.3.tgz", 160 | "integrity": "sha512-jnCLpLXWuw/PAiJiVbLjA8WBC0IJQbFeUwF4I9M+23MvIxTxk5pD4Q8byQBSPmHQjz5aBoA7AKAElQxMpjrCLQ==", 161 | "deprecated": "@zeit/ncc is no longer maintained. Please use @vercel/ncc instead.", 162 | "dev": true, 163 | "bin": { 164 | "ncc": "dist/ncc/cli.js" 165 | } 166 | }, 167 | "node_modules/before-after-hook": { 168 | "version": "2.2.2", 169 | "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz", 170 | "integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==" 171 | }, 172 | "node_modules/deprecation": { 173 | "version": "2.3.1", 174 | "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", 175 | "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" 176 | }, 177 | "node_modules/is-plain-object": { 178 | "version": "5.0.0", 179 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", 180 | "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", 181 | "engines": { 182 | "node": ">=0.10.0" 183 | } 184 | }, 185 | "node_modules/node-fetch": { 186 | "version": "2.6.7", 187 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", 188 | "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", 189 | "dependencies": { 190 | "whatwg-url": "^5.0.0" 191 | }, 192 | "engines": { 193 | "node": "4.x || >=6.0.0" 194 | }, 195 | "peerDependencies": { 196 | "encoding": "^0.1.0" 197 | }, 198 | "peerDependenciesMeta": { 199 | "encoding": { 200 | "optional": true 201 | } 202 | } 203 | }, 204 | "node_modules/once": { 205 | "version": "1.4.0", 206 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 207 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 208 | "dependencies": { 209 | "wrappy": "1" 210 | } 211 | }, 212 | "node_modules/prettier": { 213 | "version": "2.7.1", 214 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", 215 | "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", 216 | "dev": true, 217 | "bin": { 218 | "prettier": "bin-prettier.js" 219 | }, 220 | "engines": { 221 | "node": ">=10.13.0" 222 | }, 223 | "funding": { 224 | "url": "https://github.com/prettier/prettier?sponsor=1" 225 | } 226 | }, 227 | "node_modules/tr46": { 228 | "version": "0.0.3", 229 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", 230 | "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" 231 | }, 232 | "node_modules/tunnel": { 233 | "version": "0.0.6", 234 | "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", 235 | "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", 236 | "engines": { 237 | "node": ">=0.6.11 <=0.7.0 || >=0.7.3" 238 | } 239 | }, 240 | "node_modules/typescript": { 241 | "version": "4.8.3", 242 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", 243 | "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==", 244 | "dev": true, 245 | "bin": { 246 | "tsc": "bin/tsc", 247 | "tsserver": "bin/tsserver" 248 | }, 249 | "engines": { 250 | "node": ">=4.2.0" 251 | } 252 | }, 253 | "node_modules/universal-user-agent": { 254 | "version": "6.0.0", 255 | "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", 256 | "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==" 257 | }, 258 | "node_modules/uuid": { 259 | "version": "8.3.2", 260 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", 261 | "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", 262 | "bin": { 263 | "uuid": "dist/bin/uuid" 264 | } 265 | }, 266 | "node_modules/webidl-conversions": { 267 | "version": "3.0.1", 268 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", 269 | "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" 270 | }, 271 | "node_modules/whatwg-url": { 272 | "version": "5.0.0", 273 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", 274 | "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", 275 | "dependencies": { 276 | "tr46": "~0.0.3", 277 | "webidl-conversions": "^3.0.0" 278 | } 279 | }, 280 | "node_modules/wrappy": { 281 | "version": "1.0.2", 282 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 283 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 284 | } 285 | }, 286 | "dependencies": { 287 | "@actions/core": { 288 | "version": "1.9.1", 289 | "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz", 290 | "integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==", 291 | "requires": { 292 | "@actions/http-client": "^2.0.1", 293 | "uuid": "^8.3.2" 294 | } 295 | }, 296 | "@actions/github": { 297 | "version": "5.1.0", 298 | "resolved": "https://registry.npmjs.org/@actions/github/-/github-5.1.0.tgz", 299 | "integrity": "sha512-tuI80F7JQIhg77ZTTgUAPpVD7ZnP9oHSPN8xw7LOwtA4vEMbAjWJNbmLBfV7xua7r016GyjzWLuec5cs8f/a8A==", 300 | "requires": { 301 | "@actions/http-client": "^2.0.1", 302 | "@octokit/core": "^3.6.0", 303 | "@octokit/plugin-paginate-rest": "^2.17.0", 304 | "@octokit/plugin-rest-endpoint-methods": "^5.13.0" 305 | } 306 | }, 307 | "@actions/http-client": { 308 | "version": "2.0.1", 309 | "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz", 310 | "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==", 311 | "requires": { 312 | "tunnel": "^0.0.6" 313 | } 314 | }, 315 | "@octokit/auth-token": { 316 | "version": "2.5.0", 317 | "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", 318 | "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", 319 | "requires": { 320 | "@octokit/types": "^6.0.3" 321 | } 322 | }, 323 | "@octokit/core": { 324 | "version": "3.6.0", 325 | "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz", 326 | "integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==", 327 | "requires": { 328 | "@octokit/auth-token": "^2.4.4", 329 | "@octokit/graphql": "^4.5.8", 330 | "@octokit/request": "^5.6.3", 331 | "@octokit/request-error": "^2.0.5", 332 | "@octokit/types": "^6.0.3", 333 | "before-after-hook": "^2.2.0", 334 | "universal-user-agent": "^6.0.0" 335 | } 336 | }, 337 | "@octokit/endpoint": { 338 | "version": "6.0.12", 339 | "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz", 340 | "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==", 341 | "requires": { 342 | "@octokit/types": "^6.0.3", 343 | "is-plain-object": "^5.0.0", 344 | "universal-user-agent": "^6.0.0" 345 | } 346 | }, 347 | "@octokit/graphql": { 348 | "version": "4.8.0", 349 | "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz", 350 | "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==", 351 | "requires": { 352 | "@octokit/request": "^5.6.0", 353 | "@octokit/types": "^6.0.3", 354 | "universal-user-agent": "^6.0.0" 355 | } 356 | }, 357 | "@octokit/openapi-types": { 358 | "version": "11.2.0", 359 | "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.2.0.tgz", 360 | "integrity": "sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA==" 361 | }, 362 | "@octokit/plugin-paginate-rest": { 363 | "version": "2.17.0", 364 | "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.17.0.tgz", 365 | "integrity": "sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw==", 366 | "requires": { 367 | "@octokit/types": "^6.34.0" 368 | } 369 | }, 370 | "@octokit/plugin-rest-endpoint-methods": { 371 | "version": "5.13.0", 372 | "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.13.0.tgz", 373 | "integrity": "sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA==", 374 | "requires": { 375 | "@octokit/types": "^6.34.0", 376 | "deprecation": "^2.3.1" 377 | } 378 | }, 379 | "@octokit/request": { 380 | "version": "5.6.3", 381 | "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz", 382 | "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==", 383 | "requires": { 384 | "@octokit/endpoint": "^6.0.1", 385 | "@octokit/request-error": "^2.1.0", 386 | "@octokit/types": "^6.16.1", 387 | "is-plain-object": "^5.0.0", 388 | "node-fetch": "^2.6.7", 389 | "universal-user-agent": "^6.0.0" 390 | } 391 | }, 392 | "@octokit/request-error": { 393 | "version": "2.1.0", 394 | "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz", 395 | "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==", 396 | "requires": { 397 | "@octokit/types": "^6.0.3", 398 | "deprecation": "^2.0.0", 399 | "once": "^1.4.0" 400 | } 401 | }, 402 | "@octokit/types": { 403 | "version": "6.34.0", 404 | "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.34.0.tgz", 405 | "integrity": "sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw==", 406 | "requires": { 407 | "@octokit/openapi-types": "^11.2.0" 408 | } 409 | }, 410 | "@types/node": { 411 | "version": "14.18.12", 412 | "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.12.tgz", 413 | "integrity": "sha512-q4jlIR71hUpWTnGhXWcakgkZeHa3CCjcQcnuzU8M891BAWA2jHiziiWEPEkdS5pFsz7H9HJiy8BrK7tBRNrY7A==", 414 | "dev": true 415 | }, 416 | "@zeit/ncc": { 417 | "version": "0.22.3", 418 | "resolved": "https://registry.npmjs.org/@zeit/ncc/-/ncc-0.22.3.tgz", 419 | "integrity": "sha512-jnCLpLXWuw/PAiJiVbLjA8WBC0IJQbFeUwF4I9M+23MvIxTxk5pD4Q8byQBSPmHQjz5aBoA7AKAElQxMpjrCLQ==", 420 | "dev": true 421 | }, 422 | "before-after-hook": { 423 | "version": "2.2.2", 424 | "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz", 425 | "integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==" 426 | }, 427 | "deprecation": { 428 | "version": "2.3.1", 429 | "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", 430 | "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" 431 | }, 432 | "is-plain-object": { 433 | "version": "5.0.0", 434 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", 435 | "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" 436 | }, 437 | "node-fetch": { 438 | "version": "2.6.7", 439 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", 440 | "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", 441 | "requires": { 442 | "whatwg-url": "^5.0.0" 443 | } 444 | }, 445 | "once": { 446 | "version": "1.4.0", 447 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 448 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 449 | "requires": { 450 | "wrappy": "1" 451 | } 452 | }, 453 | "prettier": { 454 | "version": "2.7.1", 455 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", 456 | "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", 457 | "dev": true 458 | }, 459 | "tr46": { 460 | "version": "0.0.3", 461 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", 462 | "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" 463 | }, 464 | "tunnel": { 465 | "version": "0.0.6", 466 | "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", 467 | "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==" 468 | }, 469 | "typescript": { 470 | "version": "4.8.3", 471 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", 472 | "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==", 473 | "dev": true 474 | }, 475 | "universal-user-agent": { 476 | "version": "6.0.0", 477 | "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", 478 | "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==" 479 | }, 480 | "uuid": { 481 | "version": "8.3.2", 482 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", 483 | "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" 484 | }, 485 | "webidl-conversions": { 486 | "version": "3.0.1", 487 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", 488 | "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" 489 | }, 490 | "whatwg-url": { 491 | "version": "5.0.0", 492 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", 493 | "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", 494 | "requires": { 495 | "tr46": "~0.0.3", 496 | "webidl-conversions": "^3.0.0" 497 | } 498 | }, 499 | "wrappy": { 500 | "version": "1.0.2", 501 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 502 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 503 | } 504 | } 505 | } 506 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@peckjon/reject-pr-approval-from-committer", 3 | "version": "1.0.0", 4 | "description": "Do not allow a committer on a GitHub pull request to approve the PR.", 5 | "main": "dist/main.ts", 6 | "scripts": { 7 | "build": "npm run format && ncc build src/main.ts", 8 | "format": "prettier --write **/*.ts", 9 | "format-check": "prettier --check **/*.ts", 10 | "test": "jest" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/peckjon/reject-pr-approval-from-committer.git" 15 | }, 16 | "keywords": [ 17 | "actions", 18 | "pr", 19 | "pull request", 20 | "approve", 21 | "github", 22 | "GitHub" 23 | ], 24 | "author": "peckjon", 25 | "contributors": [ 26 | "Cognite AS", 27 | "hmarr", 28 | "James Hu", 29 | "some-natalie" 30 | ], 31 | "license": "MIT", 32 | "bugs": { 33 | "url": "https://github.com/peckjon/reject-pr-approval-from-committer/issues" 34 | }, 35 | "homepage": "https://github.com/peckjon/reject-pr-approval-from-committer#readme", 36 | "dependencies": { 37 | "@actions/core": "^1.9.1", 38 | "@actions/github": "^5.1.0" 39 | }, 40 | "devDependencies": { 41 | "@types/node": "^14.0.1", 42 | "@zeit/ncc": "^0.22.3", 43 | "prettier": "^2.7.1", 44 | "typescript": "^4.8.3" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import * as core from '@actions/core'; 2 | import * as github from '@actions/github'; 3 | 4 | type GitHub = ReturnType; 5 | 6 | async function removeExistingApprovalsIfExist(client: GitHub, pr: any) { 7 | // Get list of all reviews on a PR 8 | const { data: listReviews } = await client.rest.pulls.listReviews({ 9 | owner: github.context.repo.owner, 10 | repo: github.context.repo.repo, 11 | pull_number: pr.number, 12 | }); 13 | 14 | // Get list of all commits to the PR 15 | const { data: listCommits } = await client.rest.pulls.listCommits({ 16 | owner: github.context.repo.owner, 17 | repo: github.context.repo.repo, 18 | pull_number: pr.number, 19 | }); 20 | 21 | // List logins of all commit authors on the PR 22 | var commitAuthorLogins = listCommits.map(function (commit) { 23 | return commit.author?.login; 24 | }); 25 | 26 | // Remove PR approvals by any committer to the PR 27 | for (let review of listReviews) { 28 | if ( 29 | review.state === 'APPROVED' && 30 | review.user && 31 | commitAuthorLogins.includes(review.user.login) 32 | ) { 33 | core.info( 34 | `Removing an approval (${review.id}) from ${review.user?.login} (cannot approve this PR since they committed to it)` 35 | ); 36 | const dismissResponse = await client.rest.pulls.dismissReview({ 37 | owner: github.context.repo.owner, 38 | repo: github.context.repo.repo, 39 | pull_number: pr.number, 40 | review_id: review.id, 41 | message: `${review.user?.login} cannot approve this PR since they committed to it`, 42 | }); 43 | core.debug(`dismissResponse: ${JSON.stringify(dismissResponse)}`); 44 | core.setFailed( 45 | `${review.user?.login} cannot approve this PR since they committed to it` 46 | ); 47 | } 48 | } 49 | } 50 | 51 | async function run() { 52 | try { 53 | const token = core.getInput('github-token', { required: true }); 54 | 55 | const { pull_request: pr } = github.context.payload; 56 | if (!pr) { 57 | throw new Error( 58 | 'Event payload missing `pull_request` - workflow containing this action is supposed to be triggered by `pull_request` or `pull_request_target` event' 59 | ); 60 | } 61 | 62 | const client = github.getOctokit(token); 63 | 64 | await removeExistingApprovalsIfExist(client, pr); 65 | } catch (error) { 66 | core.setFailed((error as Error).message); 67 | } 68 | } 69 | 70 | run(); 71 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "outDir": "./lib", 6 | "rootDir": "./src", 7 | "strict": true, 8 | "noImplicitAny": false, 9 | "esModuleInterop": true 10 | }, 11 | "exclude": ["node_modules", "**/*.test.ts"] 12 | } 13 | --------------------------------------------------------------------------------