Skip to content

Commit 63363af

Browse files
committed
Merge branch 'feature/PTFE-583-prevent-creation-integration-branches' into q/3.9
2 parents 6feec22 + 6d813d1 commit 63363af

File tree

12 files changed

+312
-1
lines changed

12 files changed

+312
-1
lines changed

CHANGELOG

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
# Change Log
22
All notable changes to this project will be documented in this file.
33

4+
## [3.9.0] - 2023-07-20
5+
# Added
6+
- Introducing a new option that prevent the creation of
7+
integration branches.
8+
49
## [3.7.0] - 2022-08-08
510
# Added
611
- Support config settings through environment.

bert_e/docs/USER_DOC.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ __Bert-E__.
119119
| bypass_peer_approval | Bypass the pull request peer's approval | yes | no
120120
| bypass_leader_approval | Bypass the pull request leader's approval | yes | no
121121
| create_pull_requests | Let __Bert-E__ create pull requests corresponding to integration branches | no | no
122+
| create_integration_branches | Request __Bert-E__ to create integration branches and move forward with the gitwaterflow | no | no
122123
| no_octopus | Prevent Wall-E from doing any octopus merge and use multiple consecutive merge instead | yes | no
123124
| unanimity | Change review acceptance criteria from `one reviewer at least` to `all reviewers` (**this feature is not supported on GitHub**) | no | no
124125
| wait | Instruct __Bert-E__ not to run until further notice | no | no
@@ -170,6 +171,19 @@ target development branch. This code is then tested in the build pipeline,
170171
before any merge can happen. There are as many integration branches as there
171172
are target branches.
172173

174+
The integration branches are mandatory in the GitWaterFlow process,
175+
and by default they are automatically created when a pull request is
176+
opened.
177+
This behaviour can be changed with the `always_create_integration_branches`
178+
parameter in the bot settings:
179+
180+
* *true* (default): integration branches are created automatically when a
181+
pull request is opened.
182+
* *false*: users will be required to explicitly request the creation
183+
of integration branches by adding a `/create_integration_branches`
184+
comment in their pull request (or it will be set for them during
185+
other operations, like `approve` or `create_pull_requests`).
186+
173187
On the Git project, the name of the integration branches follow the format:
174188

175189
```w/<version>/<name_of_source_branch>```

bert_e/exceptions.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,11 @@ class NotAuthor(TemplateException):
229229
template = "not_author.md"
230230

231231

232+
class RequestIntegrationBranches(TemplateException):
233+
code = 135
234+
template = "request_integration_branches.md"
235+
236+
232237
# internal exceptions
233238
class UnableToSendEmail(InternalException):
234239
code = 201

bert_e/settings.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ class Meta:
129129
# Settings defined in config files
130130
always_create_integration_pull_requests = fields.Bool(
131131
required=False, load_default=True)
132+
always_create_integration_branches = fields.Bool(
133+
required=False, load_default=True)
132134

133135
frontend_url = fields.Str(required=False, load_default='')
134136

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{% extends "message.md" %}
2+
3+
{% block title -%}
4+
Request integration branches
5+
{% endblock %}
6+
7+
{% block message %}
8+
Waiting for integration branch creation to be requested by the user.
9+
10+
To request integration branches, please comment on this pull request with the following command:
11+
12+
```
13+
/create_integration_branches
14+
```
15+
16+
Alternatively, the `/approve` and `/create_pull_requests` commands will automatically
17+
create the integration branches.
18+
19+
{% endblock %}

bert_e/tests/test_bert_e.py

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1159,6 +1159,210 @@ def test_comments_without_integration_pull_requests(self):
11591159
self.assertIn('Hello %s' % self.args.contributor_username,
11601160
self.get_last_pr_comment(pr))
11611161

