Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions Source/lang/strings_english.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,19 @@ $s_plugin_Source_filename = 'Filename';
$s_plugin_Source_ported = 'Ported';
$s_plugin_Source_vcs_username = 'Source Control Username';

$s_plugin_Source_pre_commit_checks = 'Pre-Commit Checks';
$s_plugin_Source_commit_needs_issue = 'Commit Requires Issue Reference(s)';
$s_plugin_Source_commit_issues_must_exist = 'Referenced Issue(s) Must Exist';
$s_plugin_Source_commit_ownership_must_match = 'Referenced Issue(s) Must Be Owned By Committer';
$s_plugin_Source_commit_committer_must_be_member = 'Committer must be a member of the Mantis project';
$s_plugin_Source_commit_committer_must_be_level = 'Committer must be a';
$s_plugin_Source_commit_status_restricted = 'Referenced Issue(s) must be at a particular status';
$s_plugin_Source_commit_status_restricted_list = 'Only allow commits when ticket is';
$s_plugin_Source_commit_project_restricted = 'Referenced Issue(s) must be within a particular project';
$s_plugin_Source_commit_project_restricted_list = 'Only allow commits when ticket is within';
$s_plugin_Source_commit_on = 'On';
$s_plugin_Source_commit_off = 'Off';

$s_plugin_Source_issue = 'Issue';
$s_plugin_Source_issues = 'Issues';
$s_plugin_Source_actions = 'Actions';
Expand Down Expand Up @@ -147,6 +160,7 @@ $s_plugin_Source_invalid_checkin_url = 'Invalid remote check-in address';
$s_plugin_Source_invalid_import_url = 'Invalid remote import address';
$s_plugin_Source_invalid_repo = 'Invalid repository name';
$s_plugin_Source_invalid_changeset = 'Changeset information could not be loaded';
$s_plugin_Source_invalid_key = 'Invalid API Key. Please check that you have set the API_KEY variable correctly in the hook script';

$s_plugin_Source_import_latest_failed = 'Repository latest data importing failed.';
$s_plugin_Source_import_full_failed = 'Full repository data importing failed.';
Expand All @@ -162,3 +176,12 @@ $s_plugin_Source_error_invalid_branch = 'Invalid characters in Branch name "%1$s
$s_plugin_Source_error_productmatrix_not_loaded = 'Product Matrix integration is enabled, but the plugin is not loaded.';
$s_plugin_Source_error_repo_missing = 'Repository "%1$s" not found.';
$s_plugin_Source_error_repo_missing_changeset = 'No repositories found for Changeset "%1$s".';

$s_plugin_Source_error_commit_needs_issue = 'Commit comments needs to reference one or more issues';
$s_plugin_Source_error_commit_nonexistent_issue = 'Commit comment references non-existent issue';
$s_plugin_Source_error_commit_issue_ownership = 'Issue referenced in commit need to be assigned to the committer';
$s_plugin_Source_error_commit_committer_not_member = 'Committing user is not a member of the Mantis project';
$s_plugin_Source_error_commit_committer_not_fount = 'Committing user could not be found in Mantis';
$s_plugin_Source_error_commit_committer_wrong_level = 'Committing user does not have appropriate access level in project';
$s_plugin_Source_error_commit_issue_wrong_status = 'Issue referenced in commit is not at correct status to be committed against';
$s_plugin_Source_error_commit_issue_wrong_project = 'Issue referenced in commit is within appropriate project';
20 changes: 20 additions & 0 deletions Source/lang/strings_german.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ $s_plugin_Source_username = 'Benutzer';
$s_plugin_Source_timestamp = 'Datum';
$s_plugin_Source_parent = 'Vorgänger';
$s_plugin_Source_url = 'URL';
$s_plugin_Source_pre_commit_checks = 'Pre-Commit Checks';
$s_plugin_Source_commit_needs_issue = 'Committext benötigt Beziehung zu mindestens einem Eintrag';
$s_plugin_Source_commit_issues_must_exist = 'Eintrag muss existieren';
$s_plugin_Source_commit_ownership_must_match = 'Eintrag muss Autor/Comitter gehören';
$s_plugin_Source_commit_committer_must_be_member = 'Benutzer muss dem Projekt in Mantis angehören';
$s_plugin_Source_commit_committer_must_be_level = 'Benutzer muss Rolle haben';
$s_plugin_Source_commit_status_restricted = 'Referenzierte Einträge müssen einen bestimmten Status haben';
$s_plugin_Source_commit_status_restricted_list = 'Commit nur zulassen für Einträge mit folgendem Status';
$s_plugin_Source_commit_project_restricted = 'Referenzierte Einträge müssen zu einem bestimmten Projekt gehören';
$s_plugin_Source_commit_project_restricted_list = 'Commit nur zulassen, wenn Eintrag aus Projekt';
$s_plugin_Source_commit_on = 'An';
$s_plugin_Source_commit_off = 'Aus';
$s_plugin_Source_info = 'Zusatzinfos';
$s_plugin_Source_revision = 'Revision';
$s_plugin_Source_date_begin = 'Beginn';
Expand Down Expand Up @@ -144,6 +156,14 @@ $s_plugin_Source_invalid_changeset = 'Die Informationen zu dem Änderungssatz ko
$s_plugin_Source_import_latest_failed = 'Partieller Import des Projektarchivs fehlgeschlagen.';
$s_plugin_Source_import_full_failed = 'Vollständiger Import des Projektarchivs fehlgeschlagen.';

$s_plugin_Source_error_commit_needs_issue = 'Kommentar muss einen oder mehrere Verweise auf Einträge enthalten';
$s_plugin_Source_error_commit_nonexistent_issue = 'Committext verweist auf nicht existenten Eintrag';
$s_plugin_Source_error_commit_issue_ownership = 'Verwiesener Eintrag muss dem Benutzer gehören';
$s_plugin_Source_error_commit_committer_not_member = 'Benutzer ist nicht Mitglied des Mantisprojektes';
$s_plugin_Source_error_commit_committer_not_found = 'Benutzer konnte nicht gefunden werden in Mantis';
$s_plugin_Source_error_commit_committer_wrong_level = 'Benutzer hat unzureichende Rechte im Projekt';
$s_plugin_Source_error_commit_issue_wrong_status = 'Verwiesener Eintrag hat nicht den korrekten Status';
$s_plugin_Source_error_commit_issue_wrong_project = 'Verwiesener Eintrag ist nicht im zugelassenen Projekt';
$s_plugin_Source_changeset_column_title = 'C';

$s_plugin_Source_error_invalid_branch = 'Ungültige Zeichen in der Zweige "%1$s"';
231 changes: 231 additions & 0 deletions Source/pages/pre_commit_check.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
<?php

# Copyright (c) 2014 John Bailey
# Licensed under the MIT license
#
# This file is intended to be called from a pre-commit hook in order to verify
# mantis ticket references in the commit comment. The level of checking
# is configured on a per-repository basis

header("content-type: text/html; charset=utf-8");
include_once 'si_common.php';

if ( !si_is_key_ok() ) {
die( plugin_lang_get( 'invalid_key' ) );
}

# If you're worried about information "leaking" out via error messages, set this to false to prevent error messages
# containing any information from the ticket(s)
$t_informational_errors = true;

# Get a list of the bug IDs which were referenced in the commit comment
$t_bug_list = Source_Parse_Buglinks( gpc_get_string( 'commit_comment', '' ));
$t_resolved_threshold = config_get( 'bug_resolved_status_threshold' );

$f_committer_name = gpc_get_string( 'committer', '' );
$f_repo_name = gpc_get_string( 'repo_name', '' );
$t_repo = SourceRepo::load_by_name( $f_repo_name );
# Repo not found
if ( is_null( $t_repo ) ) {
die( plugin_lang_get( 'invalid_repo' ) );
}
$t_repo_commit_needs_issue = isset( $t_repo->info['repo_commit_needs_issue'] ) ? $t_repo->info['repo_commit_needs_issue'] : false;
$t_repo_commit_issues_must_exist = isset( $t_repo->info['repo_commit_issues_must_exist'] ) ? $t_repo->info['repo_commit_issues_must_exist'] : false;
$t_repo_commit_ownership_must_match = isset( $t_repo->info['repo_commit_ownership_must_match'] ) ? $t_repo->info['repo_commit_ownership_must_match'] : false;
$t_repo_commit_status_restricted = isset( $t_repo->info['repo_commit_status_restricted'] ) ? $t_repo->info['repo_commit_status_restricted'] : false;
$t_repo_commit_status_allowed = isset( $t_repo->info['repo_commit_status_allowed'] ) ? $t_repo->info['repo_commit_status_allowed'] : '';
$t_repo_commit_project_restricted = isset( $t_repo->info['repo_commit_project_restricted'] ) ? $t_repo->info['repo_commit_project_restricted'] : '';
$t_repo_commit_project_allowed = isset( $t_repo->info['repo_commit_project_allowed'] ) ? $t_repo->info['repo_commit_project_allowed'] : '';
$t_repo_commit_committer_must_be_member = isset( $t_repo->info['repo_commit_committer_must_be_member'] ) ? $t_repo->info['repo_commit_committer_must_be_member'] : '';
$t_repo_commit_committer_must_be_level = isset( $t_repo->info['repo_commit_committer_must_be_level'] ) ? $t_repo->info['repo_commit_committer_must_be_level'] : MantisEnum::getValues( config_get( 'access_levels_enum_string' ) ) ;

$t_all_ok = true;

# Check number of bugs referenced in the commit comment
if(( sizeof( $t_bug_list ) == 0 ) && $t_repo_commit_needs_issue ) {

# It was expected that the commit comment would reference one of more bug
# IDs but this was not the case

printf( "Check-Message: '%s'\r\n",plugin_lang_get( 'error_commit_needs_issue' ) );
$t_all_ok = false;

} else {

# Loop all the bug IDs referenced in the commit comment
foreach( $t_bug_list as $t_bug_id ) {

# Check existence first to prevent API throwing an error
if( bug_exists( $t_bug_id ) ) {

$t_bug = bug_get( $t_bug_id );

# Ownership of ticket must match committer?
if( $t_repo_commit_ownership_must_match ) {

if( 0 == $t_bug->handler_id ) {
$t_user_name = 'none';
$t_user_email = 'none';
} else {
$t_user_name = user_get_name( $t_bug->handler_id );
$t_user_email = user_get_email( $t_bug->handler_id );
}

# Check that the username of the committer matches the user name
# or e-mail address of the owner of the ticket
if( !( strlen( $f_committer_name ) &&
(( $t_user_name == $f_committer_name ) ||
( $t_user_email == $f_committer_name )))) {

printf( "Check-Message: '%s : %s %d",
plugin_lang_get( 'error_commit_issue_ownership' ),
plugin_lang_get( 'issue' ),
$t_bug_id );

if( $t_informational_errors ) {

# Informative errors turned on so display the user to whom
# the ticket is assigned
printf( " (%s/%s vs %s)",
$t_user_name, $t_user_email, $f_committer_name );
}

printf( "'\r\n" );
$t_all_ok = false;
}
} # End ownership must match ticket

# Only allowed to commit against tickets with a specific status?
if( $t_repo_commit_status_restricted ) {

# Check that the bug's status is at a level for which a commit
# is allowed
if( !in_array( $t_bug->status, $t_repo_commit_status_allowed )) {

printf( "Check-Message: '%s : %s %d",
plugin_lang_get( 'error_commit_issue_wrong_status' ),
plugin_lang_get( 'issue' ),
$t_bug_id );

if( $t_informational_errors ) {

# Informative errors turned on so display a list of statuses for which
# a commit would be accepted

# Get an array of the names of the statuses for which commit is allowed
$t_statuses = array_map( function( $p_status ) { return get_enum_element( 'status', $p_status ); }, $t_repo_commit_status_allowed );

printf( " (%s vs %s)",
get_enum_element( 'status', $t_bug->status ),
implode( ", ", $t_statuses ));
}
printf( "'\r\n" );
$t_all_ok = false;
}
} # End only allowed to commit against tickets with a specific status

# Only allowed to commit against Mantis tickets within specific project(s)
if( $t_repo_commit_project_restricted ) {

if( !in_array( 0, $t_repo_commit_project_allowed ) &&
!in_array( $t_bug->project_id, $t_repo_commit_project_allowed )) {

printf( "Check-Message: '%s : %s %d",
plugin_lang_get( 'error_commit_issue_wrong_project' ),
plugin_lang_get( 'issue' ),
$t_bug_id );

if( $t_informational_errors ) {

# Informative errors turned on so display a list of Mantis projects to
# which referenced tickets must belong

# Get an array of the names of all the projects
$t_projects = array_map( function( $p_proj ) { return project_get_field( $p_proj, 'name' ); }, $t_repo_commit_project_allowed );

printf( " (%s vs %s)",
project_get_field( $t_bug->project_id, 'name' ),
implode( $t_projects, ", " ));
}

printf( "'\r\n" );
$t_all_ok = false;
}
} # End only allowed to commit against tickets within specific projects

# Committer must belong to the Mantis project?
if( $t_repo_commit_committer_must_be_member ) {

$t_user_id = user_get_id_by_name( $f_committer_name );

# Didn't find the username? Try the e-mail address
if( $t_user_id == false ) {

$t_user_id = user_get_id_by_email( $f_committer_name );
}

/* Check that the user exists in Mantis */
if( $t_user_id == false ) {

printf( "Check-Message: '%s : %s %d (%s)'\r\n",
plugin_lang_get( 'error_commit_committer_not_found' ),
plugin_lang_get( 'issue' ),
$t_bug_id, $f_committer_name );
$t_all_ok = false;

/* Check that the user is assigned to the project */
} elseif( ! project_includes_user( $t_bug->project_id, $t_user_id )) {
printf( "Check-Message: '%s : %s %d (%s)'\r\n",
plugin_lang_get( 'error_commit_committer_not_member' ),
plugin_lang_get( 'issue' ),
$t_bug_id, $f_committer_name );
$t_all_ok = false;

} else {

$t_user_access_level = access_get_local_level( $t_user_id, $t_bug->project_id );
if( in_array( $t_user_access_level, $t_repo_commit_committer_must_be_level )) {

printf( "Check-Message: '%s : %s %d",
plugin_lang_get( 'error_commit_committer_wrong_level' ),
plugin_lang_get( 'issue' ),
$t_bug_id );

if( $t_informational_errors ) {

# Informative errors turned on so display a list of access levels
# for which commit is allowed

$t_levels = MantisEnum::getAssocArrayIndexedByValues( config_get( 'access_levels_enum_string' ) );
$t_allowed_levels = array_intersect_key( $t_levels, array_flip( $t_repo_commit_committer_must_be_level ));

printf( " (%s vs %s)",
$t_levels[ $t_user_access_level ],
implode( ", ", array_values( $t_allowed_levels ) ) );
}
printf( "'\r\n" );
$t_all_ok = false;
}
}
} # End committer must belong to mantis project
} else {

/* If the issue doesn't exist, then can't perform the checks */
if( $t_repo_commit_issues_must_exist ||
$t_repo_commit_ownership_must_match ||
$t_repo_commit_status_restricted ||
$t_repo_commit_project_restricted ||
$t_repo_commit_committer_must_be_member ) {

printf( "Check-Message: '%s : %s %d'\r\n",
plugin_lang_get( 'error_commit_nonexistent_issue' ),
plugin_lang_get( 'issue' ),
$t_bug_id );
$t_all_ok = false;
}
}
}
}
printf( "Check-OK: %d\r\n",$t_all_ok );

?>
19 changes: 19 additions & 0 deletions Source/pages/repo_update.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,31 @@
$f_repo_name = gpc_get_string( 'repo_name' );
$f_repo_url = gpc_get_string( 'repo_url' );

f_repo_commit_needs_issue = gpc_get_bool( 'repo_commit_needs_issue', false );
$f_repo_commit_issues_must_exist = gpc_get_bool( 'repo_commit_issues_must_exist', false );
$f_repo_commit_ownership_must_match = gpc_get_bool( 'repo_commit_ownership_must_match', false );
$f_repo_commit_status_restricted = gpc_get_bool( 'repo_commit_status_restricted', false );
$f_repo_commit_status_allowed = gpc_get_int_array( 'repo_commit_status_allowed', MantisEnum::getValues( config_get( 'status_enum_string' ) ));
$f_repo_commit_project_restricted = gpc_get_bool( 'repo_commit_project_restricted', false );
$f_repo_commit_project_allowed = gpc_get_int_array( 'repo_commit_project_allowed', Array( 0 ) );
$f_repo_commit_committer_must_be_member = gpc_get_bool( 'repo_commit_committer_must_be_member', false );
$f_repo_commit_committer_must_be_level = gpc_get_int_array( 'repo_commit_committer_must_be_level', MantisEnum::getValues( config_get( 'access_levels_enum_string' ) ));

$t_repo = SourceRepo::load( $f_repo_id );
$t_vcs = SourceVCS::repo( $t_repo );
$t_type = SourceType($t_repo->type);

$t_repo->name = $f_repo_name;
$t_repo->url = $f_repo_url;
$t_repo->info['repo_commit_needs_issue'] = $f_repo_commit_needs_issue;
$t_repo->info['repo_commit_issues_must_exist'] = $f_repo_commit_issues_must_exist;
$t_repo->info['repo_commit_ownership_must_match'] = $f_repo_commit_ownership_must_match;
$t_repo->info['repo_commit_status_restricted'] = $f_repo_commit_status_restricted;
$t_repo->info['repo_commit_status_allowed'] = $f_repo_commit_status_allowed;
$t_repo->info['repo_commit_project_restricted'] = $f_repo_commit_project_restricted;
$t_repo->info['repo_commit_project_allowed'] = $f_repo_commit_project_allowed;
$t_repo->info['repo_commit_committer_must_be_member'] = $f_repo_commit_committer_must_be_member;
$t_repo->info['repo_commit_committer_must_be_level'] = $f_repo_commit_committer_must_be_level;

/** @var SourceRepo $t_updated_repo */
$t_updated_repo = $t_vcs->update_repo( $t_repo );
Expand Down
Loading