Skip to content

Commit 52594b1

Browse files
authored
feat(changelog.json): implement changelog.json for python (#1841)
1 parent 1493bd7 commit 52594b1

File tree

5 files changed

+234
-0
lines changed

5 files changed

+234
-0
lines changed

__snapshots__/python.js

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
exports['Python buildUpdates updates changelog.json if present 1'] = `
2+
{
3+
"entries": [
4+
{
5+
"changes": [
6+
{
7+
"type": "fix",
8+
"sha": "845db1381b3d5d20151cad2588f85feb",
9+
"message": "update dependency com.google.cloud:google-cloud-storage to v1.120.0",
10+
"issues": [],
11+
"scope": "deps"
12+
},
13+
{
14+
"type": "chore",
15+
"sha": "b3f8966b023b8f21ce127142aa91841c",
16+
"message": "update a very important dep",
17+
"issues": [],
18+
"breakingChangeNote": "update a very important dep"
19+
},
20+
{
21+
"type": "fix",
22+
"sha": "08ca01180a91c0a1ba8992b491db9212",
23+
"message": "update dependency com.google.cloud:google-cloud-spanner to v1.50.0",
24+
"issues": [],
25+
"scope": "deps"
26+
}
27+
],
28+
"version": "0.1.0",
29+
"language": "PYTHON",
30+
"artifactName": "google-cloud-automl",
31+
"id": "abc-123-efd-qwerty",
32+
"createTime": "2023-01-05T16:42:33.446Z"
33+
}
34+
],
35+
"updateTime": "2023-01-05T16:42:33.446Z"
36+
}
37+
`

src/strategies/python.ts

+48
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import {BaseStrategy, BuildUpdatesOptions, BaseStrategyOptions} from './base';
1616
import {Update} from '../update';
1717
import {Changelog} from '../updaters/changelog';
18+
import {ChangelogJson} from '../updaters/changelog-json';
1819
import {Version} from '../version';
1920
import {SetupCfg} from '../updaters/python/setup-cfg';
2021
import {SetupPy} from '../updaters/python/setup-py';
@@ -24,6 +25,8 @@ import {
2425
PyProjectToml,
2526
} from '../updaters/python/pyproject-toml';
2627
import {PythonFileWithVersion} from '../updaters/python/python-file-with-version';
28+
import {FileNotFoundError} from '../errors';
29+
import {filterCommits} from '../util/filter-commits';
2730

2831
const CHANGELOG_SECTIONS = [
2932
{type: 'feat', section: 'Features'},
@@ -133,6 +136,22 @@ export class Python extends BaseStrategy {
133136
});
134137
});
135138

139+
// If a machine readable changelog.json exists update it:
140+
const artifactName = projectName ?? (await this.getNameFromSetupPy());
141+
if (options.commits && artifactName) {
142+
const commits = filterCommits(options.commits, this.changelogSections);
143+
updates.push({
144+
path: 'changelog.json',
145+
createIfMissing: false,
146+
updater: new ChangelogJson({
147+
artifactName,
148+
version,
149+
commits,
150+
language: 'PYTHON',
151+
}),
152+
});
153+
}
154+
136155
return updates;
137156
}
138157

@@ -148,6 +167,35 @@ export class Python extends BaseStrategy {
148167
}
149168
}
150169

