Skip to content

Commit 01e0ab6

Browse files
feat: add automatic AB# tagging from branch name (#152)
* feat: add automatic AB# tagging from branch name Add new `add-ab-tag-from-branch` input that extracts work item IDs from the head branch name and appends AB#xxx to the PR body if not already present. Supports common branch formats like task/12345/description, task-12345, 12345-description, and more. closes #151 * refactor: rename add-ab-tag-from-branch to add-work-item-from-branch * docs: update description for add-work-item-from-branch input to clarify usage with check-pull-request * feat: enhance work item extraction from branch names to match only 3+ digit IDs and update related documentation * feat!: require Azure DevOps validation for branch work item extraction - add-work-item-from-branch now requires azure-devops-token and azure-devops-organization; extracted IDs are always validated against Azure DevOps before being added to the PR body - Remove 3-digit minimum from branch regex since validation catches false positives - Sanitize branch name in job summary to prevent markdown injection - Fix JSDoc param type for extractWorkItemIdsFromBranch - Clean up dangling append-work-item-title test references - Add tests for validation of branch-extracted IDs and missing token * fix: address PR review findings for branch extraction - Fix GHAS incomplete string escaping: escape backslashes in branchName - Allow add-work-item-from-branch as standalone (update guard condition) - Cap branch ID extraction at 5 to limit API calls - Fix misleading azure-devops-token/organization descriptions in README - Add test for standalone branch extraction usage * chore: bump version to 4.1.0 in package.json * feat: restrict branch work item extraction to keyword prefixes Only extract work item IDs from branch names when they follow a recognized keyword prefix (e.g. task/12345, bug-67890) instead of matching any bare number. This prevents false positives from year-like numbers or version segments in branch names. Add configurable `branch-work-item-prefixes` input (default: task, bug, bugfix) so users can customize the keyword list. Resolves the false positive concern raised in #151. * fix: revert version number to 4.1.0 in package.json * fix: update coverage percentage in coverage.svg to 87.09% * fix: handle validateWorkItemExists object return in branch tagging path The branch-tagging validation loop was treating the return value of validateWorkItemExists() as a boolean, but it returns an object ({ exists, authError?, errorMessage? }). This meant auth errors were silently swallowed and invalid work items could be incorrectly added. - Check result.exists and result.authError consistently with other call sites - Update test mocks to return { exists: true/false } objects - Add test for auth error during branch work item validation * feat: reduce false positives in branch work item extraction Add three safeguards against incorrect work item linking from branch names: 1. Date pattern exclusion - numbers followed by date-like patterns (e.g. 2024-01-15) are automatically rejected 2. First-segment-only matching - keywords must appear at the start of the branch or after a path separator (/), preventing keywords in description segments from triggering extraction (e.g. fix-bug-67890) 3. Configurable minimum digits - new branch-work-item-min-digits input lets users filter out short numbers (years, versions, etc.) Add dedicated "Auto-Tag from Branch Name" section to README with examples table showing what matches and what does not. * refactor: deduplicate escapeRegExp and validate empty prefixes - Move escapeRegExp() above buildBranchWorkItemPattern() and reuse it instead of duplicating the regex escape logic - Fail fast with a clear error when add-work-item-from-branch is enabled but branch-work-item-prefixes is empty * fix: reset AB_PATTERN.lastIndex before .test() calls The module-level AB_PATTERN regex has the /g flag, which causes .test() to advance lastIndex after each match. In a loop over multiple commits, this can cause false negatives when the next string's AB# reference appears before the stale lastIndex position. Reset lastIndex to 0 before each .test() call in both the commit validation loop and the PR validation path. * docs: fix permissions wording in README github-token description * docs: fix permissions wording in action.yml github-token description * chore: linting * docs: update azure-devops-token and azure-devops-organization descriptions in action.yml * test: clarify test name for branch work item validation * chore: change branch-work-item-min-digits default from 1 to 5
1 parent b4b2805 commit 01e0ab6

7 files changed

Lines changed: 838 additions & 34 deletions

File tree

