Merge branch 'stable-3.3' into master
* stable-3.3: Update git submodules Update git submodules Update git submodules Update git submodules Update git submodules Bump Bazel version to 3.7.0 Documentation: Update dev-release's rc information Remove the now unnecessary 'check' option from release_noter Fix linked subjects formatting in release_noter.py Treat plugin submodule changes like other core commits in release_noter Add editorconfig to release_noter for proper indent Update git submodules Update git submodules Set version to 3.3.0-SNAPSHOT Set version to 3.3.0-rc3 Update git submodules Fix tests for stable-2.16 branch Remove generation for c.g.gwtexpui.* JavaDoc Fetch JGit JavaDoc from archive.eclipse.org Upgrade truth to 1.1 Upgrade metrics-core to 4.1.14 Update git submodules Add some more excluded subjects to release_noter Do not overwrite generated release_noter markdown files Add release markdown file template to release_noter Add makefile to release_noter thus improve README Split release_noter generated notes into more component sections Improve rendering issues in generated release_noter markdown Add link option to release_noter so it links commits to change in Gerrit Escape marked-down angle brackets in release_noter Document how to configure multiple ldap servers Change-Id: I1c27d0397606d63ed4f71a10a7a7434da88421e5
This commit is contained in:
@@ -1 +1 @@
|
||||
3.5.1
|
||||
3.7.0
|
||||
|
||||
@@ -3397,6 +3397,11 @@ and group membership from. Must be of the form `ldap://host` or
|
||||
If `auth.type` is `LDAP` this setting should use `ldaps://` to
|
||||
ensure the end user's plaintext password is transmitted only over
|
||||
an encrypted connection.
|
||||
+
|
||||
If you want to configure multiple ldap servers you can try to put
|
||||
multiple ldap urls separated by a space:
|
||||
`server = ldaps://ldap1 ldaps://ldap2`
|
||||
See https://bugs.chromium.org/p/gerrit/issues/detail?id=10841[issue 10841].
|
||||
|
||||
[[ldap.startTls]]ldap.startTls::
|
||||
+
|
||||
|
||||
@@ -27,14 +27,19 @@ need to undergo some stabilization before releasing the final release.
|
||||
|
||||
* Propose the release with any plans/objectives to the mailing list.
|
||||
|
||||
* Release plans usually become a
|
||||
link:https://www.gerritcodereview.com/news.html[news article]
|
||||
to be followed up with.
|
||||
|
||||
* Create a Gerrit `rc0`.
|
||||
|
||||
* If needed create a Gerrit `rc1`.
|
||||
* If needed create Gerrit `rc1`, `rc2` and `rc3` (one per week, on Mondays
|
||||
or so; see link:https://www.gerritcodereview.com/news.html[past release plans]).
|
||||
|
||||
[NOTE]
|
||||
You may let in a few features to this release.
|
||||
You may let in a few features to these releases.
|
||||
|
||||
* If needed create a Gerrit `rc2`.
|
||||
* If needed create a Gerrit `rc4`.
|
||||
|
||||
[NOTE]
|
||||
There should be no new features in this release, only bug fixes.
|
||||
|
||||
10
WORKSPACE
10
WORKSPACE
@@ -875,30 +875,30 @@ maven_jar(
|
||||
sha1 = "42a25dc3219429f0e5d060061f71acb49bf010a0",
|
||||
)
|
||||
|
||||
TRUTH_VERS = "1.0.1"
|
||||
TRUTH_VERS = "1.1"
|
||||
|
||||
maven_jar(
|
||||
name = "truth",
|
||||
artifact = "com.google.truth:truth:" + TRUTH_VERS,
|
||||
sha1 = "361459309085bd9441cb97b62f160e8b353a93c0",
|
||||
sha1 = "6a096a16646559c24397b03f797d0c9d75ee8720",
|
||||
)
|
||||
|
||||
maven_jar(
|
||||
name = "truth-java8-extension",
|
||||
artifact = "com.google.truth.extensions:truth-java8-extension:" + TRUTH_VERS,
|
||||
sha1 = "ef07b2cc2201472381fdd3bcf773310e22bb9080",
|
||||
sha1 = "258db6eb8df61832c5c059ed2bc2e1c88683e92f",
|
||||
)
|
||||
|
||||
maven_jar(
|
||||
name = "truth-liteproto-extension",
|
||||
artifact = "com.google.truth.extensions:truth-liteproto-extension:" + TRUTH_VERS,
|
||||
sha1 = "bd1f5ac8a5f66e60cd1738f7b95c97a582ffcef9",
|
||||
sha1 = "bf65afa13aa03330e739bcaa5d795fe0f10fbf20",
|
||||
)
|
||||
|
||||
maven_jar(
|
||||
name = "truth-proto-extension",
|
||||
artifact = "com.google.truth.extensions:truth-proto-extension:" + TRUTH_VERS,
|
||||
sha1 = "039aa2d7c9196b30d367eac7cb467ecaa726e23d",
|
||||
sha1 = "64cba89cf87c1d84cb8c81d06f0b9c482f10b4dc",
|
||||
)
|
||||
|
||||
maven_jar(
|
||||
|
||||
@@ -23,8 +23,8 @@ def declare_nongoogle_deps():
|
||||
|
||||
maven_jar(
|
||||
name = "dropwizard-core",
|
||||
artifact = "io.dropwizard.metrics:metrics-core:4.1.12.1",
|
||||
sha1 = "cb2f351bf4463751201f43bb99865235d5ba07ca",
|
||||
artifact = "io.dropwizard.metrics:metrics-core:4.1.14",
|
||||
sha1 = "14cf9dd67619a0390812dddb232df339e3383d35",
|
||||
)
|
||||
|
||||
SSHD_VERS = "2.4.0"
|
||||
|
||||
2
tools/release_noter/.editorconfig
Normal file
2
tools/release_noter/.editorconfig
Normal file
@@ -0,0 +1,2 @@
|
||||
[*.py]
|
||||
indent_size = 4
|
||||
2
tools/release_noter/.gitignore
vendored
2
tools/release_noter/.gitignore
vendored
@@ -1,2 +1,2 @@
|
||||
/.idea/
|
||||
/release_noter.md
|
||||
/release_noter*.md
|
||||
|
||||
26
tools/release_noter/Makefile
Normal file
26
tools/release_noter/Makefile
Normal file
@@ -0,0 +1,26 @@
|
||||
COMMITS := 10
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: deploy black flake test
|
||||
|
||||
clean:
|
||||
rm -f release_noter*.md
|
||||
|
||||
setup:
|
||||
pipenv install --dev
|
||||
|
||||
deploy:
|
||||
pipenv install --dev --deploy
|
||||
|
||||
black:
|
||||
pipenv run black release_noter.py
|
||||
|
||||
flake:
|
||||
pipenv run flake8 release_noter.py
|
||||
|
||||
help:
|
||||
pipenv run python release_noter.py -h
|
||||
|
||||
test:
|
||||
pipenv run python release_noter.py HEAD~$(COMMITS)..HEAD -l
|
||||
@@ -8,6 +8,8 @@ black = { version = "==20.8b1", markers = "python_version >= '3.8'" }
|
||||
flake8 = { version = "==3.8.4", markers = "python_version >= '3.8'" }
|
||||
|
||||
[packages]
|
||||
jinja2 = { version = "==2.11.2", markers = "python_version >= '3.8'" }
|
||||
pygerrit2 = { version = "==2.0.13", markers = "python_version >= '3.8'" }
|
||||
|
||||
[requires]
|
||||
python_version = "3.8"
|
||||
|
||||
163
tools/release_noter/Pipfile.lock
generated
163
tools/release_noter/Pipfile.lock
generated
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "9a69912e043a63c885e5f7e15fb5011ca20c3de0e7fc8e9d26bd8eaed1f58fa9"
|
||||
"sha256": "66a7d7fdb0a62b702f5414852b80c579a3c16d7a4ed1f3b5344943437c6157ee"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
@@ -15,7 +15,110 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {},
|
||||
"default": {
|
||||
"certifi": {
|
||||
"hashes": [
|
||||
"sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3",
|
||||
"sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41"
|
||||
],
|
||||
"version": "==2020.6.20"
|
||||
},
|
||||
"chardet": {
|
||||
"hashes": [
|
||||
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
|
||||
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
|
||||
],
|
||||
"version": "==3.0.4"
|
||||
},
|
||||
"idna": {
|
||||
"hashes": [
|
||||
"sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6",
|
||||
"sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==2.10"
|
||||
},
|
||||
"jinja2": {
|
||||
"hashes": [
|
||||
"sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0",
|
||||
"sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"
|
||||
],
|
||||
"index": "pypi",
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==2.11.2"
|
||||
},
|
||||
"markupsafe": {
|
||||
"hashes": [
|
||||
"sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473",
|
||||
"sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161",
|
||||
"sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235",
|
||||
"sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5",
|
||||
"sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42",
|
||||
"sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff",
|
||||
"sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b",
|
||||
"sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1",
|
||||
"sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e",
|
||||
"sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183",
|
||||
"sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66",
|
||||
"sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b",
|
||||
"sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1",
|
||||
"sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15",
|
||||
"sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1",
|
||||
"sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e",
|
||||
"sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b",
|
||||
"sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905",
|
||||
"sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735",
|
||||
"sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d",
|
||||
"sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e",
|
||||
"sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d",
|
||||
"sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c",
|
||||
"sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21",
|
||||
"sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2",
|
||||
"sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5",
|
||||
"sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b",
|
||||
"sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6",
|
||||
"sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f",
|
||||
"sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f",
|
||||
"sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2",
|
||||
"sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7",
|
||||
"sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==1.1.1"
|
||||
},
|
||||
"pbr": {
|
||||
"hashes": [
|
||||
"sha256:14bfd98f51c78a3dd22a1ef45cf194ad79eee4a19e8e1a0d5c7f8e81ffe182ea",
|
||||
"sha256:5adc0f9fc64319d8df5ca1e4e06eea674c26b80e6f00c530b18ce6a6592ead15"
|
||||
],
|
||||
"markers": "python_version >= '2.6'",
|
||||
"version": "==5.5.0"
|
||||
},
|
||||
"pygerrit2": {
|
||||
"hashes": [
|
||||
"sha256:4e3c66017e02833bb9302f98fca47fb21cc01d5d2281d62eaefa18e8bd2c2c08"
|
||||
],
|
||||
"index": "pypi",
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==2.0.13"
|
||||
},
|
||||
"requests": {
|
||||
"hashes": [
|
||||
"sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b",
|
||||
"sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==2.24.0"
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
"sha256:91056c15fa70756691db97756772bb1eb9678fa585d9184f24534b100dc60f4a",
|
||||
"sha256:e7983572181f5e1522d9c98453462384ee92a0be7fac5f1413a1e35c56cc0461"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
|
||||
"version": "==1.25.10"
|
||||
}
|
||||
},
|
||||
"develop": {
|
||||
"appdirs": {
|
||||
"hashes": [
|
||||
@@ -88,35 +191,35 @@
|
||||
},
|
||||
"regex": {
|
||||
"hashes": [
|
||||
"sha256:1a16afbfadaadc1397353f9b32e19a65dc1d1804c80ad73a14f435348ca017ad",
|
||||
"sha256:2308491b3e6c530a3bb38a8a4bb1dc5fd32cbf1e11ca623f2172ba17a81acef1",
|
||||
"sha256:39a5ef30bca911f5a8a3d4476f5713ed4d66e313d9fb6755b32bec8a2e519635",
|
||||
"sha256:3d5a8d007116021cf65355ada47bf405656c4b3b9a988493d26688275fde1f1c",
|
||||
"sha256:4302153abb96859beb2c778cc4662607a34175065fc2f33a21f49eb3fbd1ccd3",
|
||||
"sha256:463e770c48da76a8da82b8d4a48a541f314e0df91cbb6d873a341dbe578efafd",
|
||||
"sha256:46ab6070b0d2cb85700b8863b3f5504c7f75d8af44289e9562195fe02a8dd72d",
|
||||
"sha256:4f5c0fe46fb79a7adf766b365cae56cafbf352c27358fda811e4a1dc8216d0db",
|
||||
"sha256:60c4f64d9a326fe48e8738c3dbc068e1edc41ff7895a9e3723840deec4bc1c28",
|
||||
"sha256:671c51d352cfb146e48baee82b1ee8d6ffe357c292f5e13300cdc5c00867ebfc",
|
||||
"sha256:6cf527ec2f3565248408b61dd36e380d799c2a1047eab04e13a2b0c15dd9c767",
|
||||
"sha256:7c4fc5a8ec91a2254bb459db27dbd9e16bba1dabff638f425d736888d34aaefa",
|
||||
"sha256:850339226aa4fec04916386577674bb9d69abe0048f5d1a99f91b0004bfdcc01",
|
||||
"sha256:8ba3efdd60bfee1aa784dbcea175eb442d059b576934c9d099e381e5a9f48930",
|
||||
"sha256:8c8c42aa5d3ac9a49829c4b28a81bebfa0378996f9e0ca5b5ab8a36870c3e5ee",
|
||||
"sha256:8e7ef296b84d44425760fe813cabd7afbb48c8dd62023018b338bbd9d7d6f2f0",
|
||||
"sha256:a2a31ee8a354fa3036d12804730e1e20d58bc4e250365ead34b9c30bbe9908c3",
|
||||
"sha256:a63907332531a499b8cdfd18953febb5a4c525e9e7ca4ac147423b917244b260",
|
||||
"sha256:a8240df4957a5b0e641998a5d78b3c4ea762c845d8cb8997bf820626826fde9a",
|
||||
"sha256:b8806649983a1c78874ec7e04393ef076805740f6319e87a56f91f1767960212",
|
||||
"sha256:c077c9d04a040dba001cf62b3aff08fd85be86bccf2c51a770c77377662a2d55",
|
||||
"sha256:c529ba90c1775697a65b46c83d47a2d3de70f24d96da5d41d05a761c73b063af",
|
||||
"sha256:d537e270b3e6bfaea4f49eaf267984bfb3628c86670e9ad2a257358d3b8f0955",
|
||||
"sha256:d629d750ebe75a88184db98f759633b0a7772c2e6f4da529f0027b4a402c0e2f",
|
||||
"sha256:d9d53518eeed12190744d366ec4a3f39b99d7daa705abca95f87dd8b442df4ad",
|
||||
"sha256:e490f08897cb44e54bddf5c6e27deca9b58c4076849f32aaa7a0b9f1730f2c20",
|
||||
"sha256:f579caecbbca291b0fcc7d473664c8c08635da2f9b1567c22ea32311c86ef68c"
|
||||
"sha256:02686a2f0b1a4be0facdd0d3ad4dc6c23acaa0f38fb5470d892ae88584ba705c",
|
||||
"sha256:137da580d1e6302484be3ef41d72cf5c3ad22a076070051b7449c0e13ab2c482",
|
||||
"sha256:20cdd7e1736f4f61a5161aa30d05ac108ab8efc3133df5eb70fe1e6a23ea1ca6",
|
||||
"sha256:25991861c6fef1e5fd0a01283cf5658c5e7f7aa644128e85243bc75304e91530",
|
||||
"sha256:26b85672275d8c7a9d4ff93dbc4954f5146efdb2ecec89ad1de49439984dea14",
|
||||
"sha256:2f60ba5c33f00ce9be29a140e6f812e39880df8ba9cb92ad333f0016dbc30306",
|
||||
"sha256:3dd952f3f8dc01b72c0cf05b3631e05c50ac65ddd2afdf26551638e97502107b",
|
||||
"sha256:578ac6379e65eb8e6a85299b306c966c852712c834dc7eef0ba78d07a828f67b",
|
||||
"sha256:5d4a3221f37520bb337b64a0632716e61b26c8ae6aaffceeeb7ad69c009c404b",
|
||||
"sha256:608d6c05452c0e6cc49d4d7407b4767963f19c4d2230fa70b7201732eedc84f2",
|
||||
"sha256:65b6b018b07e9b3b6a05c2c3bb7710ed66132b4df41926c243887c4f1ff303d5",
|
||||
"sha256:698f8a5a2815e1663d9895830a063098ae2f8f2655ae4fdc5dfa2b1f52b90087",
|
||||
"sha256:6c72adb85adecd4522a488a751e465842cdd2a5606b65464b9168bf029a54272",
|
||||
"sha256:6d4cdb6c20e752426b2e569128488c5046fb1b16b1beadaceea9815c36da0847",
|
||||
"sha256:6e9f72e0ee49f7d7be395bfa29e9533f0507a882e1e6bf302c0a204c65b742bf",
|
||||
"sha256:828618f3c3439c5e6ef8621e7c885ca561bbaaba90ddbb6a7dfd9e1ec8341103",
|
||||
"sha256:85b733a1ef2b2e7001aff0e204a842f50ad699c061856a214e48cfb16ace7d0c",
|
||||
"sha256:8958befc139ac4e3f16d44ec386c490ea2121ed8322f4956f83dd9cad8e9b922",
|
||||
"sha256:a51e51eecdac39a50ede4aeed86dbef4776e3b73347d31d6ad0bc9648ba36049",
|
||||
"sha256:aeac7c9397480450016bc4a840eefbfa8ca68afc1e90648aa6efbfe699e5d3bb",
|
||||
"sha256:aef23aed9d4017cc74d37f703d57ce254efb4c8a6a01905f40f539220348abf9",
|
||||
"sha256:af1f5e997dd1ee71fb6eb4a0fb6921bf7a778f4b62f1f7ef0d7445ecce9155d6",
|
||||
"sha256:b5eeaf4b5ef38fab225429478caf71f44d4a0b44d39a1aa4d4422cda23a9821b",
|
||||
"sha256:d25f5cca0f3af6d425c9496953445bf5b288bb5b71afc2b8308ad194b714c159",
|
||||
"sha256:d81be22d5d462b96a2aa5c512f741255ba182995efb0114e5a946fe254148df1",
|
||||
"sha256:e935a166a5f4c02afe3f7e4ce92ce5a786f75c6caa0c4ce09c922541d74b77e8",
|
||||
"sha256:ef3a55b16c6450574734db92e0a3aca283290889934a23f7498eaf417e3af9f0"
|
||||
],
|
||||
"version": "==2020.10.11"
|
||||
"version": "==2020.10.15"
|
||||
},
|
||||
"toml": {
|
||||
"hashes": [
|
||||
|
||||
@@ -2,30 +2,52 @@
|
||||
|
||||
## Setup
|
||||
|
||||
The `--deploy` option is to be removed if `Pipfile.lock` is out of date.
|
||||
|
||||
```bash
|
||||
pipenv install --dev
|
||||
pipenv install --dev --deploy
|
||||
make setup
|
||||
make deploy
|
||||
```
|
||||
|
||||
* The `deploy` target may not succeed if `Pipfile.lock` is out of date.
|
||||
* The `setup` target can be used first in such a case.
|
||||
* Using `make all` will run the `deploy` target, among the other key targets.
|
||||
|
||||
## Warning
|
||||
|
||||
The make `clean` target removes any previously made `release_noter*.md` file(s).
|
||||
|
||||
Running `release_noter.py` multiple times without cleaning creates the next `N`
|
||||
`release_noter-N.md` file, without overwriting the previous one(s).
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
pipenv run python release_noter.py -h
|
||||
make help
|
||||
```
|
||||
|
||||
* The resulting `release_noter*.md` file(s) can be edited then copied over to the `homepage`.
|
||||
* The markdown file name should be `x.y.md`, where `x.y` is the major release version.
|
||||
* Alternatively, an existing `x.y.md` can be edited with `release_noter*.md` snippets.
|
||||
|
||||
## Testing
|
||||
|
||||
```bash
|
||||
make test
|
||||
make test COMMITS=100
|
||||
```
|
||||
|
||||
This target will use the `-l` option, which takes more time as `COMMITS` increases.
|
||||
|
||||
## Examples
|
||||
|
||||
```bash
|
||||
pipenv run python release_noter.py v3.2.3..HEAD
|
||||
pipenv run python release_noter.py v3.2.3..v3.3.0-rc0
|
||||
pipenv run python release_noter.py v3.2.3..v3.3.0-rc0 -c
|
||||
pipenv run python release_noter.py v3.2.3..v3.3.0-rc0 -l
|
||||
```
|
||||
|
||||
## Coding
|
||||
|
||||
```bash
|
||||
pipenv run black release_noter.py
|
||||
pipenv run flake8 release_noter.py
|
||||
make black
|
||||
make flake
|
||||
```
|
||||
|
||||
36
tools/release_noter/release_noter.md.template
Normal file
36
tools/release_noter/release_noter.md.template
Normal file
@@ -0,0 +1,36 @@
|
||||
---
|
||||
title: "Gerrit {{ data.new }} release (in development)"
|
||||
permalink: {{ data.major }}.html
|
||||
hide_sidebar: true
|
||||
hide_navtoggle: true
|
||||
toc: true
|
||||
---
|
||||
|
||||
Download: **[{{ data.new }}](https://gerrit-releases.storage.googleapis.com/gerrit-{{ data.new }}.war)**
|
||||
| [{{ data.previous }}](https://gerrit-releases.storage.googleapis.com/gerrit-{{ data.previous }}.war)
|
||||
|
||||
Documentation: **[{{ data.new }}](https://gerrit-documentation.storage.googleapis.com/Documentation/{{ data.doc }}/index.html)**
|
||||
| [{{ data.previous }}](https://gerrit-documentation.storage.googleapis.com/Documentation/{{ data.previous }}/index.html)
|
||||
|
||||
## Release highlights
|
||||
|
||||
## Important notes
|
||||
|
||||
### Schema changes
|
||||
|
||||
### Breaking changes
|
||||
|
||||
## Native packaging
|
||||
|
||||
## New features
|
||||
|
||||
### REST APIs
|
||||
|
||||
* Accounts
|
||||
* Changes
|
||||
* Groups
|
||||
* Projects
|
||||
|
||||
## End-to-end tests
|
||||
|
||||
## Plugin changes
|
||||
@@ -1,34 +1,62 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
from enum import Enum
|
||||
from jinja2 import Template
|
||||
from os import path
|
||||
from pygerrit2 import Anonymous, GerritRestAPI
|
||||
|
||||
EXCLUDED_SUBJECTS = {
|
||||
"annotat",
|
||||
"assert",
|
||||
"AutoValue",
|
||||
"avadoc",
|
||||
"avadoc", # Javadoc &co.
|
||||
"avaDoc",
|
||||
"ava-doc",
|
||||
"baz", # bazel, bazlet(s)
|
||||
"Baz",
|
||||
"circular",
|
||||
"class",
|
||||
"efactor",
|
||||
"common.ts",
|
||||
"construct",
|
||||
"controls",
|
||||
"debounce",
|
||||
"Debounce",
|
||||
"decorat",
|
||||
"efactor", # Refactor &co.
|
||||
"format",
|
||||
"Format",
|
||||
"getter",
|
||||
"gr-",
|
||||
"hide",
|
||||
"icon",
|
||||
"ignore",
|
||||
"immutab",
|
||||
"import",
|
||||
"inject",
|
||||
"iterat",
|
||||
"IT",
|
||||
"js",
|
||||
"label",
|
||||
"licence",
|
||||
"license",
|
||||
"lint",
|
||||
"listener",
|
||||
"Listener",
|
||||
"lock",
|
||||
"method",
|
||||
"metric",
|
||||
"mock",
|
||||
"module",
|
||||
"naming",
|
||||
"nits",
|
||||
"nongoogle",
|
||||
"prone", # error prone &co.
|
||||
"Prone",
|
||||
"register",
|
||||
"Register",
|
||||
"remove",
|
||||
@@ -37,6 +65,8 @@ EXCLUDED_SUBJECTS = {
|
||||
"Rename",
|
||||
"Revert",
|
||||
"serializ",
|
||||
"Serializ",
|
||||
"server.go",
|
||||
"setter",
|
||||
"spell",
|
||||
"Spell",
|
||||
@@ -44,25 +74,34 @@ EXCLUDED_SUBJECTS = {
|
||||
"Test",
|
||||
"thread",
|
||||
"tsetse",
|
||||
"typescript",
|
||||
"type",
|
||||
"Type",
|
||||
"typo",
|
||||
"util",
|
||||
"variable",
|
||||
"version",
|
||||
"warning",
|
||||
}
|
||||
|
||||
COMMIT_SHA1_PATTERN = r"^commit ([a-z0-9]+)$"
|
||||
DATE_HEADER_PATTERN = r"Date: .+"
|
||||
SUBJECT_SUBMODULES_PATTERN = r"^Update git submodules$"
|
||||
UPDATE_SUBMODULE_PATTERN = r"\* Update ([a-z/\-]+) from branch '.+'"
|
||||
SUBMODULE_SUBJECT_PATTERN = r"^- (.+)"
|
||||
SUBMODULE_MERGE_PATTERN = r".+Merge .+"
|
||||
ISSUE_ID_PATTERN = r"[a-zA-Z]+: [Ii]ssue ([0-9]+)"
|
||||
CHANGE_ID_PATTERN = r"^Change-Id: [I0-9a-z]+$"
|
||||
PLUGIN_PATTERN = r"plugins/([a-z\-]+)"
|
||||
RELEASE_OPTION_PATTERN = r".+\.\.(v.+)"
|
||||
RELEASE_TAG_PATTERN = r"v[0-9]+\.[0-9]+\.[0-9]+$"
|
||||
RELEASE_VERSIONS_PATTERN = r"v([0-9\.\-rc]+)\.\.v([0-9\.\-rc]+)"
|
||||
RELEASE_MAJOR_PATTERN = r"^([0-9]+\.[0-9]+).+"
|
||||
RELEASE_DOC_PATTERN = r"^([0-9]+\.[0-9]+\.[0-9]+).*"
|
||||
|
||||
CHANGE_URL = "/c/gerrit/+/"
|
||||
COMMIT_URL = "/changes/?q=commit%3A"
|
||||
GERRIT_URL = "https://gerrit-review.googlesource.com"
|
||||
ISSUE_URL = "https://bugs.chromium.org/p/gerrit/issues/detail?id="
|
||||
CHECK_DISCLAIMER = "experimental and much slower"
|
||||
|
||||
MARKDOWN = "release_noter"
|
||||
GIT_COMMAND = "git"
|
||||
GIT_PATH = "../.."
|
||||
PLUGINS = "plugins/"
|
||||
UTF8 = "UTF-8"
|
||||
|
||||
|
||||
@@ -72,95 +111,95 @@ def parse_args():
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
)
|
||||
parser.add_argument(
|
||||
"-c",
|
||||
"--check",
|
||||
dest="check",
|
||||
"-l",
|
||||
"--link",
|
||||
dest="link",
|
||||
required=False,
|
||||
default=False,
|
||||
action="store_true",
|
||||
help=f"check commits for previous releases; {CHECK_DISCLAIMER}",
|
||||
help="link commits to change in Gerrit; slower as it gets each _number from gerrit",
|
||||
)
|
||||
parser.add_argument("range", help="git log revision range")
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def check_args(options):
|
||||
if not options.check:
|
||||
return None
|
||||
release_option = re.search(RELEASE_OPTION_PATTERN, options.range)
|
||||
if release_option is None:
|
||||
print("Check option ignored; range doesn't end with release tag.")
|
||||
return None
|
||||
print(f"Check option used; {CHECK_DISCLAIMER}.")
|
||||
return release_option.group(1)
|
||||
|
||||
|
||||
def newly_released(commit_sha1, release):
|
||||
if release is None:
|
||||
return True
|
||||
git_tag = [
|
||||
def list_submodules():
|
||||
submodule_names = [
|
||||
GIT_COMMAND,
|
||||
"tag",
|
||||
"--contains",
|
||||
commit_sha1,
|
||||
"submodule",
|
||||
"foreach",
|
||||
"--quiet",
|
||||
"echo $name",
|
||||
]
|
||||
process = subprocess.check_output(git_tag, stderr=subprocess.PIPE, encoding=UTF8)
|
||||
verdict = True
|
||||
for line in process.splitlines():
|
||||
line = line.strip()
|
||||
if not re.match(rf"{re.escape(release)}$", line):
|
||||
# Wrongfully pushed or malformed tags ignored.
|
||||
# Preceding release-candidate (-rcN) tags treated as newly released.
|
||||
verdict = not re.match(RELEASE_TAG_PATTERN, line)
|
||||
return verdict
|
||||
return subprocess.check_output(submodule_names, cwd=f"{GIT_PATH}", encoding=UTF8)
|
||||
|
||||
|
||||
def open_git_log(options):
|
||||
def open_git_log(options, cwd=os.getcwd()):
|
||||
git_log = [
|
||||
GIT_COMMAND,
|
||||
"log",
|
||||
"--no-merges",
|
||||
options.range,
|
||||
]
|
||||
return subprocess.check_output(git_log, encoding=UTF8)
|
||||
return subprocess.check_output(git_log, cwd=cwd, encoding=UTF8)
|
||||
|
||||
|
||||
class Change:
|
||||
subject = None
|
||||
issues = set()
|
||||
class Component:
|
||||
name = None
|
||||
sentinels = set()
|
||||
|
||||
def __init__(self, name, sentinels):
|
||||
self.name = name
|
||||
self.sentinels = sentinels
|
||||
|
||||
|
||||
class Components(Enum):
|
||||
plugin_ce = Component("Codemirror-editor", {PLUGINS})
|
||||
plugin_cm = Component("Commit-message-length-validator", {PLUGINS})
|
||||
plugin_dp = Component("Delete-project", {PLUGINS})
|
||||
plugin_dc = Component("Download-commands", {PLUGINS})
|
||||
plugin_gt = Component("Gitiles", {PLUGINS})
|
||||
plugin_ho = Component("Hooks", {PLUGINS})
|
||||
plugin_pm = Component("Plugin-manager", {PLUGINS})
|
||||
plugin_re = Component("Replication", {PLUGINS})
|
||||
plugin_rn = Component("Reviewnotes", {PLUGINS})
|
||||
plugin_su = Component("Singleusergroup", {PLUGINS})
|
||||
plugin_wh = Component("Webhooks", {PLUGINS})
|
||||
|
||||
ui = Component(
|
||||
"Polygerrit UI",
|
||||
{"poly", "gwt", "button", "dialog", "icon", "hover", "menu", "ux"},
|
||||
)
|
||||
doc = Component("Documentation", {"document"})
|
||||
jgit = Component("JGit", {"jgit"})
|
||||
elastic = Component("Elasticsearch", {"elastic"})
|
||||
deps = Component("Other dependency", {"upgrade", "dependenc"})
|
||||
otherwise = Component("Other core", {})
|
||||
|
||||
|
||||
class Task(Enum):
|
||||
start_commit = 1
|
||||
finish_headers = 2
|
||||
capture_subject = 3
|
||||
capture_submodule = 4
|
||||
capture_submodule_subject = 5
|
||||
finish_submodule_change = 6
|
||||
finish_commit = 7
|
||||
finish_commit = 4
|
||||
|
||||
|
||||
class Commit:
|
||||
sha1 = None
|
||||
subject = None
|
||||
submodule = None
|
||||
issues = set()
|
||||
|
||||
def reset(self, signature, task):
|
||||
if signature is not None:
|
||||
self.sha1 = signature.group(1)
|
||||
self.subject = None
|
||||
self.submodule = None
|
||||
self.issues = set()
|
||||
return Task.finish_headers
|
||||
return task
|
||||
|
||||
|
||||
def parse_log(process, release):
|
||||
def parse_log(process, gerrit, options, commits, cwd=os.getcwd()):
|
||||
commit = Commit()
|
||||
commits = []
|
||||
submodules = dict()
|
||||
submodule_change = None
|
||||
task = Task.start_commit
|
||||
for line in process.splitlines():
|
||||
line = line.strip()
|
||||
@@ -172,32 +211,8 @@ def parse_log(process, release):
|
||||
if re.match(DATE_HEADER_PATTERN, line):
|
||||
task = Task.capture_subject
|
||||
elif task == Task.capture_subject:
|
||||
if re.match(SUBJECT_SUBMODULES_PATTERN, line):
|
||||
task = Task.capture_submodule
|
||||
else:
|
||||
commit.subject = line
|
||||
task = Task.finish_commit
|
||||
elif task == Task.capture_submodule:
|
||||
commit.submodule = re.search(UPDATE_SUBMODULE_PATTERN, line).group(1)
|
||||
if commit.submodule not in submodules:
|
||||
submodules[commit.submodule] = []
|
||||
task = Task.capture_submodule_subject
|
||||
elif task == Task.capture_submodule_subject:
|
||||
submodule_subject = re.search(SUBMODULE_SUBJECT_PATTERN, line)
|
||||
if submodule_subject is not None:
|
||||
if not re.match(SUBMODULE_MERGE_PATTERN, line):
|
||||
submodule_change = change(submodule_subject, submodules, commit)
|
||||
task = Task.finish_submodule_change
|
||||
else:
|
||||
task = update_task(line, commit, task)
|
||||
elif task == Task.finish_submodule_change:
|
||||
submodule_issue = re.search(ISSUE_ID_PATTERN, line)
|
||||
if submodule_issue is not None:
|
||||
if submodule_change is not None:
|
||||
issue_id = submodule_issue.group(1)
|
||||
submodule_change.issues.add(issue_id)
|
||||
else:
|
||||
task = update_task(line, commit, task)
|
||||
commit.subject = line
|
||||
task = Task.finish_commit
|
||||
elif task == Task.finish_commit:
|
||||
commit_issue = re.search(ISSUE_ID_PATTERN, line)
|
||||
if commit_issue is not None:
|
||||
@@ -205,78 +220,137 @@ def parse_log(process, release):
|
||||
else:
|
||||
commit_end = re.match(CHANGE_ID_PATTERN, line)
|
||||
if commit_end is not None:
|
||||
commit = finish(commit, commits, release)
|
||||
commit = finish(commit, commits, gerrit, options, cwd)
|
||||
task = Task.start_commit
|
||||
else:
|
||||
raise RuntimeError("FIXME")
|
||||
return commits, submodules
|
||||
|
||||
|
||||
def change(submodule_subject, submodules, commit):
|
||||
submodule_change = Change()
|
||||
submodule_change.subject = submodule_subject.group(1)
|
||||
for exclusion in EXCLUDED_SUBJECTS:
|
||||
if exclusion in submodule_change.subject:
|
||||
return None
|
||||
for noted_change in submodules[commit.submodule]:
|
||||
if noted_change.subject == submodule_change.subject:
|
||||
return noted_change
|
||||
submodule_change.issues = set()
|
||||
submodules[commit.submodule].append(submodule_change)
|
||||
return submodule_change
|
||||
|
||||
|
||||
def update_task(line, commit, task):
|
||||
update_end = re.search(COMMIT_SHA1_PATTERN, line)
|
||||
if update_end is not None:
|
||||
task = commit.reset(update_end, task)
|
||||
return task
|
||||
|
||||
|
||||
def finish(commit, commits, release):
|
||||
def finish(commit, commits, gerrit, options, cwd):
|
||||
if re.match(SUBJECT_SUBMODULES_PATTERN, commit.subject):
|
||||
return Commit()
|
||||
if len(commit.issues) == 0:
|
||||
for exclusion in EXCLUDED_SUBJECTS:
|
||||
if exclusion in commit.subject:
|
||||
return Commit()
|
||||
for noted_commit in commits:
|
||||
if noted_commit.subject == commit.subject:
|
||||
return Commit()
|
||||
if newly_released(commit.sha1, release):
|
||||
commits.append(commit)
|
||||
else:
|
||||
print(f"Previously released: commit {commit.sha1}")
|
||||
for component in commits:
|
||||
for noted_commit in commits[component]:
|
||||
if noted_commit.subject == commit.subject:
|
||||
return Commit()
|
||||
set_component(commit, commits, cwd)
|
||||
link_subject(commit, gerrit, options)
|
||||
escape_these(commit)
|
||||
return Commit()
|
||||
|
||||
|
||||
def set_component(commit, commits, cwd):
|
||||
component_found = False
|
||||
for component in Components:
|
||||
for sentinel in component.value.sentinels:
|
||||
if not component_found:
|
||||
if re.match(f"{GIT_PATH}/{PLUGINS}{component.value.name.lower()}", cwd):
|
||||
component_found = True
|
||||
elif sentinel.lower() in commit.subject.lower():
|
||||
component_found = True
|
||||
if component_found:
|
||||
commits[component].append(commit)
|
||||
if not component_found:
|
||||
commits[Components.otherwise].append(commit)
|
||||
|
||||
|
||||
def init_components():
|
||||
components = dict()
|
||||
for component in Components:
|
||||
components[component] = []
|
||||
return components
|
||||
|
||||
|
||||
def link_subject(commit, gerrit, options):
|
||||
if options.link:
|
||||
gerrit_change = gerrit.get(f"{COMMIT_URL}{commit.sha1}")
|
||||
if not gerrit_change:
|
||||
return
|
||||
change_number = gerrit_change[0]["_number"]
|
||||
change_address = f"{GERRIT_URL}{CHANGE_URL}{change_number}"
|
||||
short_sha1 = commit.sha1[0:7]
|
||||
commit.subject = f"[{short_sha1}]({change_address})\n {commit.subject}"
|
||||
|
||||
|
||||
def escape_these(in_change):
|
||||
in_change.subject = in_change.subject.replace("<", "\\<")
|
||||
in_change.subject = in_change.subject.replace(">", "\\>")
|
||||
|
||||
|
||||
def print_commits(commits, md):
|
||||
md.write("\n## Core Changes\n")
|
||||
for commit in commits:
|
||||
md.write(f"\n* {commit.subject}\n")
|
||||
for issue in sorted(commit.issues):
|
||||
md.write(f" [Issue {issue}]({ISSUE_URL}{issue})\n")
|
||||
for component in commits:
|
||||
if len(commits[component]) > 0:
|
||||
if PLUGINS in component.value.sentinels:
|
||||
md.write(f"\n### {component.value.name}\n")
|
||||
else:
|
||||
md.write(f"\n## {component.value.name} changes\n")
|
||||
for commit in commits[component]:
|
||||
print_from(commit, md)
|
||||
|
||||
|
||||
def print_submodules(submodules, md):
|
||||
md.write("\n## Plugin Changes\n")
|
||||
for submodule in sorted(submodules):
|
||||
plugin = re.search(PLUGIN_PATTERN, submodule)
|
||||
md.write(f"\n### {plugin.group(1)}\n")
|
||||
for submodule_change in submodules[submodule]:
|
||||
md.write(f"\n* {submodule_change.subject}\n")
|
||||
for issue in sorted(submodule_change.issues):
|
||||
md.write(f" [Issue {issue}]({ISSUE_URL}{issue})\n")
|
||||
def print_from(this_change, md):
|
||||
md.write("\n*")
|
||||
for issue in sorted(this_change.issues):
|
||||
md.write(f" [Issue {issue}]({ISSUE_URL}{issue});\n ")
|
||||
md.write(f" {this_change.subject}\n")
|
||||
|
||||
|
||||
def print_notes(commits, submodules):
|
||||
with open("release_noter.md", "w") as md:
|
||||
md.write("# Release Notes\n")
|
||||
print_submodules(submodules, md)
|
||||
def print_template(md, options):
|
||||
previous = "0.0.0"
|
||||
new = "0.1.0"
|
||||
versions = re.search(RELEASE_VERSIONS_PATTERN, options.range)
|
||||
if versions is not None:
|
||||
previous = versions.group(1)
|
||||
new = versions.group(2)
|
||||
data = {
|
||||
"previous": previous,
|
||||
"new": new,
|
||||
"major": re.search(RELEASE_MAJOR_PATTERN, new).group(1),
|
||||
"doc": re.search(RELEASE_DOC_PATTERN, new).group(1),
|
||||
}
|
||||
template = Template(open(f"{MARKDOWN}.md.template").read())
|
||||
md.write(f"{template.render(data=data)}\n")
|
||||
|
||||
|
||||
def print_notes(commits, options):
|
||||
markdown = f"{MARKDOWN}.md"
|
||||
next_md = 2
|
||||
while path.exists(markdown):
|
||||
markdown = f"{MARKDOWN}-{next_md}.md"
|
||||
next_md += 1
|
||||
with open(markdown, "w") as md:
|
||||
print_template(md, options)
|
||||
print_commits(commits, md)
|
||||
md.write("\n## Bugfix releases\n")
|
||||
|
||||
|
||||
def plugin_changes():
|
||||
plugin_commits = init_components()
|
||||
for submodule_name in list_submodules().splitlines():
|
||||
plugin_name = re.search(PLUGIN_PATTERN, submodule_name)
|
||||
if plugin_name is not None:
|
||||
plugin_wd = f"{GIT_PATH}/{PLUGINS}{plugin_name.group(1)}"
|
||||
plugin_log = open_git_log(script_options, plugin_wd)
|
||||
parse_log(
|
||||
plugin_log,
|
||||
gerrit_api,
|
||||
script_options,
|
||||
plugin_commits,
|
||||
plugin_wd,
|
||||
)
|
||||
return plugin_commits
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
gerrit_api = GerritRestAPI(url=GERRIT_URL, auth=Anonymous())
|
||||
script_options = parse_args()
|
||||
release_tag = check_args(script_options)
|
||||
if script_options.link:
|
||||
print("Link option used; slower.")
|
||||
noted_changes = plugin_changes()
|
||||
change_log = open_git_log(script_options)
|
||||
core_changes, submodule_changes = parse_log(change_log, release_tag)
|
||||
print_notes(core_changes, submodule_changes)
|
||||
parse_log(change_log, gerrit_api, script_options, noted_changes)
|
||||
print_notes(noted_changes, script_options)
|
||||
|
||||
Reference in New Issue
Block a user