Initial commit

This commit is contained in:
2020-04-07 13:03:04 +00:00
committed by Gitium
commit 00f842d9bf
1673 changed files with 471161 additions and 0 deletions

View File

@ -0,0 +1,667 @@
<?php
/* Copyright 2014-2016 Presslabs SRL <ping@presslabs.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
define('GITIGNORE', <<<EOF
*.log
*.swp
*.back
*.bak
*.sql
*.sql.gz
~*
.htaccess
.maintenance
wp-config.php
sitemap.xml
sitemap.xml.gz
wp-content/uploads/
wp-content/blogs.dir/
wp-content/upgrade/
wp-content/backup-db/
wp-content/cache/
wp-content/backups/
wp-content/advanced-cache.php
wp-content/object-cache.php
wp-content/wp-cache-config.php
wp-content/db.php
wp-admin/
wp-includes/
/index.php
/license.txt
/readme.html
# de_DE
/liesmich.html
# it_IT
/LEGGIMI.txt
/licenza.html
# da_DK
/licens.html
# es_ES, es_PE
/licencia.txt
# hu_HU
/licenc.txt
/olvasdel.html
# sk_SK
/licencia-sk_SK.txt
# sv_SE
/licens-sv_SE.txt
/wp-activate.php
/wp-blog-header.php
/wp-comments-post.php
/wp-config-sample.php
/wp-cron.php
/wp-links-opml.php
/wp-load.php
/wp-login.php
/wp-mail.php
/wp-settings.php
/wp-signup.php
/wp-trackback.php
/xmlrpc.php
EOF
);
class Git_Wrapper {
private $last_error = '';
private $gitignore = GITIGNORE;
function __construct( $repo_dir ) {
$this->repo_dir = $repo_dir;
$this->private_key = '';
}
function _rrmdir( $dir ) {
if ( empty( $dir ) || ! is_dir( $dir ) ) {
return false;
}
$files = array_diff( scandir( $dir ), array( '.', '..' ) );
foreach ( $files as $file ) {
$filepath = realpath("$dir/$file");
( is_dir( $filepath ) ) ? $this->_rrmdir( $filepath ) : unlink( $filepath );
}
return rmdir( $dir );
}
function _log(...$args) {
if ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ) { return; }
$output = '';
if (isset($args) && $args) foreach ( $args as $arg ) {
$output .= var_export($arg, true).'/n/n';
}
if ($output) error_log($output);
}
function _git_temp_key_file() {
$key_file = tempnam( sys_get_temp_dir(), 'ssh-git' );
return $key_file;
}
function set_key( $private_key ) {
$this->private_key = $private_key;
}
private function get_env() {
$env = array();
$key_file = null;
if ( defined( 'GIT_SSH' ) && GIT_SSH ) {
$env['GIT_SSH'] = GIT_SSH;
} else {
$env['GIT_SSH'] = dirname( __FILE__ ) . '/ssh-git';
}
if ( defined( 'GIT_KEY_FILE' ) && GIT_KEY_FILE ) {
$env['GIT_KEY_FILE'] = GIT_KEY_FILE;
} elseif ( $this->private_key ) {
$key_file = $this->_git_temp_key_file();
chmod( $key_file, 0600 );
file_put_contents( $key_file, $this->private_key );
$env['GIT_KEY_FILE'] = $key_file;
}
return $env;
}
protected function _call(...$args) {
$args = join( ' ', array_map( 'escapeshellarg', $args ) );
$cmd = "git $args 2>&1";
$return = -1;
$response = array();
$env = $this->get_env();
$proc = proc_open(
$cmd,
array(
0 => array( 'pipe', 'r' ), // stdin
1 => array( 'pipe', 'w' ), // stdout
),
$pipes,
$this->repo_dir,
$env
);
if ( is_resource( $proc ) ) {
fclose( $pipes[0] );
while ( $line = fgets( $pipes[1] ) ) {
$response[] = rtrim( $line, "\n\r" );
}
$return = (int)proc_close( $proc );
}
$this->_log( "$return $cmd", join( "\n", $response ) );
if ( ! defined( 'GIT_KEY_FILE' ) && isset( $env['GIT_KEY_FILE'] ) ) {
unlink( $env['GIT_KEY_FILE'] );
}
if ( 0 != $return ) {
$this->last_error = join( "\n", $response );
} else {
$this->last_error = null;
}
return array( $return, $response );
}
function get_last_error() {
return $this->last_error;
}
function can_exec_git() {
list( $return, ) = $this->_call( 'version' );
return ( 0 == $return );
}
function is_status_working() {
list( $return, ) = $this->_call( 'status', '-s' );
return ( 0 == $return );
}
function get_version() {
list( $return, $version ) = $this->_call( 'version' );
if ( 0 != $return ) { return ''; }
if ( ! empty( $version[0] ) ) {
return substr( $version[0], 12 );
}
return '';
}
// git rev-list @{u}..
function get_ahead_commits() {
list( , $commits ) = $this->_call( 'rev-list', '@{u}..' );
return $commits;
}
// git rev-list ..@{u}
function get_behind_commits() {
list( , $commits ) = $this->_call( 'rev-list', '..@{u}' );
return $commits;
}
function init() {
file_put_contents( "$this->repo_dir/.gitignore", $this->gitignore );
list( $return, ) = $this->_call( 'init' );
$this->_call( 'config', 'user.email', 'gitium@presslabs.com' );
$this->_call( 'config', 'user.name', 'Gitium' );
$this->_call( 'config', 'push.default', 'matching' );
return ( 0 == $return );
}
function is_dot_git_dir( $dir ) {
$realpath = realpath( $dir );
$git_config = realpath( $realpath . '/config' );
$git_index = realpath( $realpath . '/index' );
if ( ! empty( $realpath ) && is_dir( $realpath ) && file_exists( $git_config ) && file_exists( $git_index ) ) {
return True;
}
return False;
}
function cleanup() {
$dot_git_dir = realpath( $this->repo_dir . '/.git' );
if ( $this->is_dot_git_dir( $dot_git_dir ) && $this->_rrmdir( $dot_git_dir ) ) {
if ( WP_DEBUG ) {
error_log( "Gitium cleanup successfull. Removed '$dot_git_dir'." );
}
return True;
}
if ( WP_DEBUG ) {
error_log( "Gitium cleanup failed. '$dot_git_dir' is not a .git dir." );
}
return False;
}
function add_remote_url( $url ) {
list( $return, ) = $this->_call( 'remote', 'add', 'origin', $url );
return ( 0 == $return );
}
function get_remote_url() {
list( , $response ) = $this->_call( 'config', '--get', 'remote.origin.url' );
if ( isset( $response[0] ) ) {
return $response[0];
}
return '';
}
function remove_remote() {
list( $return, ) = $this->_call( 'remote', 'rm', 'origin');
return ( 0 == $return );
}
function get_remote_tracking_branch() {
list( $return, $response ) = $this->_call( 'rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{u}' );
if ( 0 == $return ) {
return $response[0];
}
return false;
}
function get_local_branch() {
list( $return, $response ) = $this->_call( 'rev-parse', '--abbrev-ref', 'HEAD' );
if ( 0 == $return ) {
return $response[0];
}
return false;
}
function fetch_ref() {
list( $return, ) = $this->_call( 'fetch', 'origin' );
return ( 0 == $return );
}
protected function _resolve_merge_conflicts( $message ) {
list( , $changes ) = $this->status( true );
$this->_log( $changes );
foreach ( $changes as $path => $change ) {
if ( in_array( $change, array( 'UD', 'DD' ) ) ) {
$this->_call( 'rm', $path );
$message .= "\n\tConflict: $path [removed]";
} elseif ( 'DU' == $change ) {
$this->_call( 'add', $path );
$message .= "\n\tConflict: $path [added]";
} elseif ( in_array( $change, array( 'AA', 'UU', 'AU', 'UA' ) ) ) {
$this->_call( 'checkout', '--theirs', $path );
$this->_call( 'add', '--all', $path );
$message .= "\n\tConflict: $path [local version]";
}
}
$this->commit( $message );
}
function get_commit_message( $commit ) {
list( $return, $response ) = $this->_call( 'log', '--format=%B', '-n', '1', $commit );
return ( $return !== 0 ? false : join( "\n", $response ) );
}
private function strpos_haystack_array( $haystack, $needle, $offset=0 ) {
if ( ! is_array( $haystack ) ) { $haystack = array( $haystack ); }
foreach ( $haystack as $query ) {
if ( strpos( $query, $needle, $offset) !== false ) { return true; }
}
return false;
}
private function cherry_pick( $commits ) {
foreach ( $commits as $commit ) {
if ( empty( $commit ) ) { return false; }
list( $return, $response ) = $this->_call( 'cherry-pick', $commit );
// abort the cherry-pick if the changes are already pushed
if ( false !== $this->strpos_haystack_array( $response, 'previous cherry-pick is now empty' ) ) {
$this->_call( 'cherry-pick', '--abort' );
continue;
}
if ( $return != 0 ) {
$this->_resolve_merge_conflicts( $this->get_commit_message( $commit ) );
}
}
}
function merge_with_accept_mine(...$commits) {
do_action( 'gitium_before_merge_with_accept_mine' );
if ( 1 == count($commits) && is_array( $commits[0] ) ) {
$commits = $commits[0];
}
// get ahead commits
$ahead_commits = $this->get_ahead_commits();
// combine all commits with the ahead commits
$commits = array_unique( array_merge( array_reverse( $commits ), $ahead_commits ) );
$commits = array_reverse( $commits );
// get the remote branch
$remote_branch = $this->get_remote_tracking_branch();
// get the local branch
$local_branch = $this->get_local_branch();
// rename the local branch to 'merge_local'
$this->_call( 'branch', '-m', 'merge_local' );
// local branch set up to track remote branch
$this->_call( 'branch', $local_branch, $remote_branch );
// checkout to the $local_branch
list( $return, ) = $this->_call( 'checkout', $local_branch );
if ( $return != 0 ) {
$this->_call( 'branch', '-M', $local_branch );
return false;
}
// don't cherry pick if there are no commits
if ( count( $commits ) > 0 ) {
$this->cherry_pick( $commits );
}
if ( $this->successfully_merged() ) { // git status without states: AA, DD, UA, AU ...
// delete the 'merge_local' branch
$this->_call( 'branch', '-D', 'merge_local' );
return true;
} else {
$this->_call( 'cherry-pick', '--abort' );
$this->_call( 'checkout', '-b', 'merge_local' );
$this->_call( 'branch', '-M', $local_branch );
return false;
}
}
function successfully_merged() {
list( , $response ) = $this->status( true );
$changes = array_values( $response );
return ( 0 == count( array_intersect( $changes, array( 'DD', 'AU', 'UD', 'UA', 'DU', 'AA', 'UU' ) ) ) );
}
function merge_initial_commit( $commit, $branch ) {
list( $return, ) = $this->_call( 'branch', '-m', 'initial' );
if ( 0 != $return ) {
return false;
}
list( $return, ) = $this->_call( 'checkout', $branch );
if ( 0 != $return ) {
return false;
}
list( $return, ) = $this->_call(
'cherry-pick', '--strategy', 'recursive', '--strategy-option', 'theirs', $commit
);
if ( $return != 0 ) {
$this->_resolve_merge_conflicts( $this->get_commit_message( $commit ) );
if ( ! $this->successfully_merged() ) {
$this->_call( 'cherry-pick', '--abort' );
$this->_call( 'checkout', 'initial' );
return false;
}
}
$this->_call( 'branch', '-D', 'initial' );
return true;
}
function get_remote_branches() {
list( , $response ) = $this->_call( 'branch', '-r' );
$response = array_map( 'trim', $response );
$response = array_map( create_function( '$b', 'return str_replace("origin/","",$b);' ), $response );
return $response;
}
function add(...$args) {
if ( 1 == count($args) && is_array( $args[0] ) ) {
$args = $args[0];
}
$params = array_merge( array( 'add', '-n', '--all' ), $args );
list ( , $response ) = call_user_func_array( array( $this, '_call' ), $params );
$count = count( $response );
$params = array_merge( array( 'add', '--all' ), $args );
list ( , $response ) = call_user_func_array( array( $this, '_call' ), $params );
return $count;
}
function commit( $message, $author_name = '', $author_email = '' ) {
$author = '';
if ( $author_email ) {
if ( empty( $author_name ) ) {
$author_name = $author_email;
}
$author = "$author_name <$author_email>";
}
if ( ! empty( $author ) ) {
list( $return, $response ) = $this->_call( 'commit', '-m', $message, '--author', $author );
} else {
list( $return, $response ) = $this->_call( 'commit', '-m', $message );
}
if ( $return !== 0 ) { return false; }
list( $return, $response ) = $this->_call( 'rev-parse', 'HEAD' );
return ( $return === 0 ) ? $response[0] : false;
}
function push( $branch = '' ) {
if ( ! empty( $branch ) ) {
list( $return, ) = $this->_call( 'push', '--porcelain', '-u', 'origin', $branch );
} else {
list( $return, ) = $this->_call( 'push', '--porcelain', '-u', 'origin', 'HEAD' );
}
return ( $return == 0 );
}
/*
* Get uncommited changes with status porcelain
* git status --porcelain
* It returns an array like this:
array(
file => deleted|modified
...
)
*/
function get_local_changes() {
list( $return, $response ) = $this->_call( 'status', '--porcelain' );
if ( 0 !== $return ) {
return array();
}
$new_response = array();
if ( ! empty( $response ) ) {
foreach ( $response as $line ) :
$work_tree_status = substr( $line, 1, 1 );
$path = substr( $line, 3 );
if ( ( '"' == $path[0] ) && ('"' == $path[strlen( $path ) - 1] ) ) {
// git status --porcelain will put quotes around paths with whitespaces
// we don't want the quotes, let's get rid of them
$path = substr( $path, 1, strlen( $path ) - 2 );
}
if ( 'D' == $work_tree_status ) {
$action = 'deleted';
} else {
$action = 'modified';
}
$new_response[ $path ] = $action;
endforeach;
}
return $new_response;
}
function get_uncommited_changes() {
list( , $changes ) = $this->status();
return $changes;
}
function local_status() {
list( $return, $response ) = $this->_call( 'status', '-s', '-b', '-u' );
if ( 0 !== $return ) {
return array( '', array() );
}
$new_response = array();
if ( ! empty( $response ) ) {
$branch_status = array_shift( $response );
foreach ( $response as $idx => $line ) :
unset( $index_status, $work_tree_status, $path, $new_path, $old_path );
if ( empty( $line ) ) { continue; } // ignore empty lines like the last item
if ( '#' == $line[0] ) { continue; } // ignore branch status
$index_status = substr( $line, 0, 1 );
$work_tree_status = substr( $line, 1, 1 );
$path = substr( $line, 3 );
$old_path = '';
$new_path = explode( '->', $path );
if ( ( 'R' === $index_status ) && ( ! empty( $new_path[1] ) ) ) {
$old_path = trim( $new_path[0] );
$path = trim( $new_path[1] );
}
$new_response[ $path ] = trim( $index_status . $work_tree_status . ' ' . $old_path );
endforeach;
}
return array( $branch_status, $new_response );
}
function status( $local_only = false ) {
list( $branch_status, $new_response ) = $this->local_status();
if ( $local_only ) { return array( $branch_status, $new_response ); }
$behind_count = 0;
$ahead_count = 0;
if ( preg_match( '/## ([^.]+)\.+([^ ]+)/', $branch_status, $matches ) ) {
$local_branch = $matches[1];
$remote_branch = $matches[2];
list( , $response ) = $this->_call( 'rev-list', "$local_branch..$remote_branch", '--count' );
$behind_count = (int)$response[0];
list( , $response ) = $this->_call( 'rev-list', "$remote_branch..$local_branch", '--count' );
$ahead_count = (int)$response[0];
}
if ( $behind_count ) {
list( , $response ) = $this->_call( 'diff', '-z', '--name-status', "$local_branch~$ahead_count", $remote_branch );
$response = explode( chr( 0 ), $response[0] );
array_pop( $response );
for ( $idx = 0 ; $idx < count( $response ) / 2 ; $idx++ ) {
$file = $response[ $idx * 2 + 1 ];
$change = $response[ $idx * 2 ];
if ( ! isset( $new_response[ $file ] ) ) {
$new_response[ $file ] = "r$change";
}
}
}
return array( $branch_status, $new_response );
}
/*
* Checks if repo has uncommited changes
* git status --porcelain
*/
function is_dirty() {
$changes = $this->get_uncommited_changes();
return ! empty( $changes );
}
/**
* Return the last n commits
*/
function get_last_commits( $n = 20 ) {
list( $return, $message ) = $this->_call( 'log', '-n', $n, '--pretty=format:%s' );
if ( 0 !== $return ) { return false; }
list( $return, $response ) = $this->_call( 'log', '-n', $n, '--pretty=format:%h|%an|%ae|%ad|%cn|%ce|%cd' );
if ( 0 !== $return ) { return false; }
foreach ( $response as $index => $value ) {
$commit_info = explode( '|', $value );
$commits[ $commit_info[0] ] = array(
'subject' => $message[ $index ],
'author_name' => $commit_info[1],
'author_email' => $commit_info[2],
'author_date' => $commit_info[3],
);
if ( $commit_info[1] != $commit_info[4] && $commit_info[2] != $commit_info[5] ) {
$commits[ $commit_info[0] ]['committer_name'] = $commit_info[4];
$commits[ $commit_info[0] ]['committer_email'] = $commit_info[5];
$commits[ $commit_info[0] ]['committer_date'] = $commit_info[6];
}
}
return $commits;
}
public function set_gitignore( $content ) {
file_put_contents( $this->repo_dir . '/.gitignore', $content );
return true;
}
public function get_gitignore() {
return file_get_contents( $this->repo_dir . '/.gitignore' );
}
/**
* Remove files in .gitignore from version control
*/
function rm_cached( $path ) {
list( $return, ) = $this->_call( 'rm', '--cached', $path );
return ( $return == 0 );
}
function remove_wp_content_from_version_control() {
$process = proc_open(
'rm -rf ' . ABSPATH . '/wp-content/.git',
array(
0 => array( 'pipe', 'r' ), // stdin
1 => array( 'pipe', 'w' ), // stdout
),
$pipes
);
if ( is_resource( $process ) ) {
fclose( $pipes[0] );
proc_close( $process );
return true;
}
return false;
}
}
if ( ! defined( 'GIT_DIR' ) ) {
define( 'GIT_DIR', dirname( WP_CONTENT_DIR ) );
}
# global is needed here for wp-cli as it includes/exec files inside a function scope
# this forces the context to really be global :\.
global $git;
$git = new Git_Wrapper( GIT_DIR );

