Skip to content

Commit 62f26aa

Browse files
committed
Adding code
1 parent c7214fe commit 62f26aa

File tree

9 files changed

+8579
-2
lines changed

9 files changed

+8579
-2
lines changed

.gitignore

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Dependency directories
2+
node_modules/
3+
jspm_packages/
4+
5+
# Optional npm cache directory
6+
.npm
7+
8+
# Optional eslint cache
9+
.eslintcache
10+
11+
# Output of 'npm pack'
12+
*.tgz
13+
14+
# Logs
15+
logs
16+
*.log
17+
npm-debug.log*
18+
yarn-debug.log*
19+
yarn-error.log*
20+
lerna-debug.log*
21+
22+
# dotenv environment variables file
23+
.env
24+
.env.test
25+
26+
# OS specific files
27+
.DS_Store
28+
Thumbs.db
29+
30+
# IDE specific files
31+
.idea/
32+
.vscode/
33+
*.sublime-project
34+
*.sublime-workspace
35+
36+
# Test files
37+
coverage/
38+
.nyc_output/
39+
40+
# Don't ignore the dist directory as it contains the bundled code
41+
# that needs to be committed for GitHub Actions
42+
# !dist/

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 Oscar Romero
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

Lines changed: 270 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,270 @@
1-
# workflow-concurrency-validator
2-
GitHub Action validates that the concurrency usage across workflows
1+
# Workflow Concurrency Validator
2+
3+
This GitHub Action validates that the concurrency usage across workflows in a repository does not exceed a specified limit. It helps prevent abuse of GitHub's concurrent job limits by analyzing workflow files and detecting potential parallel execution.
4+
5+
## What it checks
6+
7+
- Top-level concurrency settings in workflows
8+
- Job-level concurrency settings
9+
- Implicit concurrency from jobs that run in parallel (no dependencies)
10+
- Respects `cancel-in-progress: true` which doesn't count toward concurrency limits
11+
12+
## Installation
13+
14+
This action uses a bundled approach for dependencies, which makes it more reliable and faster.
15+
16+
## Usage Options
17+
18+
You can use this tool in two ways:
19+
1. As a GitHub Action directly in your workflow
20+
2. As a reusable workflow that can be called from other workflows
21+
22+
### Option 1: Setting up the Action in your Repository
23+
24+
Add the following to your workflow:
25+
26+
```yaml
27+
jobs:
28+
validate-concurrency:
29+
runs-on: ubuntu-latest
30+
steps:
31+
- name: Checkout code
32+
uses: actions/checkout@v3
33+
34+
- name: Validate Workflow Concurrency
35+
uses: homeles/workflow-concurrency-validator@v1
36+
with:
37+
max-concurrency: '10' # Optional, defaults to 10
38+
workflow-path: '.github/workflows' # Optional
39+
fail-on-error: 'true' # Optional
40+
comment-on-pr: 'true' # Optional
41+
```
42+
43+
#### Example Workflow
44+
45+
Create a file `.github/workflows/validate-concurrency.yml`:
46+
47+
```yaml
48+
name: Validate Workflow Concurrency
49+
50+
on:
51+
pull_request:
52+
paths:
53+
- '.github/workflows/**'
54+
push:
55+
branches:
56+
- main
57+
paths:
58+
- '.github/workflows/**'
59+
60+
jobs:
61+
validate:
62+
runs-on: ubuntu-latest
63+
steps:
64+
- name: Checkout code
65+
uses: actions/checkout@v3
66+
67+
- name: Validate Workflow Concurrency
68+
uses: homeles/workflow-concurrency-validator@v1
69+
with:
70+
max-concurrency: '10'
71+
comment-on-pr: 'true'
72+
```
73+
74+
### Option 2: Using as a Reusable Workflow
75+
76+
You can also set this up as a reusable workflow that can be called from other workflows.
77+
78+
#### Create the Reusable Workflow
79+
80+
First, create a file `.github/workflows/concurrency-validator-reusable.yml` in your repository:
81+
82+
```yaml
83+
name: Reusable Concurrency Validator
84+
85+
on:
86+
workflow_call:
87+
inputs:
88+
max-concurrency:
89+
description: 'Maximum allowed concurrency across all workflows'
90+
required: false
91+
type: number
92+
default: 10
93+
workflow-path:
94+
description: 'Path to the workflows directory'
95+
required: false
96+
type: string
97+
default: '.github/workflows'
98+
fail-on-error:
99+
description: 'Whether to fail the workflow if validation fails'
100+
required: false
101+
type: boolean
102+
default: true
103+
comment-on-pr:
104+
description: 'Whether to comment on PR if validation fails'
105+
required: false
106+
type: boolean
107+
default: true
108+
outputs:
109+
total-concurrency:
110+
description: 'Total concurrency detected across workflows'
111+
value: ${{ jobs.validate.outputs.total-concurrency }}
112+
validation-passed:
113+
description: 'Whether validation passed'
114+
value: ${{ jobs.validate.outputs.validation-passed }}
115+
secrets:
116+
token:
117+
description: 'GitHub token for commenting on PRs'
118+
required: false
119+
120+
jobs:
121+
validate:
122+
runs-on: ubuntu-latest
123+
outputs:
124+
total-concurrency: ${{ steps.validate.outputs.total_concurrency }}
125+
validation-passed: ${{ steps.validate.outputs.validation_passed }}
126+
steps:
127+
- name: Checkout code
128+
uses: actions/checkout@v3
129+
130+
- name: Validate Workflow Concurrency
131+
id: validate
132+
uses: homeles/workflow-concurrency-validator@v1
133+
with:
134+
max-concurrency: ${{ inputs.max-concurrency }}
135+
workflow-path: ${{ inputs.workflow-path }}
136+
fail-on-error: ${{ inputs.fail-on-error }}
137+
comment-on-pr: ${{ inputs.comment-on-pr }}
138+
token: ${{ secrets.token || github.token }}
139+
```
140+
141+
#### Call the Reusable Workflow
142+
143+
Then, you can call this workflow from another workflow:
144+
145+
```yaml
146+
name: PR Checks
147+
148+
on:
149+
pull_request:
150+
paths:
151+
- '.github/workflows/**'
152+
153+
jobs:
154+
validate-concurrency:
155+
uses: ./.github/workflows/concurrency-validator-reusable.yml
156+
with:
157+
max-concurrency: 10
158+
comment-on-pr: true
159+
secrets:
160+
token: ${{ secrets.GITHUB_TOKEN }}
161+
162+
# Add other jobs that depend on the validation result
163+
additional-checks:
164+
needs: validate-concurrency
165+
if: needs.validate-concurrency.outputs.validation-passed == 'true'
166+
runs-on: ubuntu-latest
167+
steps:
168+
- name: Run additional checks
169+
run: echo "Running additional checks because concurrency validation passed"
170+
```
171+
172+
## Inputs
173+
174+
| Input | Description | Required | Default |
175+
| ----- | ----------- | -------- | ------- |
176+
| `max-concurrency` | Maximum allowed concurrency across all workflows | No | `10` |
177+
| `workflow-path` | Path to the workflows directory | No | `.github/workflows` |
178+
| `fail-on-error` | Whether to fail the action if validation fails | No | `true` |
179+
| `comment-on-pr` | Whether to comment on PR if validation fails | No | `true` |
180+
| `token` | GitHub token for commenting on PRs | No | `${{ github.token }}` |
181+
182+
## Outputs
183+
184+
| Output | Description |
185+
| ------ | ----------- |
186+
| `total-concurrency` | Total concurrency detected across workflows |
187+
| `validation-passed` | Whether validation passed (`true` or `false`) |
188+
| `issues` | JSON array of issues found during validation |
189+
| `details` | JSON object with detailed information about concurrency usage |
190+
191+
## Development and Building
192+
193+
This action uses [@vercel/ncc](https://github.com/vercel/ncc) to bundle all dependencies into a single file. If you make changes to the action, follow these steps to rebuild it:
194+
195+
1. Install dependencies:
196+
```bash
197+
npm install
198+
```
199+
200+
2. Install development dependencies:
201+
```bash
202+
npm install --save-dev @vercel/ncc
203+
```
204+
205+
3. Make your changes to `validate-concurrency.js`
206+
207+
4. Build the bundled version:
208+
```bash
209+
npm run build
210+
```
211+
212+
5. Commit your changes, including the updated `dist/index.js` file
213+
214+
## Testing
215+
216+
You can test the action with various workflow patterns. The repository includes several example workflow files that demonstrate different concurrency patterns:
217+
218+
- Simple parallel jobs
219+
- Jobs with dependencies
220+
- Workflow-level concurrency
221+
- Job-level concurrency
222+
- Matrix workflows
223+
- Cancel-in-progress workflows
224+
225+
Place these test files in your `.github/workflows/` directory to test the validation logic.
226+
227+
## Advanced Configuration
228+
229+
### Branch Protection Rules
230+
231+
To prevent merging PRs that would violate the concurrency limit, set up a [branch protection rule](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/about-protected-branches) that requires the validation check to pass.
232+
233+
### Slack/Teams Notifications
234+
235+
You can enhance the action by adding notifications to Slack or Teams when validation fails:
236+
237+
```yaml
238+
- name: Notify Slack
239+
if: steps.validate.outputs.validation_passed == 'false'
240+
uses: slackapi/slack-github-action@v1
241+
with:
242+
payload: |
243+
{
244+
"text": "⚠️ Workflow concurrency validation failed: ${{ steps.validate.outputs.total_concurrency }} exceeds limit of ${{ inputs.max-concurrency }}"
245+
}
246+
env:
247+
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
248+
```
249+
250+
## Troubleshooting
251+
252+
### Dependencies Issues
253+
254+
This action uses a bundled approach to avoid dependency issues. If you encounter any problems:
255+
256+
1. Make sure you're using the latest version of the action
257+
2. Check that the `dist/index.js` file is included in your repository
258+
3. Verify the Node.js version in your workflow (Node.js 16+ is recommended)
259+
260+
### Output Not Working
261+
262+
The action uses the modern GitHub Actions output method with environment files. If you're seeing warnings about deprecated commands, make sure you're using the latest version of the action.
263+
264+
## How to Contribute
265+
266+
Contributions are welcome! Please feel free to submit a Pull Request.
267+
268+
## License
269+
270+
This project is licensed under the MIT License - see the LICENSE file for details.

0 commit comments

Comments
 (0)