Disable gitea-redmine messages on excluded redmine projects (#73555)
gitea-wip/gitea-redmine/pipeline/pr-main This commit looks good Details

This commit is contained in:
Agate 2023-01-18 15:36:05 +01:00
parent 40eb21defb
commit d9c2b55180
2 changed files with 112 additions and 16 deletions

View File

@ -16,6 +16,13 @@ REDMINE_API_KEY = os.environ["REDMINE_API_KEY"]
REDMINE_CLIENT = redminelib.Redmine(REDMINE_URL, key=REDMINE_API_KEY)
REDMINE_ASSIGNABLE_GROUP = int(os.environ.get('REDMINE_ASSIGNABLE_GROUP', 21))
REDMINE_EXCLUDED_PROJECTS = [
i.strip()
for i in os.environ.get(
'REDMINE_EXCLUDED_PROJECTS',
'projets-clients'
).split(',')
]
REDMINE_STATUSES = {
'En cours': 2,
@ -62,8 +69,9 @@ def incoming_webhook(token):
return {'status': 'success', 'detail': 'Skipped, no valid redmine issues linked'}
for issue in issues:
project = get_redmine_project(issue.project.id)
logging.info(f'Calling handler {event} for issue {issue.id}')
handler(issue, payload)
handler(issue, payload, project)
logging.info(f' Done')
return {'status': 'success', 'detail': 'Event processed and forwarded to redmine'}
@ -122,12 +130,33 @@ def get_redmine_issue(id):
return REDMINE_CLIENT.issue.get(id, includes=['journals'])
def get_redmine_project(id):
return REDMINE_CLIENT.project.get(id)
class Abort(Exception):
pass
def is_excluded_project(project):
# easiest case, the project itself is excluded
if project.identifier in REDMINE_EXCLUDED_PROJECTS:
return True
# now, if the project has a parent, we must recursively check
# if the parent is excluded as well
if hasattr(project, 'parent') and project.parent and project.parent.id:
# since some project may have grandparents, we must still check for this case
parent = get_redmine_project(project.parent.id)
return is_excluded_project(parent)
return False
def make_handler(*actions):
def inner(issue, payload):
def inner(issue, payload, project):
if is_excluded_project(project):
logging.info('Issue belongs to excluded project %s', project.id)
return
flat_payload = flatten(payload)
for action in actions:
try:

View File

@ -99,8 +99,10 @@ def test_handle_pull_request_opened(mocker):
"body": "See #70893",
},
}
project = mocker.Mock()
project.parent = None
issue = mocker.Mock()
gitea_redmine.handle_pull_request_opened(issue, payload)
gitea_redmine.handle_pull_request_opened(issue, payload, project)
get_redmine_user.assert_called_once_with('testuser')
@ -144,9 +146,11 @@ def test_handle_pull_request_opened_skips_closed_statuses(status, mocker):
"body": "See #70893",
},
}
project = mocker.Mock()
project.parent = None
issue = mocker.Mock(status=mocker.Mock(id=status))
original_status = issue.status_id
gitea_redmine.handle_pull_request_opened(issue, payload)
gitea_redmine.handle_pull_request_opened(issue, payload, project)
assert issue.status_id == original_status
@ -173,8 +177,10 @@ def test_handle_pull_request_edited(mocker):
"body": "See #70893",
},
}
project = mocker.Mock()
project.parent = None
issue = mocker.Mock(journals=[])
gitea_redmine.handle_pull_request_edited(issue, payload)
gitea_redmine.handle_pull_request_edited(issue, payload, project)
get_redmine_user.assert_called_once_with('testuser')
@ -208,8 +214,10 @@ def test_handle_pull_request_draft(mocker):
"body": "See #70893",
},
}
project = mocker.Mock()
project.parent = None
issue = mocker.Mock(journals=[])
gitea_redmine.handle_pull_request_draft(issue, payload)
gitea_redmine.handle_pull_request_draft(issue, payload, project)
assert issue.status_id == gitea_redmine.REDMINE_STATUSES['En cours']
assert issue.notes == (
@ -229,12 +237,14 @@ def test_handle_pull_request_edited_already_linked_does_nothing(mocker):
"url": "https://gitea.entrouvert.org/entrouvert/gitea-redmine/pulls/2",
},
}
project = mocker.Mock()
project.parent = None
issue = mocker.Mock(
journals=[
mocker.Mock(notes='Linked to https://gitea.entrouvert.org/entrouvert/gitea-redmine/pulls/2')
]
)
gitea_redmine.handle_pull_request_edited(issue, payload)
gitea_redmine.handle_pull_request_edited(issue, payload, project)
issue.save.assert_not_called()
@ -260,9 +270,11 @@ def test_handle_pull_request_reviewed_approved(mocker):
},
"review": {"type": "pull_request_review_approved", "content": "Okay pour moi"},
}
project = mocker.Mock()
project.parent = None
issue = mocker.Mock()
gitea_redmine.handle_pull_request_approved(issue, payload)
gitea_redmine.handle_pull_request_approved(issue, payload, project)
assert issue.status_id == gitea_redmine.REDMINE_STATUSES['Solution validée']
assert issue.notes == (
@ -293,9 +305,11 @@ def test_handle_pull_request_reviewed_rejected(mocker):
},
"review": {"type": "pull_request_review_rejected", "content": "Des choses à changer"},
}
project = mocker.Mock()
project.parent = None
issue = mocker.Mock()
gitea_redmine.handle_pull_request_rejected(issue, payload)
gitea_redmine.handle_pull_request_rejected(issue, payload, project)
assert issue.status_id == gitea_redmine.REDMINE_STATUSES['En cours']
assert issue.notes == (
@ -326,12 +340,13 @@ def test_handle_pull_request_reviewed_approved_already_approved(mocker):
},
"review": {"type": "pull_request_review_approved", "content": ""},
}
issue = mocker.Mock()
project = project = mocker.Mock()
project.parent = None
issue = mocker.Mock(
status=mocker.Mock(id=gitea_redmine.REDMINE_STATUSES["Solution validée"])
)
gitea_redmine.handle_pull_request_approved(issue, payload)
gitea_redmine.handle_pull_request_approved(issue, payload, project)
issue.save.assert_not_called()
@ -355,9 +370,11 @@ def test_handle_pull_request_merged(mocker):
"username": "testuser",
},
}
project = mocker.Mock()
project.parent = None
issue = mocker.Mock()
gitea_redmine.handle_pull_request_merged(issue, payload)
gitea_redmine.handle_pull_request_merged(issue, payload, project)
assert issue.status_id == gitea_redmine.REDMINE_STATUSES['Résolu']
assert issue.notes == (
@ -383,9 +400,12 @@ def test_incoming_webhook_requires_secret(client):
def test_incoming_webhook_calls_proper_handler(client, mocker):
issue1 = mocker.Mock(journals=[])
issue2 = mocker.Mock(journals=[])
project = mocker.Mock()
project.parent = None
issue1 = mocker.Mock(journals=[], project=project)
issue2 = mocker.Mock(journals=[], project=project)
get_redmine_issue = mocker.patch.object(gitea_redmine, 'get_redmine_issue', side_effect=[issue1, issue2])
get_redmine_project = mocker.patch.object(gitea_redmine, 'get_redmine_project', return_value=project)
get_handler = mocker.patch.object(gitea_redmine, 'get_handler', return_value=[mocker.Mock(), 'foo'])
@ -410,8 +430,55 @@ def test_incoming_webhook_calls_proper_handler(client, mocker):
get_redmine_issue.assert_any_call(1234)
get_redmine_issue.assert_any_call(5678)
handler.assert_any_call(issue1, payload)
handler.assert_any_call(issue2, payload)
handler.assert_any_call(issue1, payload, project)
handler.assert_any_call(issue2, payload, project)
assert response.status_code == 200
assert response.json == {'status': 'success', 'detail': 'Event processed and forwarded to redmine'}
def test_make_handler_ignore_excluded_projects(mocker):
f1 = mocker.Mock()
issue = mocker.Mock()
project = mocker.Mock()
is_excluded_project = mocker.patch.object(gitea_redmine, 'is_excluded_project', return_value=True)
handler = gitea_redmine.make_handler(
f1
)
handler(issue, {}, project)
f1.assert_not_called()
def test_excluded_project_false(mocker):
mocker.patch.object(gitea_redmine, 'REDMINE_EXCLUDED_PROJECTS', ['noop'])
project = mocker.Mock(identifier='project')
project.parent = None
assert gitea_redmine.is_excluded_project(project) is False
def test_excluded_project_true(mocker):
mocker.patch.object(gitea_redmine, 'REDMINE_EXCLUDED_PROJECTS', ['project'])
project = mocker.Mock(identifier='project')
project.parent = None
assert gitea_redmine.is_excluded_project(project) is True
def test_excluded_project_parent_true(mocker):
mocker.patch.object(gitea_redmine, 'REDMINE_EXCLUDED_PROJECTS', ['parent'])
parent = mocker.Mock(identifier='parent', id=12)
get_redmine_project = mocker.patch.object(gitea_redmine, 'get_redmine_project', return_value=parent)
project = mocker.Mock(identifier='project')
project.parent = parent
assert gitea_redmine.is_excluded_project(project) is True
def test_excluded_project_parent_false(mocker):
mocker.patch.object(gitea_redmine, 'REDMINE_EXCLUDED_PROJECTS', ['noop'])
parent = mocker.Mock(identifier='parent', id=12)
parent.parent = None
get_redmine_project = mocker.patch.object(gitea_redmine, 'get_redmine_project', return_value=parent)
project = mocker.Mock(identifier='project')
project.parent = parent
assert gitea_redmine.is_excluded_project(project) is False