Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
71ff282
feat: add automated dependency bump checker and changelog validator
cryptodev-2s Nov 6, 2025
8ee555d
refactor: inline package name resolution during diff parsing
cryptodev-2s Nov 6, 2025
084415e
refactor: use example repo name instead of core
cryptodev-2s Nov 6, 2025
2a87c2e
fix: remove useless re-exported types
cryptodev-2s Nov 6, 2025
88d116a
docs: add changelog entry for check-deps command
cryptodev-2s Nov 12, 2025
044b46e
fix: correct changelog entry order - BREAKING first, then deps
cryptodev-2s Dec 2, 2025
ccc66e2
fix: distinguish BREAKING entries when matching changelog entries
cryptodev-2s Dec 2, 2025
48221f2
fix: show correct section name in changelog validation error
cryptodev-2s Dec 2, 2025
045331a
feat: support renamed packages in changelog validation
cryptodev-2s Dec 2, 2025
8af5181
fix: include packageRename in second parseChangelog call
cryptodev-2s Dec 2, 2025
19c3ccd
fix: detect non-scoped package dependency changes
cryptodev-2s Dec 2, 2025
0d1de51
tests: add functional tests (#189)
cryptodev-2s Dec 3, 2025
49b197d
Fix optionalDependencies incorrectly attributed to dependencies section
cryptodev-2s Dec 3, 2025
b53e89c
Fix operator precedence in section boundary check
cryptodev-2s Dec 3, 2025
2f73bd8
Fix default branch check to use defaultBranch parameter instead of ha…
cryptodev-2s Dec 3, 2025
259d980
Reset section state when parsing new file in diff
cryptodev-2s Dec 3, 2025
703e1c3
Fix check-deps command usage in CHANGELOG
cryptodev-2s Dec 5, 2025
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
Prev Previous commit
Next Next commit
fix: show correct section name in changelog validation error
When validating changelogs for a release version, the error message
now correctly shows the version section (e.g., [1.2.3]) instead of
always showing [Unreleased].
  • Loading branch information
cryptodev-2s committed Dec 2, 2025
commit 48221f2118194a6051758ff80def286fef85a5d1
50 changes: 50 additions & 0 deletions src/changelog-validator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ describe('changelog-validator', () => {
hasUnreleasedSection: false,
missingEntries: mockChanges['controller-utils'].dependencyChanges,
existingEntries: [],
checkedVersion: null,
},
]);
});
Expand All @@ -73,6 +74,7 @@ describe('changelog-validator', () => {
hasUnreleasedSection: false,
missingEntries: mockChanges['controller-utils'].dependencyChanges,
existingEntries: [],
checkedVersion: null,
},
]);
});
Expand Down Expand Up @@ -102,6 +104,7 @@ describe('changelog-validator', () => {
hasUnreleasedSection: false,
missingEntries: mockChanges['controller-utils'].dependencyChanges,
existingEntries: [],
checkedVersion: null,
},
]);
});
Expand Down Expand Up @@ -131,6 +134,7 @@ describe('changelog-validator', () => {
hasUnreleasedSection: true,
missingEntries: mockChanges['controller-utils'].dependencyChanges,
existingEntries: [],
checkedVersion: null,
},
]);
});
Expand Down Expand Up @@ -166,6 +170,7 @@ describe('changelog-validator', () => {
hasUnreleasedSection: true,
missingEntries: [],
existingEntries: ['@metamask/transaction-controller'],
checkedVersion: null,
},
]);

Expand Down Expand Up @@ -217,6 +222,50 @@ describe('changelog-validator', () => {
hasUnreleasedSection: true,
missingEntries: [],
existingEntries: ['@metamask/transaction-controller'],
checkedVersion: '1.1.0',
},
]);
});

it('catches error when release version section does not exist', async () => {
when(jest.spyOn(fsModule, 'fileExists'))
.calledWith('/path/to/project/packages/controller-utils/CHANGELOG.md')
.mockResolvedValue(true);
when(jest.spyOn(fsModule, 'readFile'))
.calledWith('/path/to/project/packages/controller-utils/CHANGELOG.md')
.mockResolvedValue('# Changelog\n## [Unreleased]');
jest.spyOn(packageModule, 'formatChangelog').mockResolvedValue('');

const mockChangelog = {
getUnreleasedChanges: jest.fn().mockReturnValue({ Changed: [] }),
getReleaseChanges: jest.fn().mockImplementation(() => {
throw new Error('Version not found');
}),
};
(parseChangelog as jest.Mock).mockReturnValue(mockChangelog);

const changesWithVersion = {
'controller-utils': {
...mockChanges['controller-utils'],
newVersion: '1.2.3',
},
};

const results = await validateChangelogs(
changesWithVersion,
'/path/to/project',
'https://github.com/example-org/example-repo',
);

expect(mockChangelog.getReleaseChanges).toHaveBeenCalledWith('1.2.3');
expect(results).toStrictEqual([
{
package: 'controller-utils',
hasChangelog: true,
hasUnreleasedSection: false,
missingEntries: mockChanges['controller-utils'].dependencyChanges,
existingEntries: [],
checkedVersion: '1.2.3',
},
]);
});
Expand Down Expand Up @@ -314,6 +363,7 @@ describe('changelog-validator', () => {
'@metamask/transaction-controller',
'@metamask/transaction-controller',
],
checkedVersion: null,
},
]);
});
Expand Down
5 changes: 5 additions & 0 deletions src/changelog-validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ type ChangelogValidationResult = {
hasUnreleasedSection: boolean;
missingEntries: DependencyChange[];
existingEntries: string[];
/** Version that was checked (null for [Unreleased] section) */
checkedVersion?: string | null;
};

/**
Expand Down Expand Up @@ -169,6 +171,7 @@ export async function validateChangelogs(
hasUnreleasedSection: false,
missingEntries: packageChanges,
existingEntries: [],
checkedVersion: packageVersion ?? null,
});
continue;
}
Expand Down Expand Up @@ -213,6 +216,7 @@ export async function validateChangelogs(
hasUnreleasedSection,
missingEntries,
existingEntries,
checkedVersion: packageVersion ?? null,
});
} catch (error) {
// If parsing fails, assume changelog is malformed
Expand All @@ -222,6 +226,7 @@ export async function validateChangelogs(
hasUnreleasedSection: false,
missingEntries: packageChanges,
existingEntries: [],
checkedVersion: packageVersion ?? null,
});
}
}
Expand Down
84 changes: 84 additions & 0 deletions src/check-dependency-bumps.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ index 1234567..890abcd 100644
hasUnreleasedSection: true,
missingEntries: [],
existingEntries: ['@metamask/transaction-controller'],
checkedVersion: null,
},
]);

Expand Down Expand Up @@ -616,6 +617,7 @@ diff --git a/packages/controller-utils/package.json b/packages/controller-utils/
},
],
existingEntries: [],
checkedVersion: null,
},
]);

Expand Down Expand Up @@ -684,6 +686,7 @@ diff --git a/packages/controller-utils/package.json b/packages/controller-utils/
hasUnreleasedSection: false,
missingEntries: [],
existingEntries: [],
checkedVersion: null,
},
]);

Expand All @@ -701,6 +704,83 @@ diff --git a/packages/controller-utils/package.json b/packages/controller-utils/
);
});

it('reports correct section name when checking release version', async () => {
const stderrWriteSpy = jest.spyOn(stderr, 'write');
const getStdoutSpy = jest.spyOn(miscUtilsModule, 'getStdoutFromCommand');

const diffWithVersion = `
diff --git a/packages/controller-utils/package.json b/packages/controller-utils/package.json
index 1234567..890abcd 100644
--- a/packages/controller-utils/package.json
+++ b/packages/controller-utils/package.json
@@ -1,6 +1,6 @@
{
"name": "@metamask/controller-utils",
- "version": "1.2.2",
+ "version": "1.2.3",
"dependencies": {
- "@metamask/transaction-controller": "^61.0.0"
+ "@metamask/transaction-controller": "^62.0.0"
}
}
`;

when(getStdoutSpy)
.calledWith(
'git',
['diff', '-U9999', 'abc123', 'HEAD', '--', '**/package.json'],
{ cwd: '/path/to/project' },
)
.mockResolvedValue(diffWithVersion);

when(jest.spyOn(packageManifestModule, 'readPackageManifest'))
.calledWith('/path/to/project/package.json')
.mockResolvedValue({
unvalidated: {},
validated: buildMockManifest(),
});

when(jest.spyOn(packageManifestModule, 'readPackageManifest'))
.calledWith('/path/to/project/packages/controller-utils/package.json')
.mockResolvedValue({
unvalidated: {},
validated: buildMockManifest({
name: '@metamask/controller-utils',
}),
});

jest
.spyOn(projectModule, 'getValidRepositoryUrl')
.mockResolvedValue('https://github.com/example-org/example-repo');

const validateChangelogsSpy = jest
.spyOn(changelogValidatorModule, 'validateChangelogs')
.mockResolvedValue([
{
package: 'controller-utils',
hasChangelog: true,
hasUnreleasedSection: false,
missingEntries: [],
existingEntries: [],
checkedVersion: '1.2.3',
},
]);

await checkDependencyBumps({
fromRef: 'abc123',
projectRoot: '/path/to/project',
stdout,
stderr,
});

expect(validateChangelogsSpy).toHaveBeenCalled();
expect(stderrWriteSpy).toHaveBeenCalledWith(
expect.stringContaining(
'❌ controller-utils: No [1.2.3] section found',
),
);
});

it('reports validation errors for missing changelog entries', async () => {
const stderrWriteSpy = jest.spyOn(stderr, 'write');
const getStdoutSpy = jest.spyOn(miscUtilsModule, 'getStdoutFromCommand');
Expand Down Expand Up @@ -759,6 +839,7 @@ diff --git a/packages/controller-utils/package.json b/packages/controller-utils/
},
],
existingEntries: [],
checkedVersion: null,
},
]);

Expand Down Expand Up @@ -846,6 +927,7 @@ diff --git a/packages/controller-utils/package.json b/packages/controller-utils/
},
],
existingEntries: [],
checkedVersion: null,
},
]);

Expand Down Expand Up @@ -919,6 +1001,7 @@ diff --git a/packages/controller-utils/package.json b/packages/controller-utils/
hasUnreleasedSection: true,
missingEntries: [],
existingEntries: ['@metamask/transaction-controller'],
checkedVersion: null,
},
]);

Expand Down Expand Up @@ -992,6 +1075,7 @@ diff --git a/packages/controller-utils/package.json b/packages/controller-utils/
},
],
existingEntries: [],
checkedVersion: null,
},
]);

Expand Down
5 changes: 4 additions & 1 deletion src/check-dependency-bumps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,10 @@ export async function checkDependencyBumps({
stderr.write(`❌ ${result.package}: CHANGELOG.md not found\n`);
hasErrors = true;
} else if (!result.hasUnreleasedSection) {
stderr.write(`❌ ${result.package}: No [Unreleased] section found\n`);
const sectionName = result.checkedVersion
? `[${result.checkedVersion}]`
: '[Unreleased]';
stderr.write(`❌ ${result.package}: No ${sectionName} section found\n`);
hasErrors = true;
} else if (result.missingEntries.length > 0) {
stderr.write(
Expand Down
Loading