README.md

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ Please refer to the [release page](https://github.com/joshjohanning/azdo_commit_
1818
2. **Validates Commits** - Ensures each commit in a pull request has an Azure DevOps work item link (e.g. `AB#123`) in the commit message
1919
3. **Automatically Links PRs to Work Items** - When a work item is referenced in a commit message, the action adds a GitHub Pull Request link to that work item in Azure DevOps
2020
- 🎯 **This is the key differentiator**: By default, Azure DevOps only adds the Pull Request link to work items mentioned directly in the PR title or body, but this action also links work items found in commit messages!
21-
4. **Visibility & Tracking** - Work item linkages are added to the job summary for easy visibility
21+
4. **Auto-Tag from Branch** - Optionally extracts work item IDs from the head branch name (e.g. `task/12345/fix-bug`) and adds `AB#12345` to the PR body automatically
22+
5. **Visibility & Tracking** - Work item linkages are added to the job summary for easy visibility
2223

2324
## Action Output
2425

@@ -69,19 +70,60 @@ jobs:
6970
7071
### Inputs
7172
72-
| Name | Description | Required | Default |
73-
| -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | --------------------- |
74-
| `check-pull-request` | Check the pull request for `AB#xxx` (scope configurable via `pull-request-check-scope`) | `true` | `false` |
75-
| `pull-request-check-scope` | Only if `check-pull-request=true`, where to look for `AB#` in the PR: `title-or-body`, `body-only`, or `title-only` | `false` | `title-or-body` |
76-
| `check-commits` | Check each commit in the pull request for `AB#xxx` | `true` | `true` |
77-
| `fail-if-missing-workitem-commit-link` | Only if `check-commits=true`, fail the action if a commit in the pull request is missing AB# in every commit message | `false` | `true` |
78-
| `link-commits-to-pull-request` | Only if `check-commits=true`, link the work items found in commits to the pull request | `false` | `true` |
79-
| `validate-work-item-exists` | Validate that the work item(s) referenced in commits and PR exist in Azure DevOps (requires `azure-devops-token` and `azure-devops-organization`) | `false` | `true` |
80-
| `add-work-item-table` | Add a "Linked Work Items" table to the PR body showing titles for `AB#xxx` references (original references are preserved). Requires `azure-devops-token` and `azure-devops-organization` | `false` | `false` |
81-
| `azure-devops-organization` | Only if `check-commits=true`, link the work items found in commits to the pull request | `false` | `''` |
82-
| `azure-devops-token` | Only required if `link-commits-to-pull-request=true`, Azure DevOps PAT used to link work item to PR (needs to be a `full` PAT) | `false` | `''` |
83-
| `github-token` | The GitHub token that has contents-read and pull_request-write access | `true` | `${{ github.token }}` |
84-
| `comment-on-failure` | Comment on the pull request if the action fails | `true` | `true` |
73+
| Name | Description | Required | Default |
74+
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | --------------------- |
75+
| `check-pull-request` | Check the pull request for `AB#xxx` (scope configurable via `pull-request-check-scope`) | `true` | `false` |
76+
| `pull-request-check-scope` | Only if `check-pull-request=true`, where to look for `AB#` in the PR: `title-or-body`, `body-only`, or `title-only` | `false` | `title-or-body` |
77+
| `check-commits` | Check each commit in the pull request for `AB#xxx` | `true` | `true` |
78+
| `fail-if-missing-workitem-commit-link` | Only if `check-commits=true`, fail the action if a commit in the pull request is missing AB# in every commit message | `false` | `true` |
79+
| `link-commits-to-pull-request` | Only if `check-commits=true`, link the work items found in commits to the pull request | `false` | `true` |
80+
| `validate-work-item-exists` | Validate that the work item(s) referenced in commits and PR exist in Azure DevOps (requires `azure-devops-token` and `azure-devops-organization`) | `false` | `true` |
81+
| `add-work-item-table` | Add a "Linked Work Items" table to the PR body showing titles for `AB#xxx` references (original references are preserved). Requires `azure-devops-token` and `azure-devops-organization` | `false` | `false` |
82+
| `add-work-item-from-branch` | Automatically extract work item ID(s) from the head branch name and add `AB#xxx` to the PR body if not already present. Only numbers following one of the configured `branch-work-item-prefixes` keywords are extracted. Each ID is always validated against Azure DevOps before being added (regardless of the `validate-work-item-exists` setting). Requires `azure-devops-token` and `azure-devops-organization` | `false` | `false` |
83+
| `branch-work-item-prefixes` | Comma-separated list of keyword prefixes used to identify work item IDs in branch names (e.g. `task/12345`). Only numbers following one of these keywords (separated by `/`, `-`, or `_`) are extracted. Only used when `add-work-item-from-branch` is `true` | `false` | `task, bug, bugfix` |
84+
| `branch-work-item-min-digits` | Minimum number of digits for a work item ID extracted from a branch name. Set to `1` to match any length. Only used when `add-work-item-from-branch` is `true` | `false` | `5` |
85+
| `azure-devops-organization` | The name of the Azure DevOps organization. Required when any of these are enabled: `link-commits-to-pull-request`, `validate-work-item-exists`, `add-work-item-table`, or `add-work-item-from-branch` | `false` | `''` |
86+
| `azure-devops-token` | Azure DevOps PAT (needs to be a `full` PAT). Required when any of these are enabled: `link-commits-to-pull-request`, `validate-work-item-exists`, `add-work-item-table`, or `add-work-item-from-branch` | `false` | `''` |
87+
| `github-token` | The GitHub token that has `contents: read` and `pull-requests: write` access | `true` | `${{ github.token }}` |
88+
| `comment-on-failure` | Comment on the pull request if the action fails | `true` | `true` |
89+
90+
### Auto-Tag from Branch Name
91+
92+
When `add-work-item-from-branch` is enabled, the action extracts work item IDs from the pull request's head branch name and adds `AB#xxx` tags to the PR body. This is useful when your team's branching convention includes the Azure DevOps work item ID in the branch name.
93+
94+
**How it works:**
95+
96+
1. The action scans the branch name for keyword prefixes (default: `task`, `bug`, `bugfix`) followed by a separator (`/`, `-`, or `_`) and a number
97+
2. The keyword must appear at the **start of the branch** or after a path separator (`/`) — keywords that appear mid-description are ignored
98+
3. Date-shaped numbers (e.g. `2024-01-15`) are automatically excluded
99+
4. Every extracted ID is validated against Azure DevOps before being added to the PR body — IDs that don't exist are skipped with a warning
100+
5. IDs already present in the PR body are not added again
101+
102+
**Branch name examples:**
103+
104+
| Branch Name | Extracted IDs | Notes |
105+
| ----------------------------- | ------------- | -------------------------------------------------------------------- |
106+
| `task/12345/fix-login` | `12345` | ✅ Standard convention |
107+
| `bug-67890` | `67890` | ✅ Keyword with `-` separator |
108+
| `users/josh/task/12345/fix` | `12345` | ✅ Keyword after path separator |
109+
| `bugfix/2024-01-15-fix-login` | _(none)_ | ⛔ Date pattern excluded |
110+
| `task/12345/fix-bug-67890` | `12345` | ⛔ `bug` in description ignored |
111+
| `hotfix/2024-bugfix` | _(none)_ | ⛔ `hotfix` is not a default prefix |
112+
| `feature/task-manager-ui` | _(none)_ | ⛔ No number after keyword |
113+
| `release/task-2.0.1` | _(none)_ | ⛔ Short digits filtered by default `branch-work-item-min-digits: 5` |
114+
115+
**Lowering the minimum digit threshold:**
116+
117+
If your Azure DevOps work item IDs are shorter than 5 digits, set `branch-work-item-min-digits` to a lower value:
118+
119+
```yml
120+
- uses: joshjohanning/azdo_commit_message_validator@v4
121+
with:
122+
add-work-item-from-branch: true
123+
branch-work-item-min-digits: 3
124+
azure-devops-organization: my-azdo-org
125+
azure-devops-token: ${{ secrets.AZURE_DEVOPS_PAT }}
126+
```
85127

86128
## Screenshots
87129

0 commit comments

Comments
 (0)