diff --git a/.github/workflows/chronus-verify.yml b/.github/workflows/chronus-verify.yml new file mode 100644 index 000000000000..158a5157b98c --- /dev/null +++ b/.github/workflows/chronus-verify.yml @@ -0,0 +1,102 @@ +name: Chronus Verify + +on: + pull_request: + branches: [main] + paths: + - "sdk/*/*/**" + +concurrency: + group: chronus-verify-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + chronus-verify: + name: Verify Chronus Change Descriptions + if: github.event.pull_request.user.login != 'azure-sdk' + runs-on: ubuntu-latest + permissions: + contents: read + issues: write + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 # needed so chronus can diff against base branch + persist-credentials: false + + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: "22" + cache: npm + cache-dependency-path: .github/chronus/package-lock.json + + - name: Install pinned dependencies + run: npm ci + working-directory: .github/chronus + + - name: Run chronus verify + id: verify + run: npm exec --no --prefix .github/chronus/ -- chronus verify + + # Sticky comment is only post-able when GITHUB_TOKEN has write scope — + # i.e. PRs from the main repo. Fork PRs see only the error annotation below. + - name: Post sticky fix-instructions PR comment on failure + if: failure() && steps.verify.conclusion == 'failure' && github.event.pull_request.head.repo.full_name == github.repository + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + with: + script: | + const HEADER = ''; + const body = [ + HEADER, + '### 📝 Missing changelog entry', + '', + 'This PR touches package source under `sdk/*/*/**` but no Chronus', + 'change description was found. CI requires every user-affecting', + 'change to have one.', + '', + '#### How to fix', + '', + 'Run the following from the repo root (or from within the package', + 'directory) and push the new `.chronus/changes/*.md` file:', + '', + '```bash', + 'azpysdk changelog add', + '```', + '', + 'This adds a change entry for each modified package. If your change', + 'is not user-facing (e.g. tests or docs only), choose the `internal`', + 'kind to satisfy the check without bumping the version.', + '', + '> 💡 You can also ask **GitHub Copilot** to fix this failing check', + '> for you directly from the PR\'s *Checks* tab.', + '', + 'See [`doc/dev/changelog_updates.md`](https://github.com/Azure/azure-sdk-for-python/blob/main/doc/dev/changelog_updates.md) for full instructions.', + ].join('\n'); + + const comments = await github.paginate(github.rest.issues.listComments, { + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.pull_request.number, + }); + const existing = comments.find(c => c.body && c.body.startsWith(HEADER)); + if (existing) { + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: existing.id, + body, + }); + } else { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.pull_request.number, + body, + }); + } + + - name: Emit annotation on failure + if: failure() && steps.verify.conclusion == 'failure' + run: | + echo "::error::Chronus verification failed. Run 'azpysdk changelog add' locally and push the new .chronus/changes/*.md file, or ask GitHub Copilot to fix this check from the PR's Checks tab." + echo "::error::See https://github.com/Azure/azure-sdk-for-python/blob/main/doc/dev/changelog_updates.md for instructions." diff --git a/doc/dev/changelog_updates.md b/doc/dev/changelog_updates.md index c39d8d49e25e..fc29752d0eee 100644 --- a/doc/dev/changelog_updates.md +++ b/doc/dev/changelog_updates.md @@ -10,21 +10,23 @@ The repository configuration lives in [`.chronus/config.yaml`](https://github.co ## Prerequisites -Chronus is distributed as an npm package. To use it, you need [Node.js](https://nodejs.org/) installed (LTS version recommended). You can then run Chronus without a global install using `npx`: +The recommended way to interact with Chronus is through the `azpysdk` CLI, which is already available in this repository's developer environment and handles installing Chronus automatically. + +If you prefer to invoke Chronus directly, it is distributed as an npm package and requires [Node.js](https://nodejs.org/) (LTS version recommended). You can run it without a global install using `npx`: ```bash npx chronus ``` -Alternatively, install it globally: +## Adding a Change Description + +When you make changes to a package that has a `pyproject.toml`, add a change description by running the following from the repository root or from within the package directory: ```bash -npm install -g @chronus/chronus +azpysdk changelog add ``` -## Adding a Change Description - -When you make changes to a package that has a `pyproject.toml`, run `chronus add` from the root of the repository: +Alternatively, using raw Chronus: ```bash npx chronus add @@ -55,7 +57,13 @@ The following change kinds are defined for this repository: ### Specifying a Package Directly -You can skip the interactive prompt by passing the package path(s) directly: +You can skip the interactive prompt by passing the package path and change details directly: + +```bash +azpysdk changelog add sdk/storage/azure-storage-blob --kind fix --message "Fixed upload failure on large files" +``` + +Or using raw Chronus: ```bash npx chronus add sdk/storage/azure-storage-blob @@ -65,9 +73,9 @@ npx chronus add sdk/storage/azure-storage-blob ```bash # After making changes to azure-storage-blob, add a change description -npx chronus add sdk/storage/azure-storage-blob +azpysdk changelog add sdk/storage/azure-storage-blob -# Chronus will prompt you: +# You will be prompted to select: # ? What kind of change is this? › fix # ? Describe the change: › Fixed an issue where upload would fail on large files ``` @@ -90,10 +98,17 @@ You commit this file along with your code changes. To check whether all modified packages have a corresponding change description (e.g., before opening a PR), run: +```bash +azpysdk changelog verify +``` + +Or using raw Chronus: + ```bash npx chronus verify ``` +> **Note:** The CI workflow (`Chronus Verify`) runs `chronus verify` automatically on every pull request that modifies source files under `sdk/` (specifically files matching `sdk/*/*/**`). If it fails, run `azpysdk changelog add` locally and push the resulting `.chronus/changes/*.md` file. You can also ask GitHub Copilot to fix the failing check directly from the pull request's *Checks* tab. If your changes don't need a changelog entry (e.g., pure documentation or test-only changes unrelated to package behavior), you can add an `internal` change kind entry to satisfy the requirement without bumping the version. @@ -101,6 +116,12 @@ If your changes don't need a changelog entry (e.g., pure documentation or test-o To see a summary of all pending changes and the resulting version bumps: +```bash +azpysdk changelog status +``` + +Or using raw Chronus: + ```bash npx chronus status ``` @@ -109,7 +130,7 @@ npx chronus status Packages in this repository that use `pyproject.toml` (instead of or alongside `setup.py`) are fully supported by Chronus. The `pyproject.toml` is used for package metadata, while the `CHANGELOG.md` in the package directory remains the canonical user-facing changelog. -Chronus reads the package version from the Python package metadata and writes changelog entries into the `CHANGELOG.md` file with `npx chronus changelog`. You do not need to manually edit `CHANGELOG.md` for your changes. +Chronus reads the package version from the Python package metadata and writes changelog entries into the `CHANGELOG.md` file with `azpysdk changelog create` (or `npx chronus changelog`). You do not need to manually edit `CHANGELOG.md` for your changes. ## Further Reading