diff --git a/SourceBitBucket/SourceBitBucket.php b/SourceBitBucket/SourceBitBucket.php new file mode 100755 index 0000000..c35d3cc --- /dev/null +++ b/SourceBitBucket/SourceBitBucket.php @@ -0,0 +1,408 @@ +name = plugin_lang_get( 'title' ); + $this->description = plugin_lang_get( 'description' ); + + $this->version = '0.18'; + $this->requires = array( + 'MantisCore' => '1.2.16', + 'Source' => '0.18', + ); + + $this->author = 'Sergey Marchenko'; + $this->contact = 'sergey@mzsl.ru'; + $this->url = 'http://zetabyte.ru'; + + } + + public $type = 'bb'; + + public function show_type() { + return plugin_lang_get( 'bitbucket' ); + } + + public function show_changeset( $p_repo, $p_changeset ) { + $t_ref = substr( $p_changeset->revision, 0, 8 ); + $t_branch = $p_changeset->branch; + + return "$t_branch $t_ref"; + } + + public function show_file( $p_repo, $p_changeset, $p_file ) { + return "$p_file->action - $p_file->filename"; + } + + public function url_repo( $p_repo, $p_changeset = null ) { + if( empty($p_repo->info) ) return ''; + + $t_username = $p_repo->info['bit_username']; + $t_reponame = $p_repo->info['bit_reponame']; + $t_ref = ''; + if( !is_null( $p_changeset ) ) + $t_ref = "/src/?at=$p_changeset->revision"; + + return $this->main_url . "$t_username/$t_reponame$t_ref"; + } + + public function url_changeset( $p_repo, $p_changeset ) { + $t_username = $p_repo->info['bit_username']; + $t_reponame = $p_repo->info['bit_reponame']; + $t_ref = $p_changeset->revision; + return $this->main_url . "$t_username/$t_reponame/commits/$t_ref"; + } + + public function url_file( $p_repo, $p_changeset, $p_file ) { + $t_username = $p_repo->info['bit_username']; + $t_reponame = $p_repo->info['bit_reponame']; + $t_ref = $p_changeset->revision; + $t_filename = $p_file->filename; + return $this->main_url . "$t_username/$t_reponame/src/$t_ref/$t_filename"; + } + + public function url_diff( $p_repo, $p_changeset, $p_file ) { + $t_username = $p_repo->info['bit_username']; + $t_reponame = $p_repo->info['bit_reponame']; + $t_ref = $p_changeset->revision; + $t_filename = $p_file->filename; + return $this->main_url . "$t_username/$t_reponame/diff/$t_filename?diff2=$t_ref"; + } + + public function update_repo_form( $p_repo ) { + $t_bit_basic_login = null; + $t_bit_basic_pwd = null; + $t_bit_username = null; + $t_bit_reponame = null; + + if( isset($p_repo->info['bit_basic_login']) ) { + $t_bit_basic_login = $p_repo->info['bit_basic_login']; + } + if( isset($p_repo->info['bit_basic_pwd']) ) { + $t_bit_basic_pwd = $p_repo->info['bit_basic_pwd']; + } + + if( isset($p_repo->info['bit_username']) ) { + $t_bit_username = $p_repo->info['bit_username']; + } + + if( isset($p_repo->info['bit_reponame']) ) { + $t_bit_reponame = $p_repo->info['bit_reponame']; + } + + if( isset($p_repo->info['master_branch']) ) { + $t_master_branch = $p_repo->info['master_branch']; + } else { + $t_master_branch = 'master'; + } + ?> + > + + + + > + + + + > + + + + > + + + + + + + > + + + + info['bit_basic_login'] = $f_basic_login; + $p_repo->info['bit_basic_pwd'] = $f_basic_pwd; + $p_repo->info['bit_username'] = $f_bit_username; + $p_repo->info['bit_reponame'] = $f_bit_reponame; + $p_repo->info['master_branch'] = $f_master_branch; + + return $p_repo; + } + + private function api_url10( $p_path ) { + return $this->api_url_10 . $p_path; + } + + private function api_url20( $p_path ) { + return $this->api_url_20 . $p_path; + } + + private function api_json_url( $p_repo, $p_url ) { + $t_data = $this->url_get( $p_repo, $p_url ); + $t_json = json_decode( utf8_encode( $t_data ) ); + return $t_json; + } + + public function precommit() { + return; + } + + public function commit( $p_repo, $p_data ) { + $t_commits = array(); + + foreach ( $p_data['commits'] as $t_commit ) { + $t_commits[] = $t_commit['id']; + } + + $t_refData = split( '/', $p_data['ref'] ); + $t_branch = $t_refData[2]; + + return $this->import_commits( $p_repo, $t_commits, $t_branch ); + } + + public function import_full( $p_repo, $p_use_cache = true ) { + echo '
';
+		$t_branch = $p_repo->info['master_branch'];
+		if( is_blank( $t_branch ) ) {
+			$t_branch = 'master';
+		}
+
+		if( $t_branch != '*' ) {
+			$t_branches = array_map( 'trim', explode( ',', $t_branch ) );
+		} else {
+			$t_username = $p_repo->info['bit_username'];
+			$t_reponame = $p_repo->info['bit_reponame'];
+			$t_uri      = $this->api_url10( "repositories/$t_username/$t_reponame/branches" );
+			$t_json     = $this->api_json_url( $p_repo, $t_uri );
+			$t_branches = array();
+			foreach ( $t_json as $t_branch ) $t_branches[] = $t_branch->branch;
+		}
+		$t_changesets = array();
+
+		$t_changeset_table = plugin_table( 'changeset', 'Source' );
+
+		foreach ( $t_branches as $t_branch ) {
+			$t_query  = "SELECT parent FROM $t_changeset_table
+				WHERE repo_id=" . db_param() . ' AND branch=' . db_param() .
+						'ORDER BY timestamp ASC';
+			$t_result = db_query_bound( $t_query, array($p_repo->id, $t_branch), 1 );
+
+			$t_commits = array($t_branch);
+
+			if( db_num_rows( $t_result ) > 0 ) {
+				$t_parent = db_result( $t_result );
+				echo "Oldest '$t_branch' branch parent: '$t_parent'\n";
+
+				if( !empty($t_parent) ) {
+					$t_commits[] = $t_parent;
+				}
+			}
+			if( $p_use_cache ) foreach ( $t_commits as $t_commit_id ) $this->load_all_commits( $p_repo, $t_commit_id );
+
+			$t_changesets = array_merge( $t_changesets, $this->import_commits( $p_repo, $t_commits, $t_branch ) );
+		}
+
+		echo '
'; + + return $t_changesets; + } + + public function import_latest( $p_repo ) { + return $this->import_full( $p_repo, false ); + } + + private $commits_cache = array(); + + private function load_all_commits( $p_repo, $p_commit_id, $p_next = '' ) { + $t_username = $p_repo->info['bit_username']; + $t_reponame = $p_repo->info['bit_reponame']; + + $t_url = empty($p_next) ? $this->api_url20( "repositories/$t_username/$t_reponame/commits/$p_commit_id" ) : $p_next; + $t_json = $this->api_json_url( $p_repo, $t_url ); + + if( property_exists( $t_json, 'values' ) ) { + foreach ( $t_json->values as $t_item ) { + $this->commits_cache[$t_item->hash] = $t_item; + } + } + if( property_exists( $t_json, 'next' ) ) $this->load_all_commits( $p_repo, $p_commit_id, $t_json->next ); + } + + public function import_commits( $p_repo, $p_commit_ids, $p_branch = '' ) { + static $s_parents = array(); + static $s_counter = 0; + + $t_username = $p_repo->info['bit_username']; + $t_reponame = $p_repo->info['bit_reponame']; + + if( is_array( $p_commit_ids ) ) { + $s_parents = array_merge( $s_parents, $p_commit_ids ); + } else { + $s_parents[] = $p_commit_ids; + } + + $t_changesets = array(); + + while( count( $s_parents ) > 0 && $s_counter < 200 ) { + $t_commit_id = array_shift( $s_parents ); + + echo "Retrieving $t_commit_id ... "; + $t_json = null; + if( empty($this->commits_cache[$t_commit_id]) ) { + $t_url = $this->api_url20( "repositories/$t_username/$t_reponame/commit/$t_commit_id/" ); + $t_json = $this->api_json_url( $p_repo, $t_url ); + } else { + $t_json = $this->commits_cache[$t_commit_id]; + } + + if( false === $t_json || is_null( $t_json ) ) { + # Some error occured retrieving the commit + echo "failed.\n"; + continue; + } else if( !property_exists( $t_json, 'hash' ) ) { + echo 'failed (', $t_json->error->message, ").\n"; + continue; + } + + list($t_changeset, $t_commit_parents) = $this->json_commit_changeset( $p_repo, $t_json, $p_branch ); + if( $t_changeset ) { + $t_changesets[] = $t_changeset; + } + + $s_parents = array_merge( $s_parents, $t_commit_parents ); + } + + $s_counter = 0; + return $t_changesets; + } + + private function get_author_name( $p_row ) { + return trim( substr( $p_row, 0, strpos( $p_row, '<' ) ) ); + } + + private function get_author_email( $p_row ) { + $start = strpos( $p_row, '<' ) + 1; + $length = strpos( $p_row, '>' ) - $start; + return trim( substr( $p_row, $start, $length ) ); + } + + private function json_commit_changeset( $p_repo, $p_json, $p_branch = '' ) { + + echo "processing $p_json->hash ... "; + if( !SourceChangeset::exists( $p_repo->id, $p_json->hash ) ) { + $t_parents = array(); + foreach ( $p_json->parents as $t_parent ) { + $t_parents[] = $t_parent->hash; + } + + $t_changeset = new SourceChangeset( + $p_repo->id, + $p_json->hash, + $p_branch, + date( 'Y-m-d H:i:s', strtotime( $p_json->date ) ), + $this->get_author_name( $p_json->author->raw ), + $p_json->message + ); + + if( count( $p_json->parents ) > 0 ) { + $t_parent = $p_json->parents[0]; + $t_changeset->parent = $t_parent->hash; + } + + $t_changeset->author_email = $this->get_author_email( $p_json->author->raw ); + $t_changeset->committer = $t_changeset->author; + $t_changeset->committer_email = $t_changeset->author_email; + + + $t_username = $p_repo->info['bit_username']; + $t_reponame = $p_repo->info['bit_reponame']; + $t_commit_id = $p_json->hash; + $t_url = $this->api_url10( "repositories/$t_username/$t_reponame/changesets/$t_commit_id/diffstat/" ); + $t_files = $this->api_json_url( $p_repo, $t_url ); + if( !empty($t_files) ) { + foreach ( $t_files as $t_file ) { + switch( $t_file->type ) { + case 'added': + $t_changeset->files[] = new SourceFile(0, '', $t_file->file, 'add'); + break; + case 'modified': + $t_changeset->files[] = new SourceFile(0, '', $t_file->file, 'mod'); + break; + case 'removed': + $t_changeset->files[] = new SourceFile(0, '', $t_file->file, 'rm'); + break; + } + } + } + + $t_changeset->save(); + + echo "saved.\n"; + return array($t_changeset, $t_parents); + } else { + echo "already exists.\n"; + return array(null, array()); + } + } + + public function url_get( $p_repo, $p_url ) { + $t_user_pass = $p_repo->info['bit_basic_login'] . ':' . $p_repo->info['bit_basic_pwd']; + # Use the PHP cURL extension + if( function_exists( 'curl_init' ) ) { + $t_curl = curl_init( $p_url ); + # cURL options + $t_curl_opt[CURLOPT_USERPWD] = $t_user_pass; + $t_curl_opt[CURLOPT_RETURNTRANSFER] = true; + + $t_vers = curl_version(); + $t_curl_opt[CURLOPT_USERAGENT] = + 'mantisbt/' . MANTIS_VERSION . ' php-curl/' . $t_vers['version']; + + # Set the options + curl_setopt_array( $t_curl, $t_curl_opt ); + + # Retrieve data + $t_data = curl_exec( $t_curl ); + curl_close( $t_curl ); + + if( $t_data !== false ) { + return $t_data; + } + } + # Last resort system call + $t_url = escapeshellarg( $p_url ); //use -u user:pass + return shell_exec( 'curl -u ' . $t_user_pass . ' ' . $t_url ); + } +} diff --git a/SourceBitBucket/lang/strings_english.txt b/SourceBitBucket/lang/strings_english.txt new file mode 100644 index 0000000..79e0ec8 --- /dev/null +++ b/SourceBitBucket/lang/strings_english.txt @@ -0,0 +1,18 @@ +(no spaces; must match the name as received from the webservice\'s payload)'; +$s_plugin_SourceBitBucket_master_branch = 'Primary Branches
(comma-separated list)'; + +$s_plugin_SourceBitBucket_repo_authorized = '

MantisBT is now authorized to access this BitBucket repository.

'; +$s_plugin_SourceBitBucket_repo_authorization_failed = '

Sorry, MantisBT could not be authorized to access this BitBucket repository.

'; + +$s_plugin_SourceBitBucket_oauth_authorization = 'BitBucket OAuth Authorization'; +$s_plugin_SourceBitBucket_back_repo = 'Back to Repository'; diff --git a/SourceBitBucket/lang/strings_russian.txt b/SourceBitBucket/lang/strings_russian.txt new file mode 100644 index 0000000..d50e865 --- /dev/null +++ b/SourceBitBucket/lang/strings_russian.txt @@ -0,0 +1,17 @@ +(только имя в нижней раскладке)'; +$s_plugin_SourceBitBucket_master_branch = 'Главные ветки
(список разделенный запятыми)'; + +$s_plugin_SourceBitBucket_repo_authorized = '

MantisBT авторизован в репозитарии BitBucket.

'; +$s_plugin_SourceBitBucket_repo_authorization_failed = '

Извините, MantisBT не может авторизоваться к этому репозитарию BitBucket.

'; + +$s_plugin_SourceBitBucket_back_repo = 'назад в репозитарии';