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 diff --git a/sdk/core/azure-core/azure/core/configuration.py b/sdk/core/azure-core/azure/core/configuration.py index bdae07d264a6..3a8b8aa0b43a 100644 --- a/sdk/core/azure-core/azure/core/configuration.py +++ b/sdk/core/azure-core/azure/core/configuration.py @@ -43,7 +43,8 @@ class Configuration(Generic[HTTPRequestType, HTTPResponseType]): # pylint: disa """Provides the home for all of the configurable policies in the pipeline. A new Configuration object provides no default policies and does not specify in what - order the policies will be added to the pipeline. The SDK developer must specify each + order the policies will be added to the pipeline. Policies can be added after + construction. The SDK developer must specify each of the policy defaults as required by the service and use the policies in the Configuration to construct the pipeline correctly, as well as inserting any unexposed/non-configurable policies.