Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/funny-cheetahs-appear.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@changesets/cli": minor
"@changesets/types": minor
---

Adds an additional `dependencyType` argument to the `getDependencyReleaseLine` changelog function to distinguish peer dependency upgrades from normal dependency upgrades
6 changes: 6 additions & 0 deletions .changeset/polite-peaches-grin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@changesets/apply-release-plan": patch
"@changesets/cli": patch
---

Fix peer dependency changelog lines being added under 'patch' instead of 'major'
63 changes: 44 additions & 19 deletions packages/apply-release-plan/src/get-changelog-entry.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ChangelogFunctions, NewChangesetWithCommit } from "@changesets/types";

import { ModCompWithPackage } from "@changesets/types";
import { ModCompWithPackage, DependencyType } from "@changesets/types";
import startCase from "lodash.startcase";
import { shouldUpdateDependencyBasedOnConfig } from "./utils";

Expand All @@ -21,6 +21,20 @@ async function generateChangesForVersionTypeMarkdown(
}
}

function getRelevantChangesets(
releases: ModCompWithPackage[],
changesets: NewChangesetWithCommit[]
) {
let relevantChangesetIds: Set<string> = new Set();
releases.forEach(rel => {
rel.changesets.forEach(cs => {
relevantChangesetIds.add(cs);
});
});

return changesets.filter(cs => relevantChangesetIds.has(cs.id));
}

// release is the package and version we are releasing
export default async function getChangelogEntry(
release: ModCompWithPackage,
Expand Down Expand Up @@ -56,45 +70,56 @@ export default async function getChangelogEntry(
);
}
});
let dependentReleases = releases.filter(rel => {

let dependentReleases: ModCompWithPackage[] = [];
let peerDependentReleases: ModCompWithPackage[] = [];
releases.forEach(rel => {
const dependencyVersionRange = release.packageJson.dependencies?.[rel.name];
const peerDependencyVersionRange =
release.packageJson.peerDependencies?.[rel.name];
const depType: DependencyType = peerDependencyVersionRange
? "peerDependencies"
: "dependencies";
const versionRange = peerDependencyVersionRange || dependencyVersionRange;

const versionRange = dependencyVersionRange || peerDependencyVersionRange;
return (
const shouldUpdate =
versionRange &&
shouldUpdateDependencyBasedOnConfig(
{ type: rel.type, version: rel.newVersion },
{
depVersionRange: versionRange,
depType: dependencyVersionRange ? "dependencies" : "peerDependencies"
depType
},
{
minReleaseType: updateInternalDependencies,
onlyUpdatePeerDependentsWhenOutOfRange
}
)
);
});

let relevantChangesetIds: Set<string> = new Set();
);

dependentReleases.forEach(rel => {
rel.changesets.forEach(cs => {
relevantChangesetIds.add(cs);
});
if (!shouldUpdate) {
return;
}
if (depType === "peerDependencies") {
peerDependentReleases.push(rel);
} else {
dependentReleases.push(rel);
}
});

let relevantChangesets = changesets.filter(cs =>
relevantChangesetIds.has(cs.id)
changelogLines.major.push(
changelogFuncs.getDependencyReleaseLine(
getRelevantChangesets(peerDependentReleases, changesets),
peerDependentReleases,
changelogOpts,
"peerDependencies"
)
);

changelogLines.patch.push(
changelogFuncs.getDependencyReleaseLine(
relevantChangesets,
getRelevantChangesets(dependentReleases, changesets),
dependentReleases,
changelogOpts
changelogOpts,
"dependencies"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I read the code correctly this could actually be also caused by an optional dependency.

q: do you plan to utilize this new argument in your code?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Releases only contain packages specified in the dependencies and peerDependencies fields of package.json so I don't think optional dependencies would be included here unless they were also specified in dependencies which isn't recommended behaviour.

We're planning to use it to distinguish peer dep upgrade lines from non-peer dep ones so that we output a more detailed message for major peer upgrades.

This distinction could also be made using a bumpType or isPeer argument instead.

)
);

Expand Down
76 changes: 76 additions & 0 deletions packages/apply-release-plan/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1931,6 +1931,82 @@ describe("apply release plan", () => {

- Hey, let's have fun with testing!`);
});

it("should add peer dependency changelog line under major", async () => {
let { changedFiles } = await testSetup(
"simple-caret-peer-dep",
{
changesets: [
{
id: "quick-lions-devour",
summary: "Hey, let's have fun with testing!",
releases: [{ name: "depended-upon", type: "minor" }]
}
],
releases: [
{
name: "depended-upon",
type: "patch",
oldVersion: "1.0.0",
newVersion: "1.1.0",
changesets: ["quick-lions-devour"]
},
{
name: "has-peer-dep",
type: "patch",
oldVersion: "1.0.0",
newVersion: "2.0.0",
changesets: []
}
],
preState: undefined
},
{
changelog: [
path.resolve(__dirname, "test-utils/simple-get-changelog-entry"),
null
],
commit: false,
linked: [],
access: "restricted",
baseBranch: "main",
updateInternalDependencies: "patch",
ignore: [],
___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH: {
onlyUpdatePeerDependentsWhenOutOfRange: false,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity - so I assume that you are still using this default setting, doesn't it create major releases for you way too often?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah we are. It does for packages that have peer dependencies that upgrade frequently yes. The alternative though is that the minimum versions of peer dependency version ranges become stale which can break things, especially with aggressive de-duplication.

It probably is worth re-exploring though.

updateInternalDependents: "out-of-range",
useCalculatedVersionForSnapshots: false
}
}
);

let readmePath = changedFiles.find(a =>
a.endsWith(`depended-upon${path.sep}CHANGELOG.md`)
);
let readmePathB = changedFiles.find(a =>
a.endsWith(`has-peer-dep${path.sep}CHANGELOG.md`)
);

if (!readmePath || !readmePathB)
throw new Error(`could not find an updated changelog`);
let readme = await fs.readFile(readmePath, "utf-8");
let readmeB = await fs.readFile(readmePathB, "utf-8");

expect(readme.trim()).toEqual(outdent`# depended-upon

## 1.1.0
### Minor Changes

- Hey, let's have fun with testing!`);

expect(readmeB.trim()).toEqual(outdent`# has-peer-dep

## 2.0.0
### Major Changes

- Updated dependencies
- depended-upon@1.1.0`);
});
});
describe("should error and not write if", () => {
// This is skipped as *for now* we are assuming we have been passed
Expand Down
3 changes: 2 additions & 1 deletion packages/types/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ export type GetReleaseLine = (
export type GetDependencyReleaseLine = (
changesets: NewChangesetWithCommit[],
dependenciesUpdated: ModCompWithPackage[],
changelogOpts: any
changelogOpts: any,
dependencyType: DependencyType
) => Promise<string>;

export type ChangelogFunctions = {
Expand Down