View File

@ -0,0 +1,53 @@
<?php
/* Copyright 2014-2016 Presslabs SRL <ping@presslabs.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
class Gitium_Admin {
public function __construct() {
global $git;
list( , $git_private_key ) = gitium_get_keypair();
$git->set_key( $git_private_key );
if ( current_user_can( GITIUM_MANAGE_OPTIONS_CAPABILITY ) ) {
$req = new Gitium_Requirements();
if ( ! $req->get_status() ) {
return false;
}
if ( $this->has_configuration() ) {
new Gitium_Submenu_Status();
new Gitium_Submenu_Commits();
new Gitium_Submenu_Settings();
new Gitium_Menu_Bubble();
} else {
new Gitium_Submenu_Configure();
}
}
}
public function has_configuration() {
return _gitium_is_status_working() && _gitium_get_remote_tracking_branch();
}
}
if ( ( is_admin() && ! is_multisite() ) || ( is_network_admin() && is_multisite() ) ) {
add_action( 'init', 'gitium_admin_page' );
function gitium_admin_page() {
new Gitium_Admin();
}
}

View File

@ -0,0 +1,107 @@
<?php
/* Copyright 2014-2016 Presslabs SRL <ping@presslabs.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
class Gitium_Help {
public function __construct( $hook, $help = 'gitium' ) {
add_action( "load-{$hook}", array( $this, $help ), 20 );
}
private function general() {
$screen = get_current_screen();
$screen->add_help_tab( array( 'id' => 'gitium', 'title' => __( 'Gitium', 'gitium' ), 'callback' => array( $this, 'gitium' ) ) );
$screen->add_help_tab( array( 'id' => 'faq', 'title' => __( 'F.A.Q.', 'gitium' ), 'callback' => array( $this, 'faq' ) ) );
$screen->add_help_tab( array( 'id' => 'requirements', 'title' => __( 'Requirements', 'gitium' ), 'callback' => array( $this, 'requirements_callback' ) ) );
$screen->set_help_sidebar( '<div style="width:auto; height:auto; float:right; padding-right:28px; padding-top:15px"><img src="' . plugins_url( 'img/gitium.svg', dirname( __FILE__ ) ) . '" width="96"></div>' );
}
public function gitium() {
echo '<p>' . __( 'Gitium enables continuous deployment for WordPress integrating with tools such as Github, Bitbucket or Travis-CI. Plugin and theme updates, installs and removals are automatically versioned.', 'gitium' ) . '</p>';
echo '<p>' . __( 'Ninja code edits from the WordPress editor are also tracked into version control. Gitium is designed for sane development environments.', 'gitium' ) . '</p>';
echo '<p>' . __( 'Staging and production can follow different branches of the same repository. You can deploy code simply trough git push.', 'gitium' ) . '</p>';
echo '<p>' . __( 'Gitium requires <code>git</code> command line tool minimum version 1.7 installed on the server and <code>proc_open</code> PHP function enabled.', 'gitium' ) . '</p>';
}
public function faq() {
echo '<p><strong>' . __( 'Could not connect to remote repository?', 'gitium' ) . '</strong><br />'. __( 'If you encounter this kind of error you can try to fix it by setting the proper username of the .git directory.', 'gitium' ) . '<br />' . __( 'Example', 'gitium' ) .': <code>chown -R www-data:www-data .git</code></p>';
echo '<p><strong>' . __( 'Is this plugin considered stable?', 'gitium' ) . '</strong><br />'. __( 'Right now this plugin is considered alpha quality and should be used in production environments only by adventurous kinds.', 'gitium' ) . '</p>';
echo '<p><strong>' . __( 'What happens in case of conflicts?', 'gitium' ) . '</strong><br />'. __( 'The behavior in case of conflicts is to overwrite the changes on the origin repository with the local changes (ie. local modifications take precedence over remote ones).', 'gitium' ) . '</p>';
echo '<p><strong>' . __( 'How to deploy automatically after a push?', 'gitium' ) . '</strong><br />'. __( 'You can ping the webhook url after a push to automatically deploy the new code. The webhook url can be found under Code menu. This url plays well with Github or Bitbucket webhooks.', 'gitium' ) . '</p>';
echo '<p><strong>' . __( 'Does it works on multi site setups?', 'gitium' ) . '</strong><br />'. __( 'Gitium is not supporting multisite setups at the moment.', 'gitium' ) . '</p>';
echo '<p><strong>' . __( 'How does gitium handle submodules?', 'gitium' ) . '</strong><br />'. __( 'Currently submodules are not supported.', 'gitium' ) . '</p>';
}
public function requirements_callback() {
echo '<p>' . __( 'Gitium requires:', 'gitium' ) . '</p>';
echo '<p>' . __( 'the function proc_open available', 'gitium' ) . '</p>';
echo '<p>' . __( 'can exec the file inc/ssh-git', 'gitium' ) . '</p>';
printf( '<p>' . __( 'git version >= %s', 'gitium' ) . '</p>', GITIUM_MIN_GIT_VER );
printf( '<p>' . __( 'PHP version >= %s', 'gitium' ) . '</p>', GITIUM_MIN_PHP_VER );
}
public function configuration() {
$screen = get_current_screen();
$screen->add_help_tab( array( 'id' => 'configuration', 'title' => __( 'Configuration', 'gitium' ), 'callback' => array( $this, 'configuration_callback' ) ) );
$this->general();
}
public function configuration_callback() {
echo '<p><strong>' . __( 'Configuration step 1', 'gitium' ) . '</strong><br />' . __( 'In this step you must specify the <code>Remote URL</code>. This URL represents the link between the git sistem and your site.', 'gitium' ) . '</p>';
echo '<p>' . __( 'You can get this URL from your Git repository and it looks like this:', 'gitium' ) . '</p>';
echo '<p>' . __( 'github.com -> git@github.com:user/example.git', 'gitium' ) . '</p>';
echo '<p>' . __( 'bitbucket.org -> git@bitbucket.org:user/glowing-happiness.git', 'gitium' ) . '</p>';
echo '<p>' . __( 'To go to the next step, fill the <code>Remote URL</code> and then press the <code>Fetch</code> button.', 'gitium' ) . '</p>';
echo '<p><strong>' . __( 'Configuration step 2', 'gitium' ) . '</strong><br />' . __( 'In this step you must select the <code>branch</code> you want to follow.', 'gitium' ) . '</p>';
echo '<p>' . __( 'Only this branch will have all of your code modifications.', 'gitium' ) . '</p>';
echo '<p>' . __( 'When you push the button <code>Merge & Push</code>, all code(plugins & themes) will be pushed on the git repository.', 'gitium' ) . '</p>';
}
public function status() {
$screen = get_current_screen();
$screen->add_help_tab( array( 'id' => 'status', 'title' => __( 'Status', 'gitium' ), 'callback' => array( $this, 'status_callback' ) ) );
$this->general();
}
public function status_callback() {
echo '<p>' . __( 'On status page you can see what files are modified, and you can commit the changes to git.', 'gitium' ) . '</p>';
}
public function commits() {
$screen = get_current_screen();
$screen->add_help_tab( array( 'id' => 'commits', 'title' => __( 'Commits', 'gitium' ), 'callback' => array( $this, 'commits_callback' ) ) );
$this->general();
}
public function commits_callback() {
echo '<p>' . __( 'You may be wondering what is the difference between author and committer.', 'gitium' ) . '</p>';
echo '<p>' . __( 'The <code>author</code> is the person who originally wrote the patch, whereas the <code>committer</code> is the person who last applied the patch.', 'gitium' ) . '</p>';
echo '<p>' . __( 'So, if you send in a patch to a project and one of the core members applies the patch, both of you get credit — you as the author and the core member as the committer.', 'gitium' ) . '</p>';
}
public function settings() {
$screen = get_current_screen();
$screen->add_help_tab( array( 'id' => 'settings', 'title' => __( 'Settings', 'gitium' ), 'callback' => array( $this, 'settings_callback' ) ) );
$this->general();
}
public function settings_callback() {
echo '<p>' . __( 'Each line from the gitignore file specifies a pattern.', 'gitium' ) . '</p>';
echo '<p>' . __( 'When deciding whether to ignore a path, Git normally checks gitignore patterns from multiple sources, with the following order of precedence, from highest to lowest (within one level of precedence, the last matching pattern decides the outcome)', 'gitium' ) . '</p>';
echo '<p>' . sprintf( __( 'Read more on %s', 'gitium' ), '<a href="http://git-scm.com/docs/gitignore" target="_blank">git documentation</a>' ) . '</p>';
}
}

View File

@ -0,0 +1,55 @@
<?php
/* Copyright 2014-2016 Presslabs SRL <ping@presslabs.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
class Gitium_Menu_Bubble extends Gitium_Menu {
public function __construct() {
parent::__construct( $this->gitium_menu_slug, $this->gitium_menu_slug );
add_action( GITIUM_ADMIN_MENU_ACTION, array( $this, 'add_menu_bubble' ) );
}
public function add_menu_bubble() {
global $menu;
if ( ! _gitium_is_status_working() ) {
foreach ( $menu as $key => $value ) {
if ( $this->menu_slug == $menu[ $key ][2] ) {
$menu_bubble = get_transient( 'gitium_menu_bubble' );
if ( false === $menu_bubble ) { $menu_bubble = ''; }
$menu[ $key ][0] = str_replace( $menu_bubble, '', $menu[ $key ][0] );
delete_transient( 'gitium_menu_bubble' );
return;
}
}
}
list( , $changes ) = _gitium_status();
if ( ! empty( $changes ) ) :
$bubble_count = count( $changes );
foreach ( $menu as $key => $value ) {
if ( $this->menu_slug == $menu[ $key ][2] ) {
$menu_bubble = " <span class='update-plugins count-$bubble_count'><span class='plugin-count'>"
. $bubble_count . '</span></span>';
$menu[ $key ][0] .= $menu_bubble;
set_transient( 'gitium_menu_bubble', $menu_bubble );
return;
}
}
endif;
}
}

View File

@ -0,0 +1,97 @@
<?php
/* Copyright 2014-2016 Presslabs SRL <ping@presslabs.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
class Gitium_Menu {
public $gitium_menu_slug = 'gitium/gitium.php';
public $commits_menu_slug = 'gitium/gitium-commits.php';
public $settings_menu_slug = 'gitium/gitium-settings.php';
public $git = null;
public $menu_slug;
public $submenu_slug;
public function __construct( $menu_slug, $submenu_slug ) {
global $git;
$this->git = $git;
$this->menu_slug = $menu_slug;
$this->submenu_slug = $submenu_slug;
}
public function redirect( $message = '', $success = false, $menu_slug = '' ) {
$message_id = substr(
md5( str_shuffle( 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' ) . time() ), 0, 8
);
if ( $message ) {
set_transient( 'message_' . $message_id, $message, 900 );
}
if ( '' === $menu_slug ) { $menu_slug = $this->menu_slug; }
$url = network_admin_url( 'admin.php?page=' . $menu_slug );
$url = esc_url_raw( add_query_arg(
array(
'message' => $message_id,
'success' => $success,
),
$url
) );
wp_safe_redirect( $url );
exit;
}
public function success_redirect( $message = '', $menu_slug = '' ) {
$this->redirect( $message, true, $menu_slug );
}
public function disconnect_repository() {
$gitium_disconnect_repo = filter_input(INPUT_POST, 'GitiumSubmitDisconnectRepository', FILTER_SANITIZE_STRING);
if ( ! isset( $gitium_disconnect_repo ) ) {
return;
}
check_admin_referer( 'gitium-admin' );
gitium_uninstall_hook();
if ( ! $this->git->remove_remote() ) {
$this->redirect( __('Could not remove remote.', 'gitium') );
}
$this->success_redirect( __('You are now disconnected from the repository. New key pair generated.', 'gitium') );
}
public function show_message() {
$get_message = filter_input(INPUT_GET, 'message', FILTER_SANITIZE_STRING);
$get_success = filter_input(INPUT_GET, 'success', FILTER_SANITIZE_STRING);
if ( isset( $get_message ) && $get_message ) {
$type = ( isset( $get_success ) && $get_success == 1 ) ? 'updated' : 'error';
$message = get_transient( 'message_'. $get_message );
if ( $message ) : ?>
<div class="<?php echo esc_attr( $type ); ?>"><p><?php echo esc_html( $message ); ?></p></div>
<?php endif;
}
}
protected function show_disconnect_repository_button() {
?>
<form name="gitium_form_disconnect" id="gitium_form_disconnect" action="" method="POST">
<?php
wp_nonce_field( 'gitium-admin' );
?>
<input type="submit" name="GitiumSubmitDisconnectRepository" value='<?php _e( 'Disconnect from repo', 'gitium' ); ?>' class="button secondary" onclick="return confirm('<?php _e( 'Are you sure you want to disconnect from the remote repository?', 'gitium' ); ?>')"/>&nbsp;
</form>
<?php
}
}

View File

@ -0,0 +1,117 @@
<?php
/* Copyright 2014-2016 Presslabs SRL <ping@presslabs.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
class Gitium_Requirements {
private $req = array();
private $msg = array();
/**
* Gitium requires:
* git min version
* the function proc_open available
* PHP min version
* can exec the file inc/ssh-git
*/
public function __construct() {
$this->_check_req();
add_action( GITIUM_ADMIN_NOTICES_ACTION, array( $this, 'admin_notices' ) );
}
private function _check_req() {
list($this->req['is_git_version'], $this->msg['is_git_version'] ) = $this->is_git_version();
list($this->req['is_proc_open'], $this->msg['is_proc_open'] ) = $this->is_proc_open();
list($this->req['is_php_verion'], $this->msg['is_php_verion'] ) = $this->is_php_version();
list($this->req['can_exec_ssh_git_file'],$this->msg['can_exec_ssh_git_file']) = $this->can_exec_ssh_git_file();
return $this->req;
}
public function admin_notices() {
if ( ! current_user_can( GITIUM_MANAGE_OPTIONS_CAPABILITY ) ) {
return;
}
foreach ( $this->req as $key => $value ) {
if ( false === $value ) {
echo "<div class='error-nag error'><p>Gitium Requirement: {$this->msg[$key]}</p></div>";
}
}
}
public function get_status() {
$requirements = $this->req;
foreach ( $requirements as $req ) :
if ( false === $req ) :
return false;
endif;
endforeach;
return true;
}
private function is_git_version() {
$git_version = get_transient( 'gitium_git_version' );
if ( GITIUM_MIN_GIT_VER > substr( $git_version, 0, 3 ) ) {
global $git;
$git_version = $git->get_version();
set_transient( 'gitium_git_version', $git_version );
if ( empty( $git_version ) ) {
return array( false, 'There is no git installed on this server.' );
} else if ( GITIUM_MIN_GIT_VER > substr( $git_version, 0, 3 ) ) {
return array( false, "The git version is `$git_version` and must be greater than `" . GITIUM_MIN_GIT_VER . "`!" );
}
}
return array( true, "The git version is `$git_version`." );
}
private function is_proc_open() {
if ( ! function_exists( 'proc_open' ) ) {
return array( false, 'The function `proc_open` is disabled!' );
} else {
return array( true, 'The function `proc_open` is enabled!' );
}
}
private function is_php_version() {
if ( ! function_exists( 'phpversion' ) ) {
return array( false, 'The function `phpversion` is disabled!' );
} else {
$php_version = phpversion();
if ( GITIUM_MIN_PHP_VER <= substr( $php_version, 0, 3 ) ) {
return array( true, "The PHP version is `$php_version`." );
} else {
return array( false, "The PHP version is `$php_version` and is not greater or equal to " . GITIUM_MIN_PHP_VER );
}
}
}
private function can_exec_ssh_git_file() {
$filepath = dirname( __FILE__ ) . '/ssh-git';
if ( ! function_exists( 'is_executable' ) ) {
return array( false, 'The function `is_executable` is disabled!' );
} else if ( is_executable( $filepath ) ) {
return array( true, "The `$filepath` file can be executed!" );
} else {
return array( false, "The `$filepath` file is not executable" );
}
}
}

