Skip to content

Release 0.639.0 - #2831

Merged
marschattha merged 1 commit into
mainfrom
release-0.639.0
Jul 23, 2026
Merged

Release 0.639.0#2831
marschattha merged 1 commit into
mainfrom
release-0.639.0

Conversation

@qlty-releases

@qlty-releases qlty-releases Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Automated PR for release 0.639.0.

Review (and edit, if needed) the changelog entry below, then
merge this pull request to publish the release.

Draft release notes

Fixed

noahd1 commented Jul 23, 2026

Copy link
Copy Markdown
Member

🔍 Backwards-compatibility review in progress…

I'm running the bc-check skill on this PR now. This is a release PR (0.639.0), so I'll be examining the changelog entries and the underlying PRs (#2829, #2830) for behavior changes that could affect existing qlty users on upgrade.

I'll edit this comment with findings once the review is done.


Generated by Claude Code

noahd1 commented Jul 23, 2026

Copy link
Copy Markdown
Member

Backwards-compatibility review

Target: PR #2831 (Release 0.639.0)
Verdict: risky — needs reviewer sign-off on the linter-version shift
Affected user segments: local devs, CI users, and Qlty Cloud (any repo using package_file with a package-lock.json or composer.lock)

Scope

The release PR itself only bumps Cargo.toml/Cargo.lock and appends a CHANGELOG.md entry — zero code changes in this diff. The release aggregates two commits that already landed on main since v0.638.0:

Both are behavior changes on the qlty check install path when a plugin is configured with package_file. They align the CLI with documented behavior ("When using package_file, Qlty respects the locked versions for reliability"), but they will change which linter versions get installed for existing users on upgrade, which can change the findings those linters produce.

Findings

[risky] qlty-check/src/tool/node.rs:172-207 — behavior change on existing command path (#2829)

  • Before: qlty check staged a copy of the repo's package-lock.json but then ran npm install --force --no-package-lock, so npm ignored the lockfile and resolved the latest versions matching package.json's semver ranges.
  • After: When a lockfile was staged, --no-package-lock is dropped. npm now honors the lockfile. When there is no lockfile (or package_filters is set), the flag is preserved and behavior is unchanged.
  • Who breaks:
    • Segment 1 (local devs) and Segment 2 (CI): A repo with package.json containing "eslint": "^8.0.0" and a lockfile pinning eslint@8.0.0 was silently getting eslint@8.57.1. After upgrade, that repo runs eslint 8.0.0. The rule set for 8.0.0 is a strict subset of 8.57.1, so findings can change on unchanged code — some warnings/errors will disappear, and any config referencing rules added after 8.0.0 will now warn ("Definition for rule … was not found"). Users may see a diff in qlty check output on the very first upgraded run without touching any code.
    • Segment 2 (CI) specifically: If a lockfile is stale or corrupt in a way that made npm's non-lock resolution silently succeed before, npm install may now fail — and unlike the composer path (fix(check): honor composer.lock when installing from package_file #2830), there is no npm install --no-package-lock fallback. A CI-only failure is possible for any customer with a lockfile that resolves but is inconsistent with the linter's actual peer/dep tree.
    • Segment 3 (Qlty Cloud): Same as segment 2 if Qlty Cloud invokes qlty check or qlty install on customer repos with node linters — the flip is silent to the customer until findings shift.
  • Suggested mitigation: (a) Add a symmetric fallback to what fix(check): honor composer.lock when installing from package_file #2830 did: on npm install failure with a staged lockfile, retry with --no-package-lock and warn. (b) Call this out in the release notes as a behavior change, not just a fix, so users who pinned a .qlty/qlty.toml snapshot expecting "latest" behavior know to re-check their lockfiles. (c) The changelog line is accurate but frames this only as a fix — worth a stronger "you may see different linter versions" callout on the release notes / docs.

[risky] qlty-check/src/tool/php/composer.rs:73-137, 219-283 — behavior change on existing command path (#2830)

  • Before: qlty check staged a copy of the repo's composer.lock but then ran composer update --no-interaction --ignore-platform-reqs, which re-resolves dependencies and rewrites the lock. Locked versions were effectively ignored.
  • After: When a lockfile was staged, composer install runs first (honors the lock). The staged lockfile also has packages-dev collapsed into packages so dev-locked linters (e.g. phpstan under require-dev) don't hard-error against the collapsed require in the staged composer.json. If composer install fails, code falls back to composer update with a warn! log line.
  • Who breaks:
    • Segment 1 (local devs) and Segment 2 (CI): Similar to the npm case — a repo with "squizlabs/php_codesniffer": "^3.8" and a lockfile pinning 3.8.0 was silently getting 3.13.5. After upgrade, that repo runs 3.8.0. Findings can shift on unchanged code (some rules added after 3.8.0 disappear, older rule bugs re-appear).
    • Segment 3 (Qlty Cloud): Same as above for PHP-linter workloads.
  • Suggested mitigation: The fallback to composer update on failure already limits the CI blast radius (a stale lock does not fail the build), so this is materially safer than the npm case. The behavior change is real but soft. Same "call out as a behavior change" note as above.

Categories checked and clear

  • CLI flag surface (no #[arg]/#[clap] additions, removals, or default changes)
  • qlty.toml schema (no serde field changes, no deny_unknown_fields, no config_version gating changes)
  • Output formats (no changes to print_*_as_json, qlty-types protos, qlty-coverage/src/print.rs, or scripted text output)
  • Exit codes (no ?/bail!/ensure! changes on command entry points)
  • Environment variables (no new/renamed QLTY_* handling, no auth token resolution changes)
  • Source fetching / cache layout (no .qlty/sources/, .qlty/cache/, or ~/.qlty/ layout changes; no GitSource/LocalSource/DefaultSource/SourcesList semantics changes)
  • Plugin schema (no plugin.toml schema, drivers, prepare_script, or affects_cache changes; no download URL patterns touched)
  • Telemetry / logging defaults (only additions of warn!/debug! on the new fallback path, no debug!warn!/error! promotions)
  • qlty coverage * commands (untouched — Segment 2's highest-stakes surface is not affected by this release)
  • Commands Qlty Cloud calls (qlty sources fetch, qlty config validate, qlty fmt --skip-source-fetch, qlty init, qlty install, qlty build) — only qlty install transitively touches the changed tool-install code paths, and only for node/PHP linters using package_file

Notes for reviewer

  • The changelog entries are accurate but describe both changes as pure fixes. They are fixes against documented behavior, but they will silently downgrade linter versions for any user whose lockfile is older than what npm/composer would otherwise resolve. Consider bolding this in the release announcement so users aren't caught off guard by shifting linter output.
  • Please verify with the fix(check): honor package-lock.json when installing from package_file #2829 author whether adding an npm install --no-package-lock retry-on-failure (mirroring the composer fallback in fix(check): honor composer.lock when installing from package_file #2830) is worth it. Without it, a stale lockfile is a hard install failure for the node path but a soft warning for the PHP path — asymmetric behavior that will confuse debugging.
  • No opt-in flag guards the new behavior; the only escape hatches are (a) delete the lockfile from the repo or (b) set package_filters (which suppresses staging the lockfile entirely). If a customer regresses on this release, that's the workaround to hand them until the retry-on-failure lands.

Generated by Claude Code

@qltysh

qltysh Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Qlty


Coverage Impact - macos-15

This PR will not change total coverage.

🚦 See full report on Qlty Cloud »

🛟 Help
  • Diff Coverage: Coverage for added or modified lines of code (excludes deleted files). Learn more.

  • Total Coverage: Coverage for the whole repository, calculated as the sum of all File Coverage. Learn more.

  • File Coverage: Covered Lines divided by Covered Lines plus Missed Lines. (Excludes non-executable lines including blank lines and comments.)

    • Indirect Changes: Changes to File Coverage for files that were not modified in this PR. Learn more.

@qltysh

qltysh Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Qlty


Coverage Impact - ubuntu-latest

⬇️ Merging this pull request will decrease total coverage on main by 0.01%.

🚦 See full report on Qlty Cloud »

🛟 Help
  • Diff Coverage: Coverage for added or modified lines of code (excludes deleted files). Learn more.

  • Total Coverage: Coverage for the whole repository, calculated as the sum of all File Coverage. Learn more.

  • File Coverage: Covered Lines divided by Covered Lines plus Missed Lines. (Excludes non-executable lines including blank lines and comments.)

    • Indirect Changes: Changes to File Coverage for files that were not modified in this PR. Learn more.

@marschattha
marschattha merged commit d9801f1 into main Jul 23, 2026
18 checks passed
@marschattha
marschattha deleted the release-0.639.0 branch July 23, 2026 20:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants