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:
Marco Miller
2020-10-29 13:04:49 -04:00
13 changed files with 458 additions and 183 deletions

View File

@@ -1 +1 @@
3.5.1
3.7.0

View File

@@ -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::
+

View File

@@ -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.

View File

@@ -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(

View File

@@ -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"

View File

@@ -0,0 +1,2 @@
[*.py]
indent_size = 4

View File

@@ -1,2 +1,2 @@
/.idea/
/release_noter.md
/release_noter*.md

View 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

View File

@@ -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"

View File

@@ -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": [

View File

@@ -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
```

View 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

View File

@@ -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)