170+
protected async getNameFromSetupPy(): Promise<string | null> {
171+
const ARTIFACT_NAME_REGEX = /name *= *['"](?<name>.*)['"](\r|\n|$)/;
172+
const setupPyContents = await this.getSetupPyContents();
173+
if (setupPyContents) {
174+
const match = setupPyContents.match(ARTIFACT_NAME_REGEX);
175+
if (match && match?.groups?.name) {
176+
return match.groups.name;
177+
}
178+
}
179+
return null;
180+
}
181+
182+
protected async getSetupPyContents(): Promise<string | null> {
183+
try {
184+
return (
185+
await this.github.getFileContentsOnBranch(
186+
this.addPath('setup.py'),
187+
this.targetBranch
188+
)
189+
).parsedContent;
190+
} catch (e) {
191+
if (e instanceof FileNotFoundError) {
192+
return null;
193+
} else {
194+
throw e;
195+
}
196+
}
197+
}
198+
151199
protected initialReleaseVersion(): Version {
152200
return Version.parse('0.1.0');
153201
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"repository": "google-cloud-foo",
3+
"entries": []
4+
}
+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Copyright 2018 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import io
16+
import os
17+
18+
import setuptools
19+
20+
name = "google-cloud-automl"
21+
description = "Cloud AutoML API client library"
22+
version = "0.5.0"
23+
release_status = "Development Status :: 3 - Alpha"
24+
dependencies = [
25+
"google-api-core[grpc] >= 1.14.0, < 2.0.0dev",
26+
'enum34; python_version < "3.4"',
27+
]
28+
extras = {
29+
"pandas": ["pandas>=0.24.0"],
30+
"storage": ["google-cloud-storage >= 1.18.0, < 2.0.0dev"],
31+
}
32+
33+
package_root = os.path.abspath(os.path.dirname(__file__))
34+
35+
readme_filename = os.path.join(package_root, "README.rst")
36+
with io.open(readme_filename, encoding="utf-8") as readme_file:
37+
readme = readme_file.read()
38+
39+
packages = [
40+
package for package in setuptools.find_packages() if package.startswith("google")
41+
]
42+
43+
namespaces = ["google"]
44+
if "google.cloud" in packages:
45+
namespaces.append("google.cloud")
46+
47+
setuptools.setup(
48+
name=name,
49+
version=version,
50+
description=description,
51+
long_description=readme,
52+
author="Google LLC",
53+
author_email="[email protected]",
54+
license="Apache 2.0",
55+
url="https://github.com/GoogleCloudPlatform/google-cloud-python",
56+
classifiers=[
57+
release_status,
58+
"Intended Audience :: Developers",
59+
"License :: OSI Approved :: Apache Software License",
60+
"Programming Language :: Python",
61+
"Programming Language :: Python :: 2",
62+
"Programming Language :: Python :: 2.7",
63+
"Programming Language :: Python :: 3",
64+
"Programming Language :: Python :: 3.5",
65+
"Programming Language :: Python :: 3.6",
66+
"Programming Language :: Python :: 3.7",
67+
"Operating System :: OS Independent",
68+
"Topic :: Internet",
69+
],
70+
platforms="Posix; MacOS X; Windows",
71+
packages=packages,
72+
namespace_packages=namespaces,
73+
install_requires=dependencies,
74+
extras_require=extras,
75+
python_requires=">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*",
76+
include_package_data=True,
77+
zip_safe=False,
78+
)

test/strategies/python.ts

+67
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,16 @@ import {PyProjectToml} from '../../src/updaters/python/pyproject-toml';
2626
import {SetupCfg} from '../../src/updaters/python/setup-cfg';
2727
import {SetupPy} from '../../src/updaters/python/setup-py';
2828
import {Changelog} from '../../src/updaters/changelog';
29+
import {ChangelogJson} from '../../src/updaters/changelog-json';
30+
import * as snapshot from 'snap-shot-it';
2931

3032
const sandbox = sinon.createSandbox();
33+
const fixturesPath = './test/fixtures/strategies/python';
34+
35+
const UUID_REGEX =
36+
/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/g;
37+
const ISO_DATE_REGEX =
38+
/[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]+Z/g; // 2023-01-05T16:42:33.446Z
3139

3240
const COMMITS = [
3341
...buildMockConventionalCommit(
@@ -59,6 +67,9 @@ describe('Python', () => {
5967
github,
6068
component: 'google-cloud-automl',
6169
});
70+
sandbox
71+
.stub(github, 'getFileContentsOnBranch')
72+
.resolves(buildGitHubFileContent(fixturesPath, 'setup.py'));
6273
sandbox.stub(github, 'findFilesByFilenameAndRef').resolves([]);
6374
const latestRelease = undefined;
6475
const release = await strategy.buildReleasePullRequest(
@@ -74,6 +85,9 @@ describe('Python', () => {
7485
github,
7586
component: 'google-cloud-automl',
7687
});
88+
sandbox
89+
.stub(github, 'getFileContentsOnBranch')
90+
.resolves(buildGitHubFileContent(fixturesPath, 'setup.py'));
7791
sandbox.stub(github, 'findFilesByFilenameAndRef').resolves([]);
7892
const latestRelease = {
7993
tag: new TagName(Version.parse('0.123.4'), 'google-cloud-automl'),
@@ -94,6 +108,9 @@ describe('Python', () => {
94108
github,
95109
component: 'google-cloud-automl',
96110
});
111+
sandbox
112+
.stub(github, 'getFileContentsOnBranch')
113+
.resolves(buildGitHubFileContent(fixturesPath, 'setup.py'));
97114
sandbox.stub(github, 'findFilesByFilenameAndRef').resolves([]);
98115
const latestRelease = undefined;
99116
const release = await strategy.buildReleasePullRequest(
@@ -153,6 +170,9 @@ describe('Python', () => {
153170
github,
154171
component: 'google-cloud-automl',
155172
});
173+
sandbox
174+
.stub(github, 'getFileContentsOnBranch')
175+
.resolves(buildGitHubFileContent(fixturesPath, 'setup.py'));
156176
sandbox
157177
.stub(github, 'findFilesByFilenameAndRef')
158178
.resolves(['src/version.py']);
@@ -164,5 +184,52 @@ describe('Python', () => {
164184
const updates = release!.updates;
165185
assertHasUpdate(updates, 'src/version.py', PythonFileWithVersion);
166186
});
187+
188+
it('updates changelog.json if present', async () => {
189+
const COMMITS = [
190+
...buildMockConventionalCommit(
191+
'fix(deps): update dependency com.google.cloud:google-cloud-storage to v1.120.0'
192+
),
193+
...buildMockConventionalCommit('chore: update deps'),
194+
...buildMockConventionalCommit('chore!: update a very important dep'),
195+
...buildMockConventionalCommit(
196+
'fix(deps): update dependency com.google.cloud:google-cloud-spanner to v1.50.0'
197+
),
198+
...buildMockConventionalCommit('chore: update common templates'),
199+
];
200+
const strategy = new Python({
201+
targetBranch: 'main',
202+
github,
203+
component: 'google-cloud-automl',
204+
});
205+
sandbox.stub(github, 'findFilesByFilenameAndRef').resolves([]);
206+
const getFileContentsStub = sandbox.stub(
207+
github,
208+
'getFileContentsOnBranch'
209+
);
210+
getFileContentsStub
211+
.withArgs('changelog.json', 'main')
212+
.resolves(buildGitHubFileContent(fixturesPath, 'changelog.json'));
213+
getFileContentsStub
214+
.withArgs('setup.py', 'main')
215+
.resolves(buildGitHubFileContent(fixturesPath, 'setup.py'));
216+
const latestRelease = undefined;
217+
const release = await strategy.buildReleasePullRequest(
218+
COMMITS,
219+
latestRelease
220+
);
221+
const updates = release!.updates;
222+
assertHasUpdate(updates, 'CHANGELOG.md', Changelog);
223+
const update = assertHasUpdate(updates, 'changelog.json', ChangelogJson);
224+
const newContent = update.updater.updateContent(
225+
JSON.stringify({entries: []})
226+
);
227+
snapshot(
228+
newContent
229+
.replace(/\r\n/g, '\n') // make newline consistent regardless of OS.
230+
.replace(UUID_REGEX, 'abc-123-efd-qwerty')
231+
.replace(ISO_DATE_REGEX, '2023-01-05T16:42:33.446Z')
232+
);
233+
});
167234
});
168235
});

0 commit comments

Comments
 (0)