Disable gitea-redmine messages on excluded redmine projects (#73555)
gitea-wip/gitea-redmine/pipeline/pr-main This commit looks good
Details
gitea-wip/gitea-redmine/pipeline/pr-main This commit looks good
Details
This commit is contained in:
parent
40eb21defb
commit
d9c2b55180
|
@ -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:
|
||||
|
|
95
test_app.py
95
test_app.py
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue