diff --git a/.gitignore b/.gitignore index dd4951179..35841d393 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ .DS_Store *.buildpath *.project +*~ diff --git a/CommitMessageCheck.md b/CommitMessageCheck.md new file mode 100755 index 000000000..027cec517 --- /dev/null +++ b/CommitMessageCheck.md @@ -0,0 +1,146 @@ +## Introduction + +*What's the problem?* + +I've got a Mantis project which I use to manage the development of my project/product. When people commit to the version control repository they reference the Mantis issue number in the commits. +I want one or more of the following: + +1. Ensure that commit comments do actually reference one or more issues. I don't think that anyone should be making commits without referencing an issue. +1. I want to ensure that the issue(s) which are referenced in the commit comment are assigned to the person performing the commit +1. I want to ensure that the issue(s) which are referenced in the commit comment are at the confirmed or assigned state and haven't already been closed +1. I want to ensure that the issue(s) which are referenced in the commit comment belong to the appropriate project + +*OK, what's your solution then?* + +To build on the [Source +Integration](https://github.com/mantisbt-plugins/source-integration) plugin in +order to implement the checks and to utilise pre-commit hooks in order to make +the appropriate call-backs to Mantis. If the checks performed by the hook don't +pass then the commit is prevented by the VCS + +*I don't think that you should be so rule-happy with commit comments!* + +It's a matter of choice - some projects prefer to have a greater degree of control/enforcement than others. All of the checks are optional and none are enabled by default. + +*I don't like your software - how else could I do this?* + +I know of the following: + +- [RepoGuard](http://repoguard.tigris.org/) + +## How To Install + +### Step 1 : Install the Mantis Plugin. + +The code is a branch of the Source Integration plugin. Go [here](https://github.com/bright-tools/source-integration) and click the "Download ZIP" link in order to get it. + +Copy the contents of the zip file to the `plugins` directory in your Mantis install. + +Follow steps 4-10 of the [Source Integration plugin installation guide](https://github.com/mantisbt-plugins/source-integration/blob/master/README.md) + +### Step 2 : Install the Hook + +Several example hooks are provided - which one you need to use depends on which version control system you're using. + +#### Subversion (SVN) + +Copy the `SourceSVN/pre-commit.tmpl.mantis-checks-commit` file from the ZIP to your SVN repository's `hooks` directory. Ensure that the file ownership is appropriate it has executable permission set. More information on hooks can be found in the [Version Control with Subversion](http://svnbook.red-bean.com/en/1.7/svn-book.html#svn.reposadmin.create.hooks) book. + +Rename the file within the `hooks` directory to be `pre-commit.tmpl` (i.e. remove the `.tmpl.mantis-checks-commit` extension) + +Modify the `URL` setting to point to the web interface to your Mantis installation. Don't remove the `plugin.php` part or the text which follows that. + +Modify the `PROJECT` setting to match the name that you gave the repository when configuring it in Mantis (Part of Step 1). + +Modify the `API_KEY` setting to match that which Mantis is configured to use (again, part of Step 1). + +If necessary, update the `SVNLOOK` and `CURL` settings to point to where those tools are installed. + +#### Git + +TODO + +### Step 3 : Configure the Mantis Plugin + +All that's left to do now is to choose which checks you want to associate with +the repository. For the purposes of this guide it is assumed that you already +have the basic repository details set up in Mantis as part of your +SourceIntegration configuration. If not then you will need to perform this step +first. + +In the Mantis web front-end, select the "Repositories" link, then click the +"Manage" link on the repository you wish to set up commit checking on. Select +"Update Repository" and you will see a list of configuration options. + +![Configuration options](docimgs/configure_checks.png) + +Select those that you want (see the table below) and click "Update Repository" + + +| Option | Description | +|------------------------------------|--------------| +| Commit Required Issue Reference(s) | When enabled, this check will ensure that the commit comment contains references to one or more Mantis bug IDs. The format of the reference is as per the SourceIntegration plugin's "Bug Link Regex" settings. | +| Referenced Issue(s) Must Exist | When enabled, this check will ensure that the Mantis bug IDs referenced in the commit comment are associated with tickets which exist in Mantis | +| Referenced Issue(s) Must Be Owned By Committer | When enabled, this check will cross-reference the user-name of the committer with the user-name to which the bug ID(s) referenced in the commit comment are assigned. In the case that they don't all match, the check will fail | +| Committer must be a member of the Mantis project | When enabled, this check will cross-reference the user-name of the committer and the user-names associated with the Mantis project (see the project's configuration under "Manage Projects" in Mantis). In the case that the committer is not listed as a project member, the check will fail | +| Committer Must Be A | In the case that the previous check is enabled, this field allows the check to be expanded to limit the access levels at which a commit is allowed. By default, commit is allowed at all levels. | +| Referenced Issue(s) must be at a particular status | When enabled, this check examine the status of the bugs referenced in the commit comment. In the case that one or more of the tickets is not one of the statuses listed in the "Only allow commit when ticket is" list, the check will fail | +| Only allow commit when ticket is | See previous item | +| Referenced Issue(s) must be within a particular project | When enabled, this check cross-references the Mantis projects to which referenced bugs belong and the list specified in the "Only allow commits when ticket is within" option. In the case that one or more ticket is not a member of the specified list of Mantis projects, the check fails. | +| Only allow commits when ticket is within | See previous item | + +### Step 4 : Quick Test (Optional) + +A simple way to quickly test that your set-up is working is to enable the option to enforce issue references in commit comments, then to attempt to commit to the repository without referencing any issues. The commit should be refused. Of course in the case that the installation has not worked correctly, you will actually commit the file, so please be prepared for this! + +## How to use + +If the installation has been successful then all you need to do is ensure that +commit comments reference the appropriate tickets, using the appropriate format +of comments. The format for referencing comments is configured as a regular +expression as part of the Source Integration plugin configuration. By default +it recognises comments containing text such as `issue #12` or `issue #12,#61`, etc. + +### Example + + bright-tools@ubuntu:~/repo$ svn commit -m "Issue #1,#8: Fix up the typos" + Sending example.txt + Transmitting file data .svn: E165001: Commit failed (details follow): + svn: E165001: Commit blocked by pre-commit hook (exit code 1) with output: + % Total % Received % Xferd Average Speed Time Time Time Current + Dload Upload Total Spent Left Speed + 100 778 100 699 100 79 44573 5037 --:--:-- --:--:-- --:--:-- 46600 + Committing user does not have appropriate access level in project : Issue 1 (updater vs manager, administrator) + Commit comment references non-existent issue : Issue 8 + bright-tools@ubuntu:~/repo$ + +## Potential Problems + +*The user-names used for version control don't match those used in Mantis* + +That's unfortunate and will require some manual intervention. Possibly the easiest way to work around this is to create a look-up function to return the Mantis user-name based on the version control user name then modify the hook function to call this. + +*I'm worried that information will 'leak' from the Mantis database - maybe someone could use this functionality to extract private information from Mantis?* + +The Mantis installation and the VCS repository need to be set up to share a private key (as per SourceIntegration). This means that someone without access to the API key will not be able to access the functionality used to check commit messages. +In the case that someone has access to the API (either by having access to the private key or by having commit access to an associated repository) then negative responses are intended to be informational in order to assist the user in understanding why the commit was refused. This may mean that information relating to access levels or user names may be shown in the refusal message. If this is a concern, changing the value of `$t_informational_errors` from `true` to `false` in `Source/pages/pre_commit_check.php` will restrict the information to a minimum. + +## Testing + +The code can be tested in an automated manner thanks to +[Vagrant](https://www.vagrantup.com/). You need to have this installed in order +to run the tests + +In order to set up the appropriate environment: + + bright-tools@ubuntu:~/source-integration$ cd testsupport + bright-tools@ubuntu:~/source-integration/testsupport$ vagrant up + +This should create a virtual machine and install the appropriate software +(including Mantis & importing the SourceIntegration code from your working area). + +To run the tests: + + bright-tools@ubuntu:~/source-integration/testsupport$ vagrant ssh + ... + vagrant@vagrant-ubuntu-trusty-64:~$ /vagrant/run_tests.sh diff --git a/Source/Source.API.php b/Source/Source.API.php index 60c6f88e5..cbb8fc41b 100644 --- a/Source/Source.API.php +++ b/Source/Source.API.php @@ -364,7 +364,7 @@ function Source_Process_Changesets( $p_changesets, $p_repo=null ) { } } - if ( $t_handler && !is_null( $t_user_id ) ) { + if ( $t_handler && !is_null( $t_user_id ) && access_has_project_level( config_get( 'handle_bug_threshold' ), $t_bug->project_id, $t_user_id )) { $t_bug->handler_id = $t_user_id; } diff --git a/Source/lang/strings_english.txt b/Source/lang/strings_english.txt old mode 100644 new mode 100755 index f80bfc82d..1369b5bb9 --- a/Source/lang/strings_english.txt +++ b/Source/lang/strings_english.txt @@ -25,6 +25,16 @@ $s_plugin_Source_username = 'Username'; $s_plugin_Source_timestamp = 'Timestamp'; $s_plugin_Source_parent = 'Parent'; $s_plugin_Source_url = 'URL'; +$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_info = 'Extra Info'; $s_plugin_Source_revision = 'Revision'; $s_plugin_Source_date_begin = 'Beginning Date'; @@ -137,11 +147,21 @@ $s_plugin_Source_import_repo_error = 'Import process produced an error.'; $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_repo = 'Invalid repository name. Please check that you have set the PROJECT variable correctly in the hook script'; $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.'; +$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'; + $s_plugin_Source_changeset_column_title = 'C'; diff --git a/Source/pages/pre_commit_check.php b/Source/pages/pre_commit_check.php new file mode 100755 index 000000000..39c71e4de --- /dev/null +++ b/Source/pages/pre_commit_check.php @@ -0,0 +1,230 @@ +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 = project_get_local_user_access_level( $t_bug->project_id, $t_user_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 ); + +?> diff --git a/Source/pages/repo_update.php b/Source/pages/repo_update.php old mode 100644 new mode 100755 index 99931f70b..d999d3659 --- a/Source/pages/repo_update.php +++ b/Source/pages/repo_update.php @@ -9,6 +9,15 @@ $f_repo_id = gpc_get_int( 'repo_id' ); $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 ); @@ -16,6 +25,15 @@ $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; $t_updated_repo = $t_vcs->update_repo( $t_repo ); diff --git a/Source/pages/repo_update_page.php b/Source/pages/repo_update_page.php old mode 100644 new mode 100755 index 881c421e5..047191615 --- a/Source/pages/repo_update_page.php +++ b/Source/pages/repo_update_page.php @@ -10,9 +10,47 @@ $t_repo = SourceRepo::load( $f_repo_id ); $t_vcs = SourceVCS::repo( $t_repo ); $t_type = SourceType($t_repo->type); +$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_committer_must_be_member = isset( $t_repo->info['repo_commit_committer_must_be_member'] ) ? $t_repo->info['repo_commit_committer_must_be_member'] : false; +$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_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'] : MantisEnum::getValues( config_get( 'status_enum_string' )); +$t_repo_commit_project_restricted = isset( $t_repo->info['repo_commit_project_restricted'] ) ? $t_repo->info['repo_commit_project_restricted'] : false; +$t_repo_commit_project_allowed = isset( $t_repo->info['repo_commit_project_allowed'] ) ? $t_repo->info['repo_commit_project_allowed'] : Array( 0 ); html_page_top1( plugin_lang_get( 'title' ) ); html_page_top2(); + +if( ON == config_get( 'use_javascript' ) ) { + $t_useJS = ' onclick="Source_Update_CheckOpts();" '; + html_javascript_link( 'addLoadEvent.js' ); +?> + +
@@ -41,11 +79,65 @@ + + update_repo_form( $t_repo ) ?> +> + + + +> + + + + +> + + + + +> + + + + +> + + + + +> + + + + +> + + + + +> + + + + +> + + + + +> + + + + +
/>
/>
/>
id="repo_commit_committer_must_be_member" name="repo_commit_committer_must_be_member" type="checkbox" />
name="repo_commit_status_restricted" id="repo_commit_status_restricted" type="checkbox" />
id="repo_commit_project_restricted" name="repo_commit_project_restricted" type="checkbox" />
+ + diff --git a/Source/pages/si_common.php b/Source/pages/si_common.php new file mode 100755 index 000000000..111ce6bf5 --- /dev/null +++ b/Source/pages/si_common.php @@ -0,0 +1,8 @@ + diff --git a/SourceSVN/pre-commit.tmpl.mantis-checks-commit b/SourceSVN/pre-commit.tmpl.mantis-checks-commit new file mode 100755 index 000000000..737d5fc93 --- /dev/null +++ b/SourceSVN/pre-commit.tmpl.mantis-checks-commit @@ -0,0 +1,78 @@ +#!/bin/sh + +# Copyright (c) 2014 John Bailey +# Licensed under the MIT license +# +# Requires GNU grep with PCRE + +# Customise the following settings based on your Mantis installation +URL="http://localhost/mantis/plugin.php?page=Source/pre_commit_check" +PROJECT="RepoName" +API_KEY="dd" + +SVNLOOK=/usr/bin/svnlook +CURL=/usr/bin/curl + +# Set this to 1 during testing so that even commits which pass the +# mantis checks will be halted +BOUNCE_ALL_COMMITS=0 + +# Deal with hook parameters +REPOS="$1" +TXN="$2" + +LOG_FILE=`mktemp /tmp/svn_log.XXX` +COMMENT_FILE=`mktemp /tmp/svn_comment.XXX` + +# Exit as soon as an error is encountered +#set -e + +# Check for tools + +if [ ! -x "$SVNLOOK" ]; then + echo "You need to update the script at $0 to point to svnlook" 1>&2 + exit 1 +fi + +if [ ! -x "$CURL" ]; then + echo "You need to update the script at $0 to point to curl" 1>&2 + exit 1 +fi + +COMMITTING_USER=$("${SVNLOOK}" author -t "${TXN}" "${REPOS}") + +# Put the commit comment into a file which we can pass to curl +echo 'commit_comment="' >> ${COMMENT_FILE} +"${SVNLOOK}" log -t "${TXN}" "${REPOS}" >> ${COMMENT_FILE} +echo '"' >> ${COMMENT_FILE} + +# Fire off the query to Mantis (-s -S to prevent progress bar but keep error +# reporting +"${CURL}" -s -S -d "repo_name=${PROJECT}" -d "committer=${COMMITTING_USER}" -d @${COMMENT_FILE} -d "api_key=${API_KEY}" ${URL} >> ${LOG_FILE} + +# Try and extract the result from the response +RESULT=$(grep -oP 'Check-OK: \K([0-9]+)' ${LOG_FILE}) + +if [ "x$RESULT" = "x" ]; then + echo "Didn't receive a valid response from Mantis SourceIntegration" 1>&2 + echo "Received:" 1>&2 + echo "-----------8<--------------------" 1>&2 + cat ${LOG_FILE} 1>&2 + echo 1>&2 + echo "-----------8<--------------------" 1>&2 + exit 1; +elif [ $RESULT -eq 0 ]; then + CHECK_MESSAGE=$(grep -oP "Check-Message: '\K(.+)(?=')" ${LOG_FILE}) + if [ "x$CHECK_MESSAGE" = "x" ]; then + echo "Mantis SourceIntegration bounced the commit but didn't report why" 1>&2 + else + echo "$CHECK_MESSAGE" 1>&2 + fi + exit 1 +else + # Success! + exit $BOUNCE_ALL_COMMITS +fi + +exit 1 + diff --git a/SourceViewVC/LICENSE b/SourceViewVC/LICENSE new file mode 100755 index 000000000..9c6c2e6fb --- /dev/null +++ b/SourceViewVC/LICENSE @@ -0,0 +1,23 @@ +Copyright (c) 2015 John Bailey + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + diff --git a/SourceViewVC/SourceViewVC.php b/SourceViewVC/SourceViewVC.php new file mode 100755 index 000000000..cf329ea52 --- /dev/null +++ b/SourceViewVC/SourceViewVC.php @@ -0,0 +1,169 @@ +name = lang_get( 'plugin_SourceViewVC_title' ); + $this->description = lang_get( 'plugin_SourceViewVC_description' ); + + $this->version = '0.1'; + $this->requires = array( + 'MantisCore' => '1.2.0', + 'Source' => '0.16', + 'SourceSVN' => '0.16', + ); + + $this->author = 'John Bailey'; + $this->contact = 'dev@brightsilence.com'; + $this->url = 'https://github.com/bright-tools/source-integration'; + } + + public $type = 'viewvc'; + + public function show_type() { + return lang_get( 'plugin_SourceViewVC_svn' ); + } + + public function get_viewvc_url( $p_repo ) { + return isset( $p_repo->info['viewvc_url'] ) + ? $p_repo->info['viewvc_url'] + : ''; + } + + public function get_viewvc_name( $p_repo ) { + return isset( $p_repo->info['viewvc_name'] ) + ? $p_repo->info['viewvc_name'] + : ''; + } + + public function get_viewvc_use_checkout( $p_repo ) { + return isset( $p_repo->info['viewvc_use_checkout'] ) + ? $p_repo->info['viewvc_use_checkout'] + : false; + } + + public function get_viewvc_root_as_url( $p_repo ) { + return isset( $p_repo->info['viewvc_root_as_url'] ) + ? $p_repo->info['viewvc_root_as_url'] + : false; + } + + /** + * Builds the ViewVC URL base string + * @param object $p_repo repository + * @param string $p_file optional filename (as absolute path from root) + * @param array $p_opts optional additional ViewVC URL parameters + * @return string ViewVC URL + */ + protected function url_base( $p_repo, $p_file = '', $p_opts=array() ) { + $t_name = urlencode( $this->get_viewvc_name( $p_repo ) ); + $t_root_as_url = $this->get_viewvc_root_as_url( $p_repo ); + + $t_url = rtrim( $this->get_viewvc_url( $p_repo ), '/' ); + + if( $t_root_as_url ) { + $t_url_name = '/'.$t_name; + } else { + $t_url_name = ''; + $p_opts['root']=$t_name; + } + + return $t_url . $t_url_name . $p_file . '?' . http_build_query( $p_opts ); + } + + public function url_repo( $p_repo, $p_changeset=null ) { + $t_opts = array(); + + if ( !is_null( $p_changeset ) ) { + $t_opts['revision'] = $p_changeset->revision; + } + + return $this->url_base( $p_repo, '', $t_opts); + } + + public function url_changeset( $p_repo, $p_changeset ) { + $t_rev = $p_changeset->revision; + $t_opts = array(); + $t_opts['view'] = 'revision'; + $t_opts['revision'] = $t_rev; + + return $this->url_base( $p_repo, '', $t_opts ); + } + + public function url_file( $p_repo, $p_changeset, $p_file ) { + + # if the file has been removed, it doesn't exist in current revision + # so we generate a link to (current revision - 1) + $t_revision = ($p_file->action == 'rm') + ? $p_changeset->revision - 1 + : $p_changeset->revision; + $t_use_checkout = $this->get_viewvc_use_checkout( $p_repo ); + + $t_opts = array(); + $t_opts['revision'] = $t_revision; + + if( !$t_use_checkout ) + { + $t_opts['view'] = 'markup'; + } + + return $this->url_base( $p_repo, $p_file->filename, $t_opts ); + } + + public function url_diff( $p_repo, $p_changeset, $p_file ) { + if ( $p_file->action == 'rm' || $p_file->action == 'add' ) { + return ''; + } + + $t_opts = array(); + $t_opts['r1'] = $p_changeset->revision; + $t_opts['r2'] = $p_changeset->revision - 1; + + return $this->url_base( $p_repo, $p_file->filename, $t_opts ); + } + + public function update_repo_form( $p_repo ) { + $t_url = $this->get_viewvc_url( $p_repo ); + $t_name = $this->get_viewvc_name( $p_repo ); + $t_use_checkout = $this->get_viewvc_use_checkout( $p_repo ); + $t_root_as_url = $this->get_viewvc_root_as_url( $p_repo ); + +?> +> + + + +> + + + +> + +/> + +> + +/> + +info['viewvc_url'] = gpc_get_string( 'viewvc_url' ); + $p_repo->info['viewvc_name'] = gpc_get_string( 'viewvc_name' ); + $p_repo->info['viewvc_use_checkout'] = gpc_get_bool( 'viewvc_use_checkout', false ); + $p_repo->info['viewvc_root_as_url'] = gpc_get_bool( 'viewvc_root_as_url', false ); + + return parent::update_repo( $p_repo ); + } +} diff --git a/SourceViewVC/lang/strings_english.txt b/SourceViewVC/lang/strings_english.txt new file mode 100755 index 000000000..ce47090f4 --- /dev/null +++ b/SourceViewVC/lang/strings_english.txt @@ -0,0 +1,22 @@ +(With trailing slash)'; +$s_plugin_SourceViewVC_viewvc_name = 'ViewVC Name
(Repository directory)'; +$s_plugin_SourceViewVC_viewvc_root_as_url = 'ViewVC Root As URL Component Enabled?'; +$s_plugin_SourceViewVC_viewvc_use_checkout = 'ViewVC Checkout View Enabled?'; + +$s_plugin_SourceViewVC_svn_username = 'SVN Username'; +$s_plugin_SourceViewVC_svn_password = 'SVN Password'; +$s_plugin_SourceViewVC_standard_repo = 'Standard Repository
(trunk/branches/tags)'; +$s_plugin_SourceViewVC_trunk_path = 'Trunk Path
(Non-standard repository)'; +$s_plugin_SourceViewVC_branch_path = 'Branch Path
(Non-standard repository)'; +$s_plugin_SourceViewVC_tag_path = 'Tag Path
(Non-standard repository)'; +$s_plugin_SourceViewVC_ignore_paths = 'Ignore Other Paths
(Non-standard repository)'; diff --git a/docimgs/configure_checks.png b/docimgs/configure_checks.png new file mode 100755 index 000000000..d0a93d8e1 Binary files /dev/null and b/docimgs/configure_checks.png differ diff --git a/testsupport/Vagrantfile b/testsupport/Vagrantfile new file mode 100755 index 000000000..0e7be88b2 --- /dev/null +++ b/testsupport/Vagrantfile @@ -0,0 +1,97 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +# All Vagrant configuration is done below. The "2" in Vagrant.configure +# configures the configuration version (we support older styles for +# backwards compatibility). Please don't change it unless you know what +# you're doing. +Vagrant.configure(2) do |config| + # The most common configuration options are documented and commented below. + # For a complete reference, please see the online documentation at + # https://docs.vagrantup.com. + + # Every Vagrant development environment requires a box. You can search for + # boxes at https://atlas.hashicorp.com/search. + config.vm.box = "ubuntu/trusty64" + + # Disable automatic box update checking. If you disable this, then + # boxes will only be checked for updates when the user runs + # `vagrant box outdated`. This is not recommended. + # config.vm.box_check_update = false + + # Create a forwarded port mapping which allows access to a specific port + # within the machine from a port on the host machine. In the example below, + # accessing "localhost:8080" will access port 80 on the guest machine. + config.vm.network "forwarded_port", guest: 80, host: 8080 + + # Create a private network, which allows host-only access to the machine + # using a specific IP. + # config.vm.network "private_network", ip: "192.168.33.10" + + # Create a public network, which generally matched to bridged network. + # Bridged networks make the machine appear as another physical device on + # your network. + # config.vm.network "public_network" + + # Share an additional folder to the guest VM. The first argument is + # the path on the host to the actual folder. The second argument is + # the path on the guest to mount the folder. And the optional third + # argument is a set of non-required options. + config.vm.synced_folder "../", "/source-integration" + + # Provider-specific configuration so you can fine-tune various + # backing providers for Vagrant. These expose provider-specific options. + # Example for VirtualBox: + # + config.vm.provider "virtualbox" do |vb| + # # Display the VirtualBox GUI when booting the machine + # vb.gui = true + # + # Customize the amount of memory on the VM - needed because MySQL fails + # install with the default 1/2 gig + vb.memory = "1024" + end + # + # View the documentation for the provider you are using for more + # information on available options. + + # Define a Vagrant Push strategy for pushing to Atlas. Other push strategies + # such as FTP and Heroku are also available. See the documentation at + # https://docs.vagrantup.com/v2/push/atlas.html for more information. + # config.push.define "atlas" do |push| + # push.app = "YOUR_ATLAS_USERNAME/YOUR_APPLICATION_NAME" + # end + + # Enable provisioning with a shell script. Additional provisioners such as + # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the + # documentation for more information about their specific syntax and use. + config.vm.provision "shell", inline: <<-SHELL + sudo apt-get update + sudo apt-get install -y apache2 libapache2-mod-php5 subversion openssl + + # Automated MySQL installation + sudo debconf-set-selections <<< 'mysql-server mysql-server/root_password password abc123' + sudo debconf-set-selections <<< 'mysql-server mysql-server/root_password_again password abc123' + sudo apt-get install -y mysql-server-5.6 php5-mysql + + # Install Mantis + sudo apt-get install unzip + cd /tmp + wget http://downloads.sourceforge.net/project/mantisbt/mantis-stable/1.2.19/mantisbt-1.2.19.zip + unzip mantisbt-1.2.19.zip + cp -r mantisbt-1.2.19 /var/www/html/mantis + + # Install Source Integration base + cp -r /source-integration/Source /var/www/html/mantis/plugins + cp -r /source-integration/SourceSVN /var/www/html/mantis/plugins + + # Fix permissions + sudo chown -R www-data:www-data /var/www/html/mantis + sudo find /var/www/html/mantis -type d -exec chmod 755 {} + + sudo chmod og+r -R /var/www/html/mantis + + # Configure Mantis + wget http://localhost/mantis/admin/install.php?db_type=mysql&hostname=localhost&username=root&db_password=abc123&database_name=bugtracker&install=2 + + SHELL +end diff --git a/testsupport/expectedoutput/test_enabled_invalid_bug_ref_allowed.txt b/testsupport/expectedoutput/test_enabled_invalid_bug_ref_allowed.txt new file mode 100755 index 000000000..dec1f1014 --- /dev/null +++ b/testsupport/expectedoutput/test_enabled_invalid_bug_ref_allowed.txt @@ -0,0 +1,3 @@ +Adding svn_sandbox/file2 +Transmitting file data . +Committed revision 2. diff --git a/testsupport/expectedoutput/test_enabled_invalid_bug_ref_not_allowed.txt b/testsupport/expectedoutput/test_enabled_invalid_bug_ref_not_allowed.txt new file mode 100755 index 000000000..82bf6728b --- /dev/null +++ b/testsupport/expectedoutput/test_enabled_invalid_bug_ref_not_allowed.txt @@ -0,0 +1,5 @@ +Adding svn_sandbox/file3 +Transmitting file data .svn: E165001: Commit failed (details follow): +svn: E165001: Commit blocked by pre-commit hook (exit code 1) with output: +Commit comment references non-existent issue : Issue 9999 + diff --git a/testsupport/expectedoutput/test_enabled_no_bug_ref.txt b/testsupport/expectedoutput/test_enabled_no_bug_ref.txt new file mode 100755 index 000000000..5031045ec --- /dev/null +++ b/testsupport/expectedoutput/test_enabled_no_bug_ref.txt @@ -0,0 +1,5 @@ +Adding svn_sandbox/file2 +Transmitting file data .svn: E165001: Commit failed (details follow): +svn: E165001: Commit blocked by pre-commit hook (exit code 1) with output: +Commit comments needs to reference one or more issues + diff --git a/testsupport/expectedoutput/test_not_enabled.txt b/testsupport/expectedoutput/test_not_enabled.txt new file mode 100755 index 000000000..2f6db4d72 --- /dev/null +++ b/testsupport/expectedoutput/test_not_enabled.txt @@ -0,0 +1,3 @@ +Adding svn_sandbox/file1 +Transmitting file data . +Committed revision 1. diff --git a/testsupport/run_tests.sh b/testsupport/run_tests.sh new file mode 100755 index 000000000..7b1f604ed --- /dev/null +++ b/testsupport/run_tests.sh @@ -0,0 +1,114 @@ +# Get a login +export WGET_PARAMS="--keep-session-cookies --save-cookies cookies.txt --load-cookies cookies.txt" +export REPO_NAME=test1 + +set_repo_options() +{ + wget -nv -O- $WGET_PARAMS --post-data="page=Source/repo_update_page&id=`cat repo_id.txt`" http://localhost/mantis/plugin.php | sed -ne 's/.*plugin_Source_repo_update_token" value="\([A-Za-z0-9]*\).*/\1/p' > update_token.txt + wget -nv -O- $WGET_PARAMS --post-data="page=Source/repo_update&repo_id=`cat repo_id.txt`&plugin_Source_repo_update_token=`cat update_token.txt`&repo_commit_issues_must_exist=$2&repo_commit_needs_issue=$1&repo_name=$REPO_NAME&repo_url=file%3A%2F%2F%2Fhome%2Fvagrant%2Fsvn_repo&svn_username=&svn_password=&standard_repository=&trunk_path=&branch_path=&tag_path=&ignore_paths=" http://localhost/mantis/plugin.php > /dev/null +} + +setup_mantis() +{ + wget -nv -O- --keep-session-cookies --save-cookies cookies.txt --post-data 'username=administrator&password=root&perm_login=1' http://localhost/mantis/login.php > /dev/null + # Install 'Source' + wget -nv -O- $WGET_PARAMS http://localhost/mantis/manage_plugin_page.php | sed -ne 's/.*\(manage_plugin_install\.php?name=Source[a-zA-Z0-9=&;_]*\).*/\1/p' | sed -e 's/\(&\)/\&/g' > install_url.txt + wget -nv -O- $WGET_PARAMS http://localhost/mantis/`cat install_url.txt` > /dev/null + # Install 'Subversion Integration' + wget -nv -O- $WGET_PARAMS http://localhost/mantis/manage_plugin_page.php | sed -ne 's/.*\(manage_plugin_install\.php?name=SourceSVN[a-zA-Z0-9=&;_]*\).*/\1/p' | sed -e 's/\(&\)/\&/g' > install_url.txt + wget -nv -O- $WGET_PARAMS http://localhost/mantis/`cat install_url.txt` > /dev/null +} + +configure_si() +{ + # Configure Source Integration + openssl rand -hex 12 > api_key.txt + wget -nv -O- $WGET_PARAMS http://localhost/mantis/plugin.php?page=Source/manage_config_page | sed -ne 's/.*plugin_Source_manage_config_token" value="\([A-Za-z0-9]*\).*/\1/p' > config_token.txt + wget -nv -O- $WGET_PARAMS --post-data="enable_message=1&import_urls=localhost&checkin_urls=localhost&bugfix_handler=1&bugfix_message_view_status=10&bugfix_message=Fix%20committed%20to%20\$1%20branch.&bugfix_resolution=20&bugfix_status=-1&bugfix_regex_2=/#?(\\d%2b)/&bugfix_regex_1=/(?:fixe?d?s?|resolved?s?)%2b\\s*:?\\s%2b(?:#(?:\\d%2b)[,\\.\\s]*)%2b/i&buglink_regex_2=/#?(\\d%2b)/&buglink_regex_1=/(?:bugs?|issues?|reports?)%2b\\s*:?\\s%2b(?:#(?:\\d%2b)[,\\.\\s]*)%2b/i&api_key=`cat api_key.txt`&show_repo_link=1&username_threshold=55&manage_threshold=90&update_threshold=20&view_threshold=10&plugin_Source_manage_config_token=`cat config_token.txt`" http://localhost/mantis/plugin.php?page=Source/manage_config > /dev/null +} + +setup_mantis_repo() +{ +# Set up a repo +wget -nv -O- $WGET_PARAMS http://localhost/mantis/plugin.php?page=Source/index | sed -ne 's/.*plugin_Source_repo_create_token" value="\([A-Za-z0-9]*\).*/\1/p' > create_token.txt +wget -nv -O- $WGET_PARAMS --post-data="repo_name=$REPO_NAME&repo_type=svn&plugin_Source_repo_create_token=`cat create_token.txt`" http://localhost/mantis/plugin.php?page=Source/repo_create > /dev/null +wget -nv -O- $WGET_PARAMS http://localhost/mantis/plugin.php?page=Source/index | grep -A6 $REPO_NAME | sed -ne 's/.*id=\([^"]*\).*/\1/p' > repo_id.txt +} + +delete_mantis_repo() +{ +# Set up a repo +wget -nv -O- $WGET_PARAMS --post-data="id=`cat repo_id.txt`" http://localhost/mantis/plugin.php?page=Source/repo_manage_page | sed -ne 's/.*plugin_Source_repo_delete_token" value="\([A-Za-z0-9]*\).*/\1/p' > delete_token.txt +wget -nv -O- $WGET_PARAMS --post-data="_confirmed=1&id=`cat repo_id.txt`&plugin_Source_repo_delete_token=`cat delete_token.txt`" http://localhost/mantis/plugin.php?page=Source/repo_delete > /dev/null +#rm repo_id.txt +} + +setup_project() +{ +# Set up a project +wget -nv -O- $WGET_PARAMS http://localhost/mantis/manage_proj_create_page.php | sed -ne 's/.*manage_proj_create_token" value="\([A-Za-z0-9]*\).*/\1/p' > proj_create_token.txt +wget -nv -O- $WGET_PARAMS --post-data="description=test&name=test_project&status=10&view_state=10&repo_type=svn&manage_proj_create_token=`cat proj_create_token.txt`" http://localhost/mantis/manage_proj_create.php > /dev/null +wget -nv -O- $WGET_PARAMS http://localhost/mantis/manage_proj_page.php | grep test_project | sed -ne 's/.*project_id=\([^"]\).*/\1/p' > project_id.txt +# Add a category to the project +wget -nv -O- $WGET_PARAMS http://localhost/mantis/manage_proj_edit_page.php?project_id=`cat project_id.txt` | sed -ne 's/.*manage_proj_cat_add_token" value="\([A-Za-z0-9]*\).*/\1/p' > cat_add_token.txt +wget -nv -O- $WGET_PARAMS --post-data="manage_proj_cat_add_token=`cat cat_add_token.txt`&project_id=`cat project_id.txt`&name=Cat1" http://localhost/mantis/manage_proj_cat_add.php > /dev/null +} + +check_test_result() +{ + cmp $1 /vagrant/expectedoutput/$1 > /dev/null 2>&1 + if [ $? == 0 ] + then + echo "Test $1: OK" + else + echo "Test $1: Failed" + fi +} + +setup_mantis +configure_si +setup_mantis_repo +setup_project + +rm -rf test_*.txt +rm -rf svn_repo +mkdir svn_repo +svnadmin create svn_repo +cat /var/www/html/mantis/plugins/SourceSVN/pre-commit.tmpl.mantis-checks-commit | sed -e "s/PROJECT=\"\([a-zA-Z0-9]*\)\"/PROJECT=\"$REPO_NAME\"/;s/API_KEY=.*/API_KEY=\"`cat api_key.txt`\"/" > svn_repo/hooks/pre-commit +cat /var/www/html/mantis/plugins/SourceSVN/post-commit.tmpl | sed -e "s/mantisbt/mantis/;s/PROJECT=\"\([a-zA-Z0-9 ]*\)\"/PROJECT=\"$REPO_NAME\"/;s/API_KEY=.*/API_KEY=\"`cat api_key.txt`\"/" > svn_repo/hooks/post-commit +chmod +x svn_repo/hooks/pre-commit svn_repo/hooks/post-commit + +rm -rf svn_sandbox +svn checkout file:///`pwd`/svn_repo svn_sandbox + +# Check that we can do a commit without any bug reference when the option is +# disabled +set_repo_options 0 0 +touch svn_sandbox/file1 +svn add svn_sandbox/file1 > /dev/null +svn commit -m "Hello" svn_sandbox/file1 > test_not_enabled.txt 2>&1 + +# Enable 'commit requires issue reference' and try and commit without +# referencing an issue +set_repo_options 1 0 +touch svn_sandbox/file2 +svn add svn_sandbox/file2 > /dev/null +svn commit -m "Hello" svn_sandbox/file2 > test_enabled_no_bug_ref.txt 2>&1 + +# Include a bug reference (it's invalid, but checking of validity is not +# enabled, so the commit should be accepted +svn commit -m "bug: #9999" svn_sandbox/file2 > test_enabled_invalid_bug_ref_allowed.txt 2>&1 + +# Turn on checking of bug reference validity & try and commit again - +# should be rejected +set_repo_options 1 1 +touch svn_sandbox/file3 +svn add svn_sandbox/file3 > /dev/null +svn commit -m "bug: #9999" svn_sandbox/file3 > test_enabled_invalid_bug_ref_not_allowed.txt 2>&1 + +delete_mantis_repo + +for X in test_*.txt; do + check_test_result $X; +done +