-
Notifications
You must be signed in to change notification settings - Fork 0
/
jurassic.ninja-private-repos.php
143 lines (126 loc) · 4.98 KB
/
jurassic.ninja-private-repos.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
<?php
namespace jn_pr;
/*
* Plugin Name: Jurassic Ninja Private Repos
* Description: Allows private repos to be added to Jurassic Ninja sites.
* Version: 0.1
* Author: c-shultz
**/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
if ( ! defined( 'JN_PRIVATE_REPOS_ABSPATH' ) ) {
define( 'JN_PRIVATE_REPOS_ABSPATH', dirname( __FILE__ ) . '/' );
}
function init() {
// Add list of repo data from request paramters to features data.
add_filter( 'jurassic_ninja_rest_create_request_features', 'jn_pr\add_private_repos_features', 10, 2);
// Download repos to local server and push them to new site.
add_action( 'jurassic_ninja_create_app', 'jn_pr\transfer_private_repos', 999, 6 );
}
add_action( 'jurassic_ninja_init', 'jn_pr\init', 10, 2 );
/**
* Get array of repos from which plugins should be installed on the remote site.
*
* @return array {
* @return array {
* @type string 'name' Repo name (slug from full repo URL (e.g. 'jetpack' from https://github.com/Automattic/jetpack.git)
* @type string 'url' URL for GitHub user/organization for repo (e.g. 'github.com/woocommerce')
* @type string 'branch' Branch to clone from repo.
* @type bool 'build' If true, plugin will be built with 'npm install && npm run build'.
* }
* }
*/
function add_private_repos_features( $features, $json_params ) {
if ( isset( $json_params['jn_pr_repos'] ) ) {
$features['repos'] = json_decode( urldecode( $json_params['jn_pr_repos'] ), true );
}
return $features;
}
// Downloads archive(s) from private GitHub repo and upload to the new site, and build.
function transfer_private_repos( &$app, $user, $php_version, $domain, $wordpress_options, $features ) {
if ( is_wp_error( $app ) ) {
return;
}
$password = $wordpress_options['admin_password'];
$username = $user->data->name;
$repos = $features['repos'];
if ( empty( $repos ) ) {
return;
}
// Install npm by uploading installer script and running it on the remote server.
upload_file_to_jn( JN_PRIVATE_REPOS_ABSPATH . 'bin/node-install.sh', '~/node-install.sh', $domain, $username, $password );
run_command( $username, $password, $domain, 'chmod +x ~/node-install.sh && ~/node-install.sh' );
foreach ( $repos as $repo ) {
// Get archive of repository from GitHub.
$archive_file = get_repo_archive( $repo );
$dest_filename = "{$repo['name']}.zip";
upload_file_to_jn( $archive_file, $dest_filename, $domain, $username, $password );
unlink( $archive_file );
// Now install, build, and activate the plugin.
$wp_home = "~/apps/$username/public";
$plugins_dir = "$wp_home/wp-content/plugins";
$build_cmd = $repo['build'] ? ' && npm install && npm run build' : '';
run_command( $username, $password, $domain,
'source ~/.nvm/nvm.sh' . // Sets up Node environment so 'npm' is available.
" && unzip $dest_filename -d $plugins_dir" . // Unzip plugin archive.
" && cd $plugins_dir/{$repo['name']}" .
$build_cmd .
" && cd .." .
" && wp plugin activate {$repo['name']}"
);
}
}
// Upload source_filename to the home directory of server @ $domain
function upload_file_to_jn( $source_filename, $dest_filename, $domain, $username, $password) {
$run = "SSHPASS=$password sshpass -e scp -o StrictHostKeyChecking=no $source_filename $username@$domain:$dest_filename";
exec( $run, $output, $return_value );
// phpcs:enable
if ( 0 !== $return_value ) {
\jn\debug( 'Commands run finished with code %s and output: %s',
$return_value,
implode( ' -> ', $output )
);
return new \WP_Error(
'commands_did_not_run_successfully',
"Commands didn't run OK"
);
}
}
// Download repo with git, archive it, and return temporary file location.
function get_repo_archive( $repo ) {
$gh_username = JN_PR_GH_USERNAME;
$gh_password = JN_PR_GH_PASSWORD;
$sys_tmp = sys_get_temp_dir();
$tmp_dir = exec( "mktemp -d" );
$clone_url = "https://$gh_username:$gh_password@{$repo['url']}/{$repo['name']}";
$output = shell_exec(
"cd $tmp_dir" .
" && git clone -b {$repo['branch']} $clone_url" .
" && zip -r {$repo['name']}.zip {$repo['name']}/*" .
" && rm -rf {$repo['name']}"
);
return "$tmp_dir/{$repo['name']}.zip";
}
// Run a shell command on remote site.
function run_command( $user, $password, $domain, $cmd ) {
// Redirect all errors to stdout so exec shows them in the $output parameters
$run = "SSHPASS=$password sshpass -e ssh -oStrictHostKeyChecking=no $user@$domain '$cmd' 2>&1";
$output = null;
$return_value = null;
// Use exec instead of shell_exect so we can know if the commands failed or not
// phpcs:disable WordPress.PHP.DiscouragedPHPFunctions.system_calls_exec
exec( $run, $output, $return_value );
// phpcs:enable
if ( 0 !== $return_value ) {
\jn\debug( 'Commands run finished with code %s and output: %s',
$return_value,
implode( ' -> ', $output )
);
return new \WP_Error(
'commands_did_not_run_successfully',
"Commands didn't run OK"
);
}
return null;
}