1162+
def test_request_integration_branch_creation(self):
1163+
"""Test comments to request integration branches creation.
1164+
1165+
1. Create a PR and ensure the proper message is sent regarding
1166+
the creation of integration branches.
1167+
2. Request the creation of integration branches and ensure the
1168+
branches are created.
1169+
3. Once the integration branches are created,
1170+
ensure the bot is able to merge the PR.
1171+
1172+
"""
1173+
settings = """
1174+
repository_owner: {owner}
1175+
repository_slug: {slug}
1176+
repository_host: {host}
1177+
robot: {robot}
1178+
robot_email: [email protected]
1179+
pull_request_base_url: https://bitbucket.org/{owner}/{slug}/bar/pull-requests/{{pr_id}}
1180+
commit_base_url: https://bitbucket.org/{owner}/{slug}/commits/{{commit_id}}
1181+
build_key: pre-merge
1182+
required_leader_approvals: 0
1183+
required_peer_approvals: 1
1184+
always_create_integration_branches: false
1185+
always_create_integration_pull_requests: false
1186+
admins:
1187+
- {admin}
1188+
""" # noqa
1189+
options = self.bypass_all_but(['bypass_build_status'])
1190+
pr = self.create_pr('feature/TEST-0069', 'development/4.3')
1191+
with self.assertRaises(exns.RequestIntegrationBranches):
1192+
self.handle(
1193+
pr.id, settings=settings, options=options, backtrace=True)
1194+
self.assertEqual(len(list(pr.get_comments())), 2)
1195+
self.assertIn(
1196+
'Request integration branches', self.get_last_pr_comment(pr))
1197+
self.assertIn(
1198+
'/create_integration_branches', self.get_last_pr_comment(pr))
1199+
1200+
pr.add_comment('/create_integration_branches')
1201+
with self.assertRaises(exns.BuildNotStarted):
1202+
self.handle(
1203+
pr.id, settings=settings, options=options, backtrace=True)
1204+
self.assertEqual(len(list(pr.get_comments())), 4)
1205+
self.assertIn('Integration data created', self.get_last_pr_comment(pr))
1206+
self.assertIn(
1207+
'create_integration_branches', self.get_last_pr_comment(pr))
1208+
1209+
options = self.bypass_all
1210+
with self.assertRaises(exns.SuccessMessage):
1211+
self.handle(
1212+
pr.id, settings=settings, options=options, backtrace=True)
1213+
1214+
def test_request_integration_branch_by_creating_pull_requests(self):
1215+
"""Test creating integration branches by creating pull requests
1216+
1217+
1. Create a PR and verify that the appropriate message is sent
1218+
regarding its creation
1219+
2. Type `/create_integration_branches` and ensure the
1220+
branches are created.
1221+
3. Once the integration branches are created,
1222+
ensure the bot is able to merge the PR.
1223+
1224+
"""
1225+
settings = """
1226+
repository_owner: {owner}
1227+
repository_slug: {slug}
1228+
repository_host: {host}
1229+
robot: {robot}
1230+
robot_email: [email protected]
1231+
pull_request_base_url: https://bitbucket.org/{owner}/{slug}/bar/pull-requests/{{pr_id}}
1232+
commit_base_url: https://bitbucket.org/{owner}/{slug}/commits/{{commit_id}}
1233+
build_key: pre-merge
1234+
required_leader_approvals: 0
1235+
required_peer_approvals: 1
1236+
always_create_integration_branches: false
1237+
always_create_integration_pull_requests: false
1238+
admins:
1239+
- {admin}
1240+
""" # noqa
1241+
options = self.bypass_all_but(['bypass_build_status'])
1242+
pr = self.create_pr('feature/TEST-0069', 'development/4.3')
1243+
with self.assertRaises(exns.RequestIntegrationBranches):
1244+
self.handle(
1245+
pr.id, settings=settings, options=options, backtrace=True)
1246+
1247+
pr.add_comment('/create_pull_requests')
1248+
with self.assertRaises(exns.BuildNotStarted):
1249+
self.handle(
1250+
pr.id, settings=settings, options=options, backtrace=True)
1251+
self.assertEqual(len(list(pr.get_comments())), 4)
1252+
self.assertIn('Integration data created', self.get_last_pr_comment(pr))
1253+
1254+
options = self.bypass_all
1255+
with self.assertRaises(exns.SuccessMessage):
1256+
self.handle(
1257+
pr.id, settings=settings, options=options, backtrace=True)
1258+
1259+
self.assertIn(
1260+
'I have successfully merged the changeset',
1261+
self.get_last_pr_comment(pr))
1262+
1263+
def test_creation_integration_branch_by_approve(self):
1264+
"""Test pr.approve() to request integration branches creation.
1265+
1266+
1. Create a PR and verify that the appropriate message is sent
1267+
regarding its creation
1268+
2. Ensure that author approval is required for the PR
1269+
3. Approve the PR from the author's perspective and check if
1270+
the integration branches are created.
1271+
4. Once the integration branches are created,
1272+
ensure the bot is able to merge the PR.
1273+
1274+
"""
1275+
settings = """
1276+
repository_owner: {owner}
1277+
repository_slug: {slug}
1278+
repository_host: {host}
1279+
robot: {robot}
1280+
robot_email: [email protected]
1281+
pull_request_base_url: https://bitbucket.org/{owner}/{slug}/bar/pull-requests/{{pr_id}}
1282+
commit_base_url: https://bitbucket.org/{owner}/{slug}/commits/{{commit_id}}
1283+
build_key: pre-merge
1284+
required_leader_approvals: 0
1285+
required_peer_approvals: 0
1286+
always_create_integration_branches: false
1287+
admins:
1288+
- {admin}
1289+
""" # noqa
1290+
pr_1 = self.create_pr('feature/TEST-0069', 'development/4.3')
1291+
pr_2 = self.create_pr('feature/TEST-0070', 'development/4.3')
1292+
prs = [pr_1, pr_2]
1293+
1294+
for pr in prs:
1295+
options = self.bypass_all_but(['bypass_build_status',
1296+
'bypass_author_approval'])
1297+
with self.assertRaises(exns.ApprovalRequired):
1298+
self.handle(pr.id, options=options, backtrace=True)
1299+
1300+
self.assertEqual(len(list(pr.get_comments())), 3)
1301+
1302+
self.assertIn(
1303+
'Integration data created', list(pr.get_comments())[-2].text)
1304+
1305+
self.assertIn(
1306+
'Waiting for approval', self.get_last_pr_comment(pr))
1307+
self.assertIn(
1308+
'The following approvals are needed',
1309+
self.get_last_pr_comment(pr))
1310+
1311+
if pr.src_branch == "feature/TEST-0069":
1312+
pr.approve()
1313+
elif pr.src_branch == "feature/TEST-0070":
1314+
pr.add_comment('/approve')
1315+
1316+
with self.assertRaises(exns.BuildNotStarted):
1317+
self.handle(
1318+
pr.id, settings=settings, options=options, backtrace=True)
1319+
1320+
options = self.bypass_all
1321+
with self.assertRaises(exns.SuccessMessage):
1322+
self.handle(
1323+
pr.id, settings=settings, options=options, backtrace=True)
1324+
1325+
self.assertIn(
1326+
'I have successfully merged the changeset',
1327+
self.get_last_pr_comment(pr))
1328+
1329+
def test_integration_branch_creation_latest_branch(self):
1330+
"""Test there is no comment to request integration branches creation.
1331+
1332+
1. Create a PR with the latest branch and check if there is no comment
1333+
to request integration branches creation.
1334+
2. Then, ensure the bot is able to merge the PR.
1335+
1336+
"""
1337+
settings = """
1338+
repository_owner: {owner}
1339+
repository_slug: {slug}
1340+
repository_host: {host}
1341+
robot: {robot}
1342+
robot_email: [email protected]
1343+
pull_request_base_url: https://bitbucket.org/{owner}/{slug}/bar/pull-requests/{{pr_id}}
1344+
commit_base_url: https://bitbucket.org/{owner}/{slug}/commits/{{commit_id}}
1345+
build_key: pre-merge
1346+
required_leader_approvals: 0
1347+
required_peer_approvals: 1
1348+
always_create_integration_branches: false
1349+
admins:
1350+
- {admin}
1351+
""" # noqa
1352+
options = self.bypass_all_but(['bypass_build_status'])
1353+
pr = self.create_pr('feature/TEST-0069', 'development/10.0')
1354+
self.handle(pr.id, settings=settings, options=options)
1355+
self.assertEqual(len(list(pr.get_comments())), 1)
1356+
1357+
with self.assertRaises(exns.BuildNotStarted):
1358+
self.handle(
1359+
pr.id, settings=settings, options=options, backtrace=True)
1360+
1361+
options = self.bypass_all
1362+
with self.assertRaises(exns.SuccessMessage):
1363+
self.handle(
1364+
pr.id, settings=settings, options=options, backtrace=True)
1365+
11621366
def test_comments_for_manual_integration_pr_creation(self):
11631367
"""Test comments when integration data is created.
11641368

bert_e/workflow/gitwaterflow/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@
3434
bypass_author_approval, bypass_leader_approval, bypass_build_status
3535
)
3636
from .commands import setup # noqa
37-
from .integration import (create_integration_branches,
37+
from .integration import (check_integration_branches,
38+
create_integration_branches,
3839
create_integration_pull_requests,
3940
merge_integration_branches,
4041
notify_integration_data,
@@ -158,6 +159,7 @@ def _handle_pull_request(job: PullRequestJob):
158159
check_branch_compatibility(job)
159160
jira_checks(job)
160161

162+
check_integration_branches(job)
161163
wbranches = list(create_integration_branches(job))
162164
use_queue = job.settings.use_queue
163165
if use_queue and queueing.already_in_queue(job, wbranches):

bert_e/workflow/gitwaterflow/commands.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,11 @@ def setup(defaults={}):
209209
"Allow the creation of integration pull requests.",
210210
privileged=False,
211211
default=defaults.get("create_pull_requests", False))
212+
Reactor.add_option(
213+
"create_integration_branches",
214+
"Allow the creation of integration branches.",
215+
privileged=False,
216+
default=defaults.get("create_integration_branches", False))
212217
Reactor.add_option(
213218
"no_octopus",
214219
"Prevent Wall-E from doing any octopus merge and use multiple "

bert_e/workflow/gitwaterflow/integration.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,29 @@ def update(wbranch, source):
136136
prev = branch
137137

138138

139+
def check_integration_branches(job):
140+
"""Check if the integration branches can be created."""
141+
142+
approvals = set(job.pull_request.get_approvals())
143+
if job.settings.approve:
144+
approvals.add(job.pull_request.author)
145+
approved_by_author = job.pull_request.author in approvals
146+
147+
create_integration = (job.settings.always_create_integration_branches or
148+
job.settings.create_integration_branches)
149+
create_prs = (job.settings.always_create_integration_pull_requests or
150+
job.settings.create_pull_requests)
151+
multiple_dst_branches = len(job.git.cascade.dst_branches) <= 1
152+
153+
if not (create_integration or
154+
create_prs or
155+
approved_by_author or
156+
multiple_dst_branches):
157+
raise exceptions.RequestIntegrationBranches(
158+
active_options=job.active_options,
159+
)
160+
161+
139162
def check_conflict(job, dst: git.Branch, src: git.Branch):
140163
"""Check conflict between the source and destination branches of a PR."""
141164
# Create a temporary branch starting off from the destination branch, only

charts/bert-e/templates/settings.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ stringData:
2121
robot_email: {{ .Values.bertE.robot.email | quote }}
2222
organization: {{ .Values.bertE.oauth.organization }}
2323
always_create_integration_pull_requests: {{ .Values.bertE.gating.alwaysCreateIntegrationPullRequests }}
24+
always_create_integration_branches: {{ .Values.bertE.gating.alwaysCreateIntegrationBranches }}
2425
{{- if eq .Values.bertE.repository.gitHost "bitbucket" }}
2526
pull_request_base_url: https://bitbucket.org/{{ .Values.bertE.repository.owner }}/{{ .Values.bertE.repository.slug }}/pull-requests/{pr_id}
2627
commit_base_url: https://bitbucket.org/{{ .Values.bertE.repository.owner }}/{{ .Values.bertE.repository.slug }}/commits/{commit_id}

0 commit comments

Comments
 (0)