This Skill is read-only: usetwo buildsto define the scope (excluding the starting build, including the ending build), and compile the changes during the period into Markdown that can be pasted directly.
Project selection
-
If the user has provided a project name (for example "Contoso project"), use it directly and do not call the project list API.
-
If not provided, ask the user to provide it once.
-
If still not provided, list the projects for the user to choose:
curl -sS -u ":$AZURE_DEVOPS_PAT" \ "https://dev.azure.com/$AZURE_DEVOPS_ORG/_apis/projects?%24top=500&api-version=7.1" -
Do not continue until the user provides or selects a project.
Connection and authentication
Always use curl to call the Azure DevOps REST API directly; each command carries its own authentication parameters.
- Organization: read the environment variable
AZURE_DEVOPS_ORG(organization name, for examplecontoso). If it is not set, ask the user once; if the user gives a URL, extract the organization name fromhttps://dev.azure.com/{org}orhttps://{org}.visualstudio.com. - Token: send the PAT with Basic authentication:
-u ":$AZURE_DEVOPS_PAT"; if onlyAZURE_DEVOPS_EXT_PATis set (the variable used by the Azure CLI azure-devops extension), use it instead. When switching to a Microsoft Entra ID token, replace it with-H "Authorization: Bearer $AZURE_DEVOPS_TOKEN". If neither is set, ask the user to setAZURE_DEVOPS_PATin their own terminal and retry, and stop. Read the token only from environment variables: do not ask the user to paste the token into the conversation, and do not print it or write it to a file. - PAT permission scopes:Build (Read)、Code (Read)、Work Items (Read)。
- Encoding: URL-encode the project and Pipeline names in the path and query string (write spaces as
%20); in the query string, write$as%24(for example%24top) to avoid shell expansion. - Errors: HTTP 401, 403, 203, or an HTML login page in the response means the token is invalid, expired, or has insufficient permissions; report it and stop. HTTP 404 means the organization, project, build ID, or API version is incorrect.
- Windows PowerShell: call
curl.exe(not thecurlalias), and write the environment variable as$env:AZURE_DEVOPS_PAT; PowerShell does not support<<'EOF'; first write the JSON body to a temporary file, then send it with--data-binary "@body.json".
Steps
1. Determine the comparison scope
-
Ending build(
to): if the user has given a build ID, use it, and get the build to learndefinition.id、sourceBranch、finishTime、buildNumber、repository.name:curl -sS -u ":$AZURE_DEVOPS_PAT" \ "https://dev.azure.com/$AZURE_DEVOPS_ORG/{project}/_apis/build/builds/{toBuildId}?api-version=7.1"If the user only gives a Pipeline name, use
GET .../_apis/build/definitions?name={name}&api-version=7.1to find the definition ID, and use the first item from the query below as the ending build (the most recent successful build). -
Starting build(
from): if the user has given one, use it (the two builds must belong to the same repository; the starting build must be earlier; if they are reversed, swap them). If not given, find the previous successful build of the same definition and same branch:curl -sS -u ":$AZURE_DEVOPS_PAT" \ "https://dev.azure.com/$AZURE_DEVOPS_ORG/{project}/_apis/build/builds?definitions={definitionId}&branchName=refs/heads/main&resultFilter=succeeded&%24top=2&queryOrder=finishTimeDescending&api-version=7.1"value[0]is the ending build,value[1]is the starting build. When the ending build is not the most recent successful build, add&maxTime={toFinishTime}(inclusive of that time); the result is still[終點, 起點]When only one record is found, explain that there is no earlier successful build to compare against, and ask the user to specify a starting point. -
Tell the user the range first (the two build IDs, branch, and completion time), then continue.
2. Get the commits in the period
curl -sS -u ":$AZURE_DEVOPS_PAT" \
"https://dev.azure.com/$AZURE_DEVOPS_ORG/{project}/_apis/build/changes?fromBuildId={fromBuildId}&toBuildId={toBuildId}&%24top=200&api-version=7.1-preview.2"
- Microsoft Learn only lists the preview version of this resource (
7.1-preview.2)。 - The range excludes commits from the starting build itself and includes commits from the ending build.
- No pagination: when the number of records returned equals
%24top, it may be truncated; increase%24top(for example,1000) and query again. - Each record has
id(full SHA),message(messageTruncatedistruewhen incomplete),type(TfsGitis Azure Repos,GitHubis GitHub),author.displayName、timestamp、location(for Azure Repos it is.../git/repositories/{repositoryId}/commits/{sha}, from which the repository ID can be extracted). - When there are no commits at all, explain that there are no code changes between the two builds (it may be a rerun of the same commit), and stop.
3. Get linked work items
curl -sS -u ":$AZURE_DEVOPS_PAT" \
"https://dev.azure.com/$AZURE_DEVOPS_ORG/{project}/_apis/build/workitems?fromBuildId={fromBuildId}&toBuildId={toBuildId}&%24top=200&api-version=7.1-preview.2"
-
Likewise, only the preview version is available. Returns
value[].id(a string); for the work items of a single build, useGET .../_apis/build/builds/{buildId}/workitems?api-version=7.1。 -
with
workitemsbatchto get fields (at most 200 IDs each time, seterrorPolicytoOmitso that items without permission or deleted items returnnullinstead of failing the whole batch):curl -sS -u ":$AZURE_DEVOPS_PAT" -X POST -H "Content-Type: application/json" \ "https://dev.azure.com/$AZURE_DEVOPS_ORG/{project}/_apis/wit/workitemsbatch?api-version=7.1" \ -d '{"ids":[101,102],"fields":["System.Id","System.Title","System.WorkItemType","System.State"],"errorPolicy":"Omit"}' -
Work items come from links in commits and PRs, including the
#123syntax in commit messages; list separately items whose titles appear unrelated to this batch of changes (for example, very small IDs or items from many years ago), and ask the user to confirm whether to keep them.
4. Find merged PRs
-
Azure Repos(
typeisTfsGit): to query PRs for Azure Repos, send all SHAs from step 2 in one query, andlastMergeCommitfind PRs merged with these commits. This is a read-only query (returns HTTP 201 on success); SHAs must be the full 40 characters, and one query can contain hundreds of SHAs:curl -sS -u ":$AZURE_DEVOPS_PAT" -X POST -H "Content-Type: application/json" \ "https://dev.azure.com/$AZURE_DEVOPS_ORG/{project}/_apis/git/repositories/{repositoryId}/pullrequestquery?api-version=7.1" \ -d '{"queries":[{"type":"lastMergeCommit","items":["{commitSha1}","{commitSha2}"]}]}'results[0]is a mapping table for{ "<sha>": [PR, ...] }, containing only SHAs for which a PR can be found. A PR haspullRequestId、title、createdBy.displayName、sourceRefName、targetRefName. When a feature branch is first merged into an intermediate branch (for example,develop) and then merged in bulk into a release branch, both layers of PRs will appear: use PRs whose target is not the build branch as the feature list, and mark PRs whose target is the build branch as "release merge". -
GitHub(
typeisGitHub): if Azure Repos PRs cannot be queried, parseMerge pull request #123from commit messages or(#123)at the end of squash merge titles, and write the link ashttps://github.com/{owner}/{repo}/pull/123({owner}/{repo}taken from the build'srepository.id)。 -
Azure Repos merge messages are usually
Merged PR 123: 標題; when the query fails, it can be used as a fallback.
5. Categorize and organize
- ✨ New features:
System.WorkItemTypeWork items whose type is Feature, Epic, User Story, Product Backlog Item, or Requirement. - 🐛 Bug fixes: Bug (and Issue, depending on the process template).
- 🔧 Other: other types such as Task.
- List the related PRs for each work item (if they can be mapped). PRs with no linked work items go under "Other changes".
- Important commits: direct commits that are not covered by any PR and are not merge commits (message starts with
MergeorMerged PR), pick out those with substantive content and list them (for example,feat:、fix:prefix); when there are many, list only the first 20 and note the total count. - Contributors:commit
author.displayName: after deduplication, sorted by commit count. - When the work item status is not a completed category (for example, New, Active), add a note to remind that acceptance may not yet be complete.
Example: "Generate release notes for the latest build of MyApp-CI in the Contoso project," "What changes are there between builds 12300 and 12345?"
Present results
Display times in the user's local time zone (format YYYY/MM/DD); when the time zone cannot be determined, indicate UTC. Work item links are https://dev.azure.com/{organization}/{project}/_workitems/edit/{ID}; Azure Repos PR links are https://dev.azure.com/{organization}/{project}/_git/{repositoryName}/pullrequest/{pullRequestId}({repositoryName} taken from the build's repository.name; PRs in query results do not include webUrl); build links are https://dev.azure.com/{organization}/{project}/_build/results?buildId={buildId}。
Output as a single Markdown block so the user can copy it easily:
# MyApp 20260915.3 Release Notes
比較範圍:[20260910.1](建置連結) → [20260915.3](建置連結)(main,2026/09/10 – 2026/09/15)
共 23 個 commit、6 個 PR、5 個工作項目,4 位貢獻者。
## ✨ 新功能
- [#101](連結) 會員可以匯出訂單(PR [!12345](連結))
## 🐛 Bug 修正
- [#102](連結) 修正結帳金額四捨五入錯誤(PR [!12346](連結))
## 🔧 其他變更
- PR [!12347](連結) 升級 Node.js 版本
## 貢獻者
Contoso Dev A、Contoso Dev B
Omit sections with no data. Finally, outside the block, add: lists that may be truncated, PRs that cannot be mapped, and work items that require user confirmation.