View File

@ -0,0 +1,94 @@
<?php
/* Copyright 2014-2016 Presslabs SRL <ping@presslabs.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
class Gitium_Submenu_Commits extends Gitium_Menu {
public function __construct() {
parent::__construct( $this->gitium_menu_slug, $this->commits_menu_slug );
add_action( GITIUM_ADMIN_MENU_ACTION, array( $this, 'admin_menu' ) );
}
public function admin_menu() {
$submenu_hook = add_submenu_page(
$this->menu_slug,
__( 'Git Commits', 'gitium' ),
__( 'Commits', 'gitium' ),
GITIUM_MANAGE_OPTIONS_CAPABILITY,
$this->submenu_slug,
array( $this, 'page' )
);
new Gitium_Help( $submenu_hook, 'commits' );
}
public function table_head() {
?>
<thead>
<tr>
<th scope="col"><?php _e( 'Commits', 'gitium' ); ?></th>
<th scope="col"></th>
</tr>
</thead>
<?php
}
public function table_end_row() {
echo '</tr>';
}
public function table_start_row() {
static $counter = 0;
$counter++;
echo ( 0 != $counter % 2 ) ? '<tr class="active">' : '<tr class="inactive">';
}
public function page() {
?>
<div class="wrap">
<h2><?php printf( __( 'Last %s commits', 'gitium' ), GITIUM_LAST_COMMITS ); ?></h2>
<table class="wp-list-table widefat plugins">
<?php $this->table_head(); ?>
<tbody>
<?php
foreach ( $this->git->get_last_commits( GITIUM_LAST_COMMITS ) as $commit_id => $data ) {
unset( $committer_name );
extract( $data );
if ( isset( $committer_name ) ) {
$committer = "<span title='$committer_email'> -> $committer_name " . sprintf( __( 'committed %s ago', 'gitium' ), human_time_diff( strtotime( $committer_date ) ) ) . '</span>';
$committers_avatar = '<div style="position:absolute; left:30px; border: 1px solid white; background:white; height:17px; top:30px; border-radius:2px">' . get_avatar( $committer_email, 16 ) . '</div>';
} else {
$committer = '';
$committers_avatar = '';
}
$this->table_start_row();
?>
<td style="position:relative">
<div style="float:left; width:auto; height:auto; padding-left:2px; padding-right:5px; padding-top:2px; margin-right:5px; border-radius:2px"><?php echo get_avatar( $author_email, 32 ); ?></div>
<?php echo $committers_avatar; ?>
<div style="float:left; width:auto; height:auto;"><strong><?php echo esc_html( $subject ); ?></strong><br />
<span title="<?php echo esc_attr( $author_email ); ?>"><?php echo esc_html( $author_name ) . ' ' . sprintf( __( 'authored %s ago', 'gitium' ), human_time_diff( strtotime( $author_date ) ) ); ?></span><?php echo $committer; ?></div>
</td>
<td><p style="padding-top:8px"><?php echo $commit_id; ?></p></td>
<?php
$this->table_end_row();
}
?>
</tbody>
</table>
</div>
<?php
}
}

View File

@ -0,0 +1,253 @@
<?php
/* Copyright 2014-2016 Presslabs SRL <ping@presslabs.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
class Gitium_Submenu_Configure extends Gitium_Menu {
public function __construct() {
parent::__construct( $this->gitium_menu_slug, $this->gitium_menu_slug );
if ( current_user_can( GITIUM_MANAGE_OPTIONS_CAPABILITY ) ) {
add_action( GITIUM_ADMIN_MENU_ACTION, array( $this, 'admin_menu' ) );
add_action( 'admin_init', array( $this, 'regenerate_keypair' ) );
add_action( 'admin_init', array( $this, 'gitium_warning' ) );
add_action( 'admin_init', array( $this, 'init_repo' ) );
add_action( 'admin_init', array( $this, 'choose_branch' ) );
add_action( 'admin_init', array( $this, 'disconnect_repository' ) );
}
}
public function admin_menu() {
add_menu_page(
__( 'Git Configuration', 'gitium' ),
'Gitium',
GITIUM_MANAGE_OPTIONS_CAPABILITY,
$this->menu_slug,
array( $this, 'page' ),
plugins_url( 'img/gitium.png', dirname( __FILE__ ) )
);
$submenu_hook = add_submenu_page(
$this->menu_slug,
__( 'Git Configuration', 'gitium' ),
__( 'Configuration', 'gitium' ),
GITIUM_MANAGE_OPTIONS_CAPABILITY,
$this->menu_slug,
array( $this, 'page' )
);
new Gitium_Help( $submenu_hook, 'configuration' );
}
public function regenerate_keypair() {
$submit_keypair = filter_input(INPUT_POST, 'GitiumSubmitRegenerateKeypair', FILTER_SANITIZE_STRING);
if ( ! isset( $submit_keypair ) ) {
return;
}
check_admin_referer( 'gitium-admin' );
gitium_get_keypair( true );
$this->success_redirect( __( 'Keypair successfully regenerated.', 'gitium' ) );
}
public function gitium_warning() {
$submit_warning = filter_input(INPUT_POST, 'GitiumSubmitWarning', FILTER_SANITIZE_STRING);
if ( ! isset( $submit_warning ) ) {
return;
}
check_admin_referer( 'gitium-admin' );
$this->git->remove_wp_content_from_version_control();
}
public function init_process( $remote_url ) {
$git = $this->git;
$git->init();
$git->add_remote_url( $remote_url );
$git->fetch_ref();
if ( count( $git->get_remote_branches() ) == 0 ) {
$git->add( 'wp-content', '.gitignore' );
$current_user = wp_get_current_user();
$git->commit( __( 'Initial commit', 'gitium' ), $current_user->display_name, $current_user->user_email );
if ( ! $git->push( 'master' ) ) {
$git->cleanup();
return false;
}
}
return true;
}
public function init_repo() {
$remote_url = filter_input(INPUT_POST, 'remote_url', FILTER_SANITIZE_STRING);
$gitium_submit_fetch = filter_input(INPUT_POST, 'GitiumSubmitFetch', FILTER_SANITIZE_STRING);
if ( ! isset( $gitium_submit_fetch ) || ! isset( $remote_url ) ) {
return;
}
check_admin_referer( 'gitium-admin' );
if ( empty( $remote_url ) ) {
$this->redirect( __( 'Please specify a valid repo.', 'gitium' ) );
}
if ( $this->init_process( $remote_url ) ) {
$this->success_redirect( __( 'Repository initialized successfully.', 'gitium' ) );
} else {
global $git;
$this->redirect( __( 'Could not push to remote: ', 'gitium' ) . $remote_url . ' ERROR: ' . serialize( $git->get_last_error() ) );
}
}
public function choose_branch() {
$gitium_submit_merge_push = filter_input(INPUT_POST, 'GitiumSubmitMergeAndPush', FILTER_SANITIZE_STRING);
$tracking_branch = filter_input(INPUT_POST, 'tracking_branch', FILTER_SANITIZE_STRING);
if ( ! isset( $gitium_submit_merge_push ) || ! isset( $tracking_branch ) ) {
return;
}
check_admin_referer( 'gitium-admin' );
$this->git->add();
$branch = $tracking_branch;
set_transient( 'gitium_remote_tracking_branch', $branch );
$current_user = wp_get_current_user();
$commit = $this->git->commit( __( 'Merged existing code from ', 'gitium' ) . get_home_url(), $current_user->display_name, $current_user->user_email );
if ( ! $commit ) {
$this->git->cleanup();
$this->redirect( __( 'Could not create initial commit -> ', 'gitium' ) . $this->git->get_last_error() );
}
if ( ! $this->git->merge_initial_commit( $commit, $branch ) ) {
$this->git->cleanup();
$this->redirect( __( 'Could not merge the initial commit -> ', 'gitium' ) . $this->git->get_last_error() );
}
$this->git->push( $branch );
$this->success_redirect( __( 'Branch selected successfully.', 'gitium' ) );
}
private function setup_step_1_remote_url() {
?>
<tr>
<th scope="row"><label for="remote_url"><?php _e( 'Remote URL', 'gitium' ); ?></label></th>
<td>
<input type="text" class="regular-text" name="remote_url" id="remote_url" placeholder="git@github.com:user/example.git" value="">
<p class="description"><?php _e( 'This URL provide access to a Git repository via SSH, HTTPS, or Subversion.', 'gitium' ); ?><br />
<?php _e( 'If you need to authenticate over "https://" instead of SSH use: <code>https://user:pass@github.com/user/example.git</code>', 'gitium' ); ?></p>
</td>
</tr>
<?php
}
private function setup_step_1_key_pair() {
if ( ! defined( 'GIT_KEY_FILE' ) || GIT_KEY_FILE == '' ) :
list( $git_public_key, ) = gitium_get_keypair(); ?>
<tr>
<th scope="row"><label for="key_pair"><?php _e( 'Key pair', 'gitium' ); ?></label></th>
<td>
<p>
<input type="text" class="regular-text" name="key_pair" id="key_pair" value="<?php echo esc_attr( $git_public_key ); ?>" readonly="readonly">
<input type="submit" name="GitiumSubmitRegenerateKeypair" class="button" value="<?php _e( 'Regenerate Key', 'gitium' ); ?>" />
</p>
<p class="description"><?php _e( 'If your code use ssh keybased authentication for git you need to allow write access to your repository using this key.', 'gitium' ); ?><br />
<?php _e( 'Checkout instructions for <a href="https://help.github.com/articles/generating-ssh-keys#step-3-add-your-ssh-key-to-github" target="_blank">github</a> or <a href="https://confluence.atlassian.com/display/BITBUCKET/Add+an+SSH+key+to+an+account#AddanSSHkeytoanaccount-HowtoaddakeyusingSSHforOSXorLinux" target="_blank">bitbucket</a>.', 'gitium' ); ?>
</p>
</td>
</tr>
<?php endif;
}
private function setup_warning() {
?>
<div class="wrap">
<h2><?php _e( 'Warning!', 'gitium' ); ?></h2>
<form name="gitium_form_warning" id="gitium_form_warning" action="" method="POST">
<?php wp_nonce_field( 'gitium-admin' ); ?>
<p><code>wp-content</code> is already under version control. You <a onclick="document.getElementById('gitium_form_warning').submit();" style="color:red;" href="#">must remove it from version control</a> in order to continue.</p>
<p><strong>NOTE</strong> by doing this you WILL LOSE commit history, but NOT the actual files.</p>
<input type="hidden" name="GitiumSubmitWarning" class="button-primary" value="1" />
</form>
</div>
<?php
}
private function setup_step_1() {
?>
<div class="wrap">
<h2><?php _e( 'Configuration step 1', 'gitium' ); ?></h2>
<p><?php _e( 'If you need help to set this up, please click on the "Help" button from the top right corner of this screen.' ); ?></p>
<form action="" method="POST">
<?php wp_nonce_field( 'gitium-admin' ); ?>
<table class="form-table">
<?php $this->setup_step_1_remote_url(); ?>
<?php $this->setup_step_1_key_pair(); ?>
</table>
<p class="submit">
<input type="submit" name="GitiumSubmitFetch" class="button-primary" value="<?php _e( 'Fetch', 'gitium' ); ?>" />
</p>
</form>
</div>
<?php
}
private function setup_step_2() {
$git = $this->git; ?>
<div class="wrap">
<h2><?php _e( 'Configuration step 2', 'gitium' ); ?></h2>
<p><?php _e( 'If you need help to set this up, please click on the "Help" button from the top right corner of this screen.' ); ?></p>
<form action="" method="POST">
<?php wp_nonce_field( 'gitium-admin' ); ?>
<table class="form-table">
<tr>
<th scope="row"><label for="tracking_branch"><?php _e( 'Choose tracking branch', 'gitium' ); ?></label></th>
<td>
<select name="tracking_branch" id="tracking_branch">
<?php foreach ( $git->get_remote_branches() as $branch ) : ?>
<option value="<?php echo esc_attr( $branch ); ?>"><?php echo esc_html( $branch ); ?></option>
<?php endforeach; ?>
</select>
<p class="description"><?php _e( 'Your code origin is set to', 'gitium' ); ?> <code><?php echo esc_html( $git->get_remote_url() ); ?></code></p>
</td>
</tr>
</table>
<p class="submit">
<input type="submit" name="GitiumSubmitMergeAndPush" class="button-primary" value="<?php _e( 'Merge & Push', 'gitium' ); ?>" />
</p>
</form>
<?php
$this->show_disconnect_repository_button();
?>
</div>
<?php
}
public function page() {
$this->show_message();
if ( wp_content_is_versioned() ) {
return $this->setup_warning();
}
if ( ! $this->git->is_status_working() || ! $this->git->get_remote_url() ) {
return $this->setup_step_1();
}
if ( ! $this->git->get_remote_tracking_branch() ) {
return $this->setup_step_2();
}
_gitium_status( true );
gitium_update_is_status_working();
gitium_update_remote_tracking_branch();
}
}

View File

@ -0,0 +1,139 @@
<?php
/* Copyright 2014-2016 Presslabs SRL <ping@presslabs.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
class Gitium_Submenu_Settings extends Gitium_Menu {
public function __construct() {
parent::__construct( $this->gitium_menu_slug, $this->settings_menu_slug );
add_action( GITIUM_ADMIN_MENU_ACTION, array( $this, 'admin_menu' ) );
add_action( 'admin_init', array( $this, 'save' ) );
add_action( 'admin_init', array( $this, 'regenerate_webhook' ) );
add_action( 'admin_init', array( $this, 'regenerate_public_key' ) );
}
public function admin_menu() {
$submenu_hook = add_submenu_page(
$this->menu_slug,
'Settings',
__( 'Settings' ),
GITIUM_MANAGE_OPTIONS_CAPABILITY,
$this->submenu_slug,
array( $this, 'page' )
);
new Gitium_Help( $submenu_hook, 'settings' );
}
public function regenerate_webhook() {
$gitium_regen_webhook = filter_input(INPUT_POST, 'GitiumSubmitRegenerateWebhook', FILTER_SANITIZE_STRING);
if ( ! isset( $gitium_regen_webhook ) ) {
return;
}
check_admin_referer( 'gitium-settings' );
gitium_get_webhook_key( true );
$this->success_redirect( __( 'Webhook URL regenerates. Please make sure you update any external references.', 'gitium' ), $this->settings_menu_slug );
}
public function regenerate_public_key() {
$submit_regenerate_pub_key = filter_input(INPUT_POST, 'GitiumSubmitRegeneratePublicKey', FILTER_SANITIZE_STRING);
if ( ! isset( $submit_regenerate_pub_key ) ) {
return;
}
check_admin_referer( 'gitium-settings' );
gitium_get_keypair( true );
$this->success_redirect( __( 'Public key successfully regenerated.', 'gitium' ), $this->settings_menu_slug );
}
private function show_webhook_table_webhook_url() {
?>
<tr>
<th><label for="webhook-url"><?php _e( 'Webhook URL', 'gitium' ); ?>:</label></th>
<td>
<p><code id="webhook-url"><?php echo esc_url( gitium_get_webhook() ); ?></code>
<?php if ( ! defined( 'GIT_WEBHOOK_URL' ) || GIT_WEBHOOK_URL == '' ) : ?>
<input type="submit" name="GitiumSubmitRegenerateWebhook" class="button" value="<?php _e( 'Regenerate Webhook', 'gitium' ); ?>" />
<a class="button" href="<?php echo esc_url( gitium_get_webhook() ); ?>" target="_blank">Merge changes</a></p>
<?php endif; ?>
<p class="description"><?php _e( 'Pinging this URL triggers an update from remote repository.', 'gitium' ); ?></p>
</td>
</tr>
<?php
}
private function show_webhook_table_public_key() {
list( $git_public_key, ) = gitium_get_keypair();
if ( ! defined( 'GIT_KEY_FILE' ) || GIT_KEY_FILE == '' ) : ?>
<tr>
<th><label for="public-key"><?php _e( 'Public Key', 'gitium' ); ?>:</label></th>
<td>
<p><input type="text" class="regular-text" name="public_key" id="public-key" value="<?php echo esc_attr( $git_public_key ); ?>" readonly="readonly">
<input type="submit" name="GitiumSubmitRegeneratePublicKey" class="button" value="<?php _e( 'Regenerate Key', 'gitium' ); ?>" /></p>
<p class="description"><?php _e( 'If your code use ssh keybased authentication for git you need to allow write access to your repository using this key.', 'gitium' ); ?><br />
<?php _e( 'Checkout instructions for <a href="https://help.github.com/articles/generating-ssh-keys#step-3-add-your-ssh-key-to-github" target="_blank">github</a> or <a href="https://confluence.atlassian.com/display/BITBUCKET/Add+an+SSH+key+to+an+account#AddanSSHkeytoanaccount-HowtoaddakeyusingSSHforOSXorLinux" target="_blank">bitbucket</a>.', 'gitium' ); ?>
</p>
</td>
</tr>
<?php endif;
}
public function show_webhook_table() {
?>
<table class="form-table">
<?php $this->show_webhook_table_webhook_url() ?>
<?php $this->show_webhook_table_public_key(); ?>
</table>
<?php
}
public function save() {
$submit_save = filter_input(INPUT_POST, 'GitiumSubmitSave', FILTER_SANITIZE_STRING);
$gitignore_content = filter_input(INPUT_POST, 'gitignore_content', FILTER_SANITIZE_STRING);
if ( ! isset( $submit_save ) || ! isset( $gitignore_content ) ) {
return;
}
check_admin_referer( 'gitium-settings' );
if ( $this->git->set_gitignore( $gitignore_content ) ) {
gitium_commit_and_push_gitignore_file();
$this->success_redirect( __( 'The file `.gitignore` is saved!', 'gitium' ), $this->settings_menu_slug );
} else {
$this->redirect( __( 'The file `.gitignore` could not be saved!', 'gitium' ), false, $this->settings_menu_slug );
}
}
public function page() {
$this->show_message();
?>
<div class="wrap">
<h2><?php _e( 'Gitium Settings', 'gitium' ); ?></h2>
<form action="" method="POST">
<?php wp_nonce_field( 'gitium-settings' ) ?>
<p><span style="color:red;"><?php _e( 'Be careful when you modify this list!', 'gitium' ); ?></span></p>
<textarea name="gitignore_content" rows="20" cols="140"><?php echo esc_html( $this->git->get_gitignore() ); ?></textarea>
<?php $this->show_webhook_table(); ?>
<p class="submit">
<input type="submit" name="GitiumSubmitSave" class="button-primary" value="<?php _e( 'Save', 'gitium' ); ?>" />
</p>
</form>
</div>
<?php
}
}

View File

@ -0,0 +1,236 @@
<?php
/* Copyright 2014-2016 Presslabs SRL <ping@presslabs.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2, as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
class Gitium_Submenu_Status extends Gitium_Menu {
public function __construct() {
parent::__construct( $this->gitium_menu_slug, $this->gitium_menu_slug );
if ( current_user_can( GITIUM_MANAGE_OPTIONS_CAPABILITY ) ) {
add_action( GITIUM_ADMIN_MENU_ACTION, array( $this, 'admin_menu' ) );
add_action( 'admin_init', array( $this, 'save_changes' ) );
add_action( 'admin_init', array( $this, 'save_ignorelist' ) );
add_action( 'admin_init', array( $this, 'disconnect_repository' ) );
}
}
public function admin_menu() {
add_menu_page(
__( 'Git Status', 'gitium' ),
'Gitium',
GITIUM_MANAGE_OPTIONS_CAPABILITY,
$this->menu_slug,
array( $this, 'page' ),
plugins_url( 'img/gitium.png', dirname( __FILE__ ) )
);
$submenu_hook = add_submenu_page(
$this->menu_slug,
__( 'Git Status', 'gitium' ),
__( 'Status', 'gitium' ),
GITIUM_MANAGE_OPTIONS_CAPABILITY,
$this->menu_slug,
array( $this, 'page' )
);
new Gitium_Help( $submenu_hook, 'status' );
}
private function get_change_meanings() {
return array(
'??' => __( 'untracked', 'gitium' ),
'rM' => __( 'modified on remote', 'gitium' ),
'rA' => __( 'added to remote', 'gitium' ),
'rD' => __( 'deleted from remote', 'gitium' ),
'D' => __( 'deleted from work tree', 'gitium' ),
'M' => __( 'updated in work tree', 'gitium' ),
'A' => __( 'added to work tree', 'gitium' ),
'AM' => __( 'added to work tree', 'gitium' ),
'R' => __( 'deleted from work tree', 'gitium' ),
);
}
public function humanized_change( $change ) {
$meaning = $this->get_change_meanings();
if ( isset( $meaning[ $change ] ) ) {
return $meaning[ $change ];
}
if ( 0 === strpos( $change, 'R ' ) ) {
$old_filename = substr( $change, 2 );
$change = sprintf( __( 'renamed from `%s`', 'gitium' ), $old_filename );
}
return $change;
}
public function save_ignorelist() {
$gitium_ignore_path = filter_input(INPUT_POST, 'GitiumIgnorePath', FILTER_SANITIZE_STRING);
if ( ! isset( $gitium_ignore_path ) ) {
return;
} else {
$path = $gitium_ignore_path;
}
check_admin_referer( 'gitium-admin' );
if ( $this->git->set_gitignore( join( "\n", array_unique( array_merge( explode( "\n", $this->git->get_gitignore() ), array( $path ) ) ) ) ) ) {
gitium_commit_and_push_gitignore_file( $path );
$this->success_redirect( __( 'The file `.gitignore` is saved!', 'gitium' ), $this->gitium_menu_slug );
} else {
$this->redirect( __( 'The file `.gitignore` could not be saved!', 'gitium' ), false, $this->gitium_menu_slug );
}
}
public function save_changes() {
$gitium_save_changes = filter_input(INPUT_POST, 'GitiumSubmitSaveChanges', FILTER_SANITIZE_STRING);
$gitium_commit_msg = filter_input(INPUT_POST, 'commitmsg', FILTER_SANITIZE_STRING);
if ( ! isset( $gitium_save_changes ) ) {
return;
}
check_admin_referer( 'gitium-admin' );
gitium_enable_maintenance_mode() or wp_die( __( 'Could not enable the maintenance mode!', 'gitium' ) );
$this->git->add();
$commitmsg = sprintf( __( 'Merged changes from %s on %s', 'gitium' ), get_site_url(), date( 'm.d.Y' ) );
if ( isset( $gitium_commit_msg ) && ! empty( $gitium_commit_msg ) ) {
$commitmsg = $gitium_commit_msg;
}
$current_user = wp_get_current_user();
$commit = $this->git->commit( $commitmsg, $current_user->display_name, $current_user->user_email );
if ( ! $commit ) {
$this->redirect( __( 'Could not commit!', 'gitium' ) );
}
$merge_success = gitium_merge_and_push( $commit );
gitium_disable_maintenance_mode();
if ( ! $merge_success ) {
$this->redirect( __( 'Merge failed: ', 'gitium' ) . $this->git->get_last_error() );
}
$this->success_redirect( sprintf( __( 'Pushed commit: `%s`', 'gitium' ), $commitmsg ) );
}
private function show_ahead_and_behind_info( $changes = '' ) {
$branch = $this->git->get_remote_tracking_branch();
$ahead = count( $this->git->get_ahead_commits() );
$behind = count( $this->git->get_behind_commits() );
?>
<p>
<?php printf( __( 'Following remote branch <code>%s</code>.', 'gitium' ), $branch );
?>&nbsp;<?php
if ( ! $ahead && ! $behind && empty( $changes ) ) {
_e( 'Everything is up to date', 'gitium' );
}
if ( $ahead && $behind ) {
printf( __( 'You are %s commits ahead and %s behind remote.', 'gitium' ), $ahead, $behind );
} elseif ( $ahead ) {
printf( __( 'You are %s commits ahead remote.', 'gitium' ), $ahead );
} elseif ( $behind ) {
printf( __( 'You are %s commits behind remote.', 'gitium' ), $behind );
}
?>
</p>
<?php
}
private function show_git_changes_table_rows( $changes = '' ) {
?>
<script type="application/javascript">
function add_path_and_submit( elem ) {
var container = document.getElementById( 'form_status' );
var input = document.createElement( 'input' );
input.type = 'hidden';
input.name = 'GitiumIgnorePath';
input.value = elem;
container.appendChild( input );
container.submit();
}
</script>
<?php
$counter = 0;
foreach ( $changes as $path => $type ) :
$counter++;
echo ( 0 != $counter % 2 ) ? '<tr class="alternate">' : '<tr>';
echo '<td><strong>' . esc_html( $path ) . '</strong>';
echo '<div class="row-actions"><span class="edit"><a href="#" onclick="add_path_and_submit(\'' . $path . '\');">' . __( 'Add this file to the `.gitignore` list.', 'gitium' ) . '</a></span></div></td>';
echo '<td>';
if ( is_dir( ABSPATH . '/' . $path ) && is_dir( ABSPATH . '/' . trailingslashit( $path ) . '.git' ) ) { // test if is submodule
_e( 'Submodules are not supported in this version.', 'gitium' );
} else {
echo '<span title="' . esc_html( $type ) .'">' . esc_html( $this->humanized_change( $type ) ) . '</span>';
}
echo '</td>';
echo '</tr>';
endforeach;
}
private function show_git_changes_table( $changes = '' ) {
?>
<table class="widefat" id="git-changes-table">
<thead><tr><th scope="col" class="manage-column"><?php _e( 'Path', 'gitium' ); ?></th><th scope="col" class="manage-column"><?php _e( 'Change', 'gitium' ); ?></th></tr></thead>
<tfoot><tr><th scope="col" class="manage-column"><?php _e( 'Path', 'gitium' ); ?></th><th scope="col" class="manage-column"><?php _e( 'Change', 'gitium' ); ?></th></tr></tfoot>
<tbody>
<?php
if ( empty( $changes ) ) :
echo '<tr><td><p>';
_e( 'Nothing to commit, working directory clean.', 'gitium' );
echo '</p></td></tr>';
else :
$this->show_git_changes_table_rows( $changes );
endif;
?>
</tbody>
</table>
<?php
}
private function show_git_changes_table_submit_buttons( $changes ) {
if ( ! empty( $changes ) ) : ?>
<p>
<label for="save-changes"><?php _e( 'Commit message', 'gitium' ); ?>:</label>
<input type="text" name="commitmsg" id="save-changes" class="widefat" value="" placeholder="<?php printf( __( 'Merged changes from %s on %s', 'gitium' ), get_site_url(), date( 'm.d.Y' ) ); ?>" />
</p>
<p>
<input type="submit" name="GitiumSubmitSaveChanges" class="button-primary button" value="<?php _e( 'Save changes', 'gitium' ); ?>" <?php if ( get_transient( 'gitium_remote_disconnected' ) ) { echo 'disabled="disabled" '; } ?>/>&nbsp;
</p>
<?php endif;
}
private function changes_page() {
list( , $changes ) = _gitium_status();
?>
<div class="wrap">
<div id="icon-options-general" class="icon32">&nbsp;</div>
<h2><?php _e( 'Status', 'gitium' ); ?> <code class="small" style="background-color:forestgreen; color:whitesmoke;"><?php _e( 'connected to', 'gitium' ); ?> <strong><?php echo esc_html( $this->git->get_remote_url() ); ?></strong></code></h2>
<form name="form_status" id="form_status" action="" method="POST">
<?php
wp_nonce_field( 'gitium-admin' );
$this->show_ahead_and_behind_info( $changes );
$this->show_git_changes_table( $changes );
$this->show_git_changes_table_submit_buttons( $changes );
?>
</form>
<?php
$this->show_disconnect_repository_button();
?>
</div>
<?php
}
public function page() {
$this->show_message();
_gitium_status( true );
$this->changes_page();
}
}

View File

@ -0,0 +1,8 @@
#!/bin/sh
SSH_AUTH_SOCK=''
SSH="ssh -q -F /dev/null -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
if [ -z "$GIT_KEY_FILE" ] ; then
exec $SSH "$@"
else
exec $SSH -i "$GIT_KEY_FILE" "$@"
fi