Pirate Rogue, Pirate Crew and GitHub Updater
This commit is contained in:
181
plugins/github-updater/src/GitHub_Updater/API/API_Interface.php
Normal file
181
plugins/github-updater/src/GitHub_Updater/API/API_Interface.php
Normal file
@@ -0,0 +1,181 @@
|
||||
<?php
|
||||
/**
|
||||
* GitHub Updater
|
||||
*
|
||||
* @author Andy Fragen
|
||||
* @license GPL-2.0+
|
||||
* @link https://github.com/afragen/github-updater
|
||||
* @package github-updater
|
||||
*/
|
||||
|
||||
namespace Fragen\GitHub_Updater\API;
|
||||
|
||||
/**
|
||||
* Interface API_Interface
|
||||
*/
|
||||
interface API_Interface {
|
||||
/**
|
||||
* Read the remote file and parse headers.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param string $file Filename.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_remote_info( $file);
|
||||
|
||||
/**
|
||||
* Get remote info for tags.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_remote_tag();
|
||||
|
||||
/**
|
||||
* Read the remote CHANGES.md file.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param string $changes Changelog filename.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_remote_changes( $changes);
|
||||
|
||||
/**
|
||||
* Read and parse remote readme.txt.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_remote_readme();
|
||||
|
||||
/**
|
||||
* Read the repository meta from API.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_repo_meta();
|
||||
|
||||
/**
|
||||
* Create array of branches and download links as array.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_remote_branches();
|
||||
|
||||
/**
|
||||
* Get release asset URL.
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
public function get_release_asset();
|
||||
|
||||
/**
|
||||
* Construct $this->type->download_link using Repository Contents API.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param bool $branch_switch For direct branch switching. Defaults to false.
|
||||
*
|
||||
* @return string URL for download link.
|
||||
*/
|
||||
public function construct_download_link( $branch_switch = false);
|
||||
|
||||
/**
|
||||
* Create endpoints.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param GitHub_API|Bitbucket_API|Bitbucket_Server_API|GitLab_API $git
|
||||
* @param string $endpoint
|
||||
*
|
||||
* @return string $endpoint
|
||||
*/
|
||||
public function add_endpoints( $git, $endpoint);
|
||||
|
||||
/**
|
||||
* Parse API response call and return only array of tag numbers.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param \stdClass|array $response API response.
|
||||
*
|
||||
* @return array|\stdClass Array of tag numbers, object is error.
|
||||
*/
|
||||
public function parse_tag_response( $response);
|
||||
|
||||
/**
|
||||
* Parse API response and return array of meta variables.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param \stdClass|array $response API response.
|
||||
*
|
||||
* @return array|\stdClass Array of meta variables.
|
||||
*/
|
||||
public function parse_meta_response( $response);
|
||||
|
||||
/**
|
||||
* Parse API response and return array with changelog.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param \stdClass|array $response API response.
|
||||
*
|
||||
* @return array|\stdClass $arr Array of changes in base64, object if error.
|
||||
*/
|
||||
public function parse_changelog_response( $response);
|
||||
|
||||
/**
|
||||
* Parse API response and return array of branch data.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param \stdClass $response API response.
|
||||
*
|
||||
* @return array Array of branch data.
|
||||
*/
|
||||
public function parse_branch_response( $response );
|
||||
|
||||
/**
|
||||
* Add values for individual repo add_setting_field().
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function add_repo_setting_field();
|
||||
|
||||
/**
|
||||
* Add settings for each API.
|
||||
*
|
||||
* @param array $auth_required
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function add_settings( $auth_required);
|
||||
|
||||
/**
|
||||
* Add remote install settings fields.
|
||||
*
|
||||
* @param string $type plugin|theme.
|
||||
*/
|
||||
public function add_install_settings_fields( $type);
|
||||
|
||||
/**
|
||||
* Add remote install feature, create endpoint.
|
||||
*
|
||||
* @param array $headers
|
||||
* @param array $install
|
||||
*
|
||||
* @return mixed $install
|
||||
*/
|
||||
public function remote_install( $headers, $install);
|
||||
}
|
||||
584
plugins/github-updater/src/GitHub_Updater/API/Bitbucket_API.php
Normal file
584
plugins/github-updater/src/GitHub_Updater/API/Bitbucket_API.php
Normal file
@@ -0,0 +1,584 @@
|
||||
<?php
|
||||
/**
|
||||
* GitHub Updater
|
||||
*
|
||||
* @author Andy Fragen
|
||||
* @license GPL-2.0+
|
||||
* @link https://github.com/afragen/github-updater
|
||||
* @package github-updater
|
||||
*/
|
||||
|
||||
namespace Fragen\GitHub_Updater\API;
|
||||
|
||||
use Fragen\Singleton;
|
||||
use Fragen\GitHub_Updater\API;
|
||||
use Fragen\GitHub_Updater\Branch;
|
||||
|
||||
/*
|
||||
* Exit if called directly.
|
||||
*/
|
||||
if ( ! defined( 'WPINC' ) ) {
|
||||
die;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Bitbucket_API
|
||||
*
|
||||
* Get remote data from a Bitbucket repo.
|
||||
*
|
||||
* @author Andy Fragen
|
||||
*/
|
||||
class Bitbucket_API extends API implements API_Interface {
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param \stdClass $type The repo type.
|
||||
*/
|
||||
public function __construct( $type ) {
|
||||
parent::__construct();
|
||||
$this->type = $type;
|
||||
$this->response = $this->get_repo_cache();
|
||||
$branch = new Branch( $this->response );
|
||||
if ( ! empty( $type->branch ) ) {
|
||||
$this->type->branch = ! empty( $branch->cache['current_branch'] )
|
||||
? $branch->cache['current_branch']
|
||||
: $type->branch;
|
||||
}
|
||||
$this->set_default_credentials();
|
||||
$this->settings_hook( $this );
|
||||
$this->add_settings_subtab();
|
||||
$this->add_install_fields( $this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default credentials if option not set.
|
||||
*/
|
||||
protected function set_default_credentials() {
|
||||
$running_servers = Singleton::get_instance( 'Base', $this )->get_running_git_servers();
|
||||
$set_credentials = false;
|
||||
if ( $this instanceof Bitbucket_API ) {
|
||||
$username = 'bitbucket_username';
|
||||
$password = 'bitbucket_password';
|
||||
}
|
||||
if ( $this instanceof Bitbucket_Server_API ) {
|
||||
$username = 'bitbucket_server_username';
|
||||
$password = 'bitbucket_server_password';
|
||||
}
|
||||
if ( ! isset( static::$options[ $username ] ) ) {
|
||||
static::$options[ $username ] = null;
|
||||
$set_credentials = true;
|
||||
}
|
||||
if ( ! isset( static::$options[ $password ] ) ) {
|
||||
static::$options[ $password ] = null;
|
||||
$set_credentials = true;
|
||||
}
|
||||
if ( ( empty( static::$options[ $username ] ) || empty( static::$options[ $password ] ) ) &&
|
||||
( ( 'bitbucket_username' === $username &&
|
||||
in_array( 'bitbucket', $running_servers, true ) ) ||
|
||||
( 'bitbucket_server_username' === $username &&
|
||||
in_array( 'bbserver', $running_servers, true ) ) )
|
||||
) {
|
||||
Singleton::get_instance( 'Messages', $this )->create_error_message( 'bitbucket' );
|
||||
static::$error_code['bitbucket'] = [ 'code' => 401 ];
|
||||
}
|
||||
if ( $set_credentials ) {
|
||||
add_site_option( 'github_updater', static::$options );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the remote file and parse headers.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param string $file The file.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_remote_info( $file ) {
|
||||
return $this->get_remote_api_info( 'bitbucket', $file, "/2.0/repositories/:owner/:repo/src/:branch/{$file}" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the remote info for tags.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_remote_tag() {
|
||||
return $this->get_remote_api_tag( 'bitbucket', '/2.0/repositories/:owner/:repo/refs/tags' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the remote CHANGES.md file.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param string $changes The changelog filename.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_remote_changes( $changes ) {
|
||||
return $this->get_remote_api_changes( 'bitbucket', $changes, "/2.0/repositories/:owner/:repo/src/:branch/{$changes}" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and parse remote readme.txt.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_remote_readme() {
|
||||
return $this->get_remote_api_readme( 'bitbucket', '/2.0/repositories/:owner/:repo/src/:branch/readme.txt' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the repository meta from API
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_repo_meta() {
|
||||
return $this->get_remote_api_repo_meta( 'bitbucket', '/2.0/repositories/:owner/:repo' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create array of branches and download links as array.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_remote_branches() {
|
||||
return $this->get_remote_api_branches( 'bitbucket', '/2.0/repositories/:owner/:repo/refs/branches' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Bitbucket release asset URL.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_release_asset() {
|
||||
return $this->get_api_release_asset( 'bitbucket', '/2.0/repositories/:owner/:repo/downloads' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct $this->type->download_link using Bitbucket API
|
||||
*
|
||||
* @param boolean $branch_switch For direct branch changing. Defaults to false.
|
||||
*
|
||||
* @return string $endpoint
|
||||
*/
|
||||
public function construct_download_link( $branch_switch = false ) {
|
||||
self::$method = 'download_link';
|
||||
$download_link_base = $this->get_api_url( '/:owner/:repo/get/', true );
|
||||
$endpoint = '';
|
||||
|
||||
// Release asset.
|
||||
if ( $this->type->release_asset && '0.0.0' !== $this->type->newest_tag ) {
|
||||
$release_asset = $this->get_release_asset();
|
||||
return $this->get_release_asset_redirect( $release_asset, true );
|
||||
}
|
||||
|
||||
/*
|
||||
* If a branch has been given, use branch.
|
||||
* If branch is master (default) and tags are used, use newest tag.
|
||||
*/
|
||||
if ( 'master' !== $this->type->branch || empty( $this->type->tags ) ) {
|
||||
if ( ! empty( $this->type->enterprise_api ) ) {
|
||||
$endpoint = add_query_arg( 'at', $this->type->branch, $endpoint );
|
||||
} else {
|
||||
$endpoint .= $this->type->branch . '.zip';
|
||||
}
|
||||
} else {
|
||||
if ( ! empty( $this->type->enterprise_api ) ) {
|
||||
$endpoint = add_query_arg( 'at', $this->type->newest_tag, $endpoint );
|
||||
} else {
|
||||
$endpoint .= $this->type->newest_tag . '.zip';
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Create endpoint for branch switching.
|
||||
*/
|
||||
if ( $branch_switch ) {
|
||||
if ( ! empty( $this->type->enterprise_api ) ) {
|
||||
$endpoint = add_query_arg( 'at', $branch_switch, $endpoint );
|
||||
} else {
|
||||
$endpoint = $branch_switch . '.zip';
|
||||
}
|
||||
}
|
||||
|
||||
$download_link = $download_link_base . $endpoint;
|
||||
|
||||
/**
|
||||
* Filter download link so developers can point to specific ZipFile
|
||||
* to use as a download link during a branch switch.
|
||||
*
|
||||
* @since 8.8.0
|
||||
*
|
||||
* @param string $download_link Download URL.
|
||||
* @param /stdClass $this->type Repository object.
|
||||
* @param string $branch_switch Branch or tag for rollback or branch switching.
|
||||
*/
|
||||
return apply_filters( 'github_updater_post_construct_download_link', $download_link, $this->type, $branch_switch );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Bitbucket API endpoints.
|
||||
*
|
||||
* @param Bitbucket_API|API $git
|
||||
* @param string $endpoint
|
||||
*
|
||||
* @return string|void $endpoint
|
||||
*/
|
||||
public function add_endpoints( $git, $endpoint ) {
|
||||
switch ( $git::$method ) {
|
||||
case 'file':
|
||||
case 'readme':
|
||||
case 'meta':
|
||||
case 'changes':
|
||||
case 'translation':
|
||||
case 'release_asset':
|
||||
case 'download_link':
|
||||
break;
|
||||
case 'tags':
|
||||
case 'branches':
|
||||
$endpoint = add_query_arg(
|
||||
[
|
||||
'pagelen' => '100',
|
||||
'sort' => '-name',
|
||||
],
|
||||
$endpoint
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
$endpoint = $this->add_access_token_endpoint( $git, $endpoint );
|
||||
|
||||
return $endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse API response call and return only array of tag numbers.
|
||||
*
|
||||
* @param \stdClass $response Response from API call.
|
||||
*
|
||||
* @return array|\stdClass Array of tag numbers, object is error.
|
||||
*/
|
||||
public function parse_tag_response( $response ) {
|
||||
if ( ! isset( $response->values ) || $this->validate_response( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$arr = [];
|
||||
array_map(
|
||||
function ( $e ) use ( &$arr ) {
|
||||
$arr[] = $e->name;
|
||||
|
||||
return $arr;
|
||||
},
|
||||
(array) $response->values
|
||||
);
|
||||
|
||||
return $arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse API response and return array of meta variables.
|
||||
*
|
||||
* @param \stdClass|array $response Response from API call.
|
||||
*
|
||||
* @return array $arr Array of meta variables.
|
||||
*/
|
||||
public function parse_meta_response( $response ) {
|
||||
if ( $this->validate_response( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
$arr = [];
|
||||
$response = [ $response ];
|
||||
|
||||
array_filter(
|
||||
$response,
|
||||
function ( $e ) use ( &$arr ) {
|
||||
$arr['private'] = $e->is_private;
|
||||
$arr['last_updated'] = $e->updated_on;
|
||||
$arr['watchers'] = 0;
|
||||
$arr['forks'] = 0;
|
||||
$arr['open_issues'] = 0;
|
||||
}
|
||||
);
|
||||
|
||||
return $arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse API response and return array with changelog in base64.
|
||||
*
|
||||
* @param \stdClass|array $response Response from API call.
|
||||
*
|
||||
* @return array|\stdClass $arr Array of changes in base64, object if error.
|
||||
*/
|
||||
public function parse_changelog_response( $response ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse API response and return array of branch data.
|
||||
*
|
||||
* @param \stdClass $response API response.
|
||||
*
|
||||
* @return array Array of branch data.
|
||||
*/
|
||||
public function parse_branch_response( $response ) {
|
||||
if ( $this->validate_response( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
$branches = [];
|
||||
foreach ( $response as $branch ) {
|
||||
$branches[ $branch->name ]['download'] = $this->construct_download_link( $branch->name );
|
||||
$branches[ $branch->name ]['commit_hash'] = $branch->target->hash;
|
||||
$branches[ $branch->name ]['commit_timestamp'] = $branch->target->date;
|
||||
}
|
||||
return $branches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse tags and create download links.
|
||||
*
|
||||
* @param \stdClass|array $response Response from API call.
|
||||
* @param string $repo_type
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function parse_tags( $response, $repo_type ) {
|
||||
$tags = [];
|
||||
$rollback = [];
|
||||
|
||||
foreach ( (array) $response as $tag ) {
|
||||
// $download_base = implode(
|
||||
// '/',
|
||||
// [
|
||||
// $repo_type['base_download'],
|
||||
// $this->type->owner,
|
||||
// $this->type->owner,
|
||||
// 'get/',
|
||||
// ]
|
||||
// );
|
||||
$download_base = "{$repo_type['base_download']}/{$this->type->owner}/{$this->type->owner}/get/";
|
||||
$tags[] = $tag;
|
||||
$rollback[ $tag ] = $download_base . $tag . '.zip';
|
||||
}
|
||||
|
||||
return [ $tags, $rollback ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add settings for Bitbucket Username and Password.
|
||||
*
|
||||
* @param array $auth_required
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add_settings( $auth_required ) {
|
||||
add_settings_section(
|
||||
'bitbucket_user',
|
||||
esc_html__( 'Bitbucket Private Settings', 'github-updater' ),
|
||||
[ $this, 'print_section_bitbucket_username' ],
|
||||
'github_updater_bitbucket_install_settings'
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'bitbucket_username',
|
||||
esc_html__( 'Bitbucket Username', 'github-updater' ),
|
||||
[ Singleton::get_instance( 'Settings', $this ), 'token_callback_text' ],
|
||||
'github_updater_bitbucket_install_settings',
|
||||
'bitbucket_user',
|
||||
[ 'id' => 'bitbucket_username' ]
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'bitbucket_password',
|
||||
esc_html__( 'Bitbucket Password', 'github-updater' ),
|
||||
[ Singleton::get_instance( 'Settings', $this ), 'token_callback_text' ],
|
||||
'github_updater_bitbucket_install_settings',
|
||||
'bitbucket_user',
|
||||
[
|
||||
'id' => 'bitbucket_password',
|
||||
'token' => true,
|
||||
]
|
||||
);
|
||||
|
||||
/*
|
||||
* Show section for private Bitbucket repositories.
|
||||
*/
|
||||
if ( $auth_required['bitbucket_private'] ) {
|
||||
add_settings_section(
|
||||
'bitbucket_id',
|
||||
esc_html__( 'Bitbucket Private Repositories', 'github-updater' ),
|
||||
[ $this, 'print_section_bitbucket_info' ],
|
||||
'github_updater_bitbucket_install_settings'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add values for individual repo add_setting_field().
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function add_repo_setting_field() {
|
||||
$setting_field['page'] = 'github_updater_bitbucket_install_settings';
|
||||
$setting_field['section'] = 'bitbucket_id';
|
||||
$setting_field['callback_method'] = [
|
||||
Singleton::get_instance( 'Settings', $this ),
|
||||
'token_callback_checkbox',
|
||||
];
|
||||
|
||||
return $setting_field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add subtab to Settings page.
|
||||
*/
|
||||
private function add_settings_subtab() {
|
||||
add_filter(
|
||||
'github_updater_add_settings_subtabs',
|
||||
function ( $subtabs ) {
|
||||
return array_merge( $subtabs, [ 'bitbucket' => esc_html__( 'Bitbucket', 'github-updater' ) ] );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the Bitbucket repo Settings text.
|
||||
*/
|
||||
public function print_section_bitbucket_info() {
|
||||
esc_html_e( 'Check box if private repository. Leave unchecked for public repositories.', 'github-updater' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the Bitbucket user/pass Settings text.
|
||||
*/
|
||||
public function print_section_bitbucket_username() {
|
||||
esc_html_e( 'Enter your personal Bitbucket username and password.', 'github-updater' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add remote install settings fields.
|
||||
*
|
||||
* @param string $type
|
||||
*/
|
||||
public function add_install_settings_fields( $type ) {
|
||||
if ( ( empty( static::$options['bitbucket_username'] ) ||
|
||||
empty( static::$options['bitbucket_password'] ) ) ||
|
||||
|
||||
( empty( static::$options['bitbucket_server_username'] ) ||
|
||||
empty( static::$options['bitbucket_server_password'] ) )
|
||||
) {
|
||||
add_settings_field(
|
||||
'bitbucket_username',
|
||||
esc_html__( 'Bitbucket Username', 'github-updater' ),
|
||||
[ $this, 'bitbucket_username' ],
|
||||
'github_updater_install_' . $type,
|
||||
$type
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'bitbucket_password',
|
||||
esc_html__( 'Bitbucket Password', 'github-updater' ),
|
||||
[ $this, 'bitbucket_password' ],
|
||||
'github_updater_install_' . $type,
|
||||
$type
|
||||
);
|
||||
}
|
||||
|
||||
add_settings_field(
|
||||
'is_private',
|
||||
esc_html__( 'Private Bitbucket Repository', 'github-updater' ),
|
||||
[ $this, 'is_private_repo' ],
|
||||
'github_updater_install_' . $type,
|
||||
$type
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setting for private repo for remote install.
|
||||
*/
|
||||
public function is_private_repo() {
|
||||
?>
|
||||
<label for="is_private">
|
||||
<input class="bitbucket_setting" type="checkbox" id="is_private" name="is_private" <?php checked( '1', false ); ?> >
|
||||
<br>
|
||||
<span class="description">
|
||||
<?php esc_html_e( 'Check for private Bitbucket repositories.', 'github-updater' ); ?>
|
||||
</span>
|
||||
</label>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Bitbucket username for remote install.
|
||||
*/
|
||||
public function bitbucket_username() {
|
||||
?>
|
||||
<label for="bitbucket_username">
|
||||
<input class="bitbucket_setting" type="text" style="width:50%;" id="bitbucket_username" name="bitbucket_username" value="">
|
||||
<br>
|
||||
<span class="description">
|
||||
<?php esc_html_e( 'Enter Bitbucket username.', 'github-updater' ); ?>
|
||||
</span>
|
||||
</label>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Bitbucket password for remote install.
|
||||
*/
|
||||
public function bitbucket_password() {
|
||||
?>
|
||||
<label for="bitbucket_password">
|
||||
<input class="bitbucket_setting" type="password" style="width:50%;" id="bitbucket_password" name="bitbucket_password" value="" autocomplete="new-password">
|
||||
<br>
|
||||
<span class="description">
|
||||
<?php esc_html_e( 'Enter Bitbucket password.', 'github-updater' ); ?>
|
||||
</span>
|
||||
</label>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Add remote install feature, create endpoint.
|
||||
*
|
||||
* @param array $headers
|
||||
* @param array $install
|
||||
*
|
||||
* @return mixed $install
|
||||
*/
|
||||
public function remote_install( $headers, $install ) {
|
||||
$bitbucket_org = true;
|
||||
|
||||
if ( 'bitbucket.org' === $headers['host'] || empty( $headers['host'] ) ) {
|
||||
$base = 'https://bitbucket.org';
|
||||
$headers['host'] = 'bitbucket.org';
|
||||
} else {
|
||||
$base = $headers['base_uri'];
|
||||
$bitbucket_org = false;
|
||||
}
|
||||
|
||||
if ( $bitbucket_org ) {
|
||||
$install['download_link'] = "{$base}/{$install['github_updater_repo']}/get/{$install['github_updater_branch']}.zip";
|
||||
if ( isset( $install['is_private'] ) ) {
|
||||
$install['options'][ $install['repo'] ] = 1;
|
||||
}
|
||||
if ( ! empty( $install['bitbucket_username'] ) ) {
|
||||
$install['options']['bitbucket_username'] = $install['bitbucket_username'];
|
||||
}
|
||||
if ( ! empty( $install['bitbucket_password'] ) ) {
|
||||
$install['options']['bitbucket_password'] = $install['bitbucket_password'];
|
||||
}
|
||||
}
|
||||
|
||||
return $install;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,451 @@
|
||||
<?php
|
||||
/**
|
||||
* GitHub Updater
|
||||
*
|
||||
* @author Andy Fragen
|
||||
* @license GPL-2.0+
|
||||
* @link https://github.com/afragen/github-updater
|
||||
* @package github-updater
|
||||
*/
|
||||
|
||||
namespace Fragen\GitHub_Updater\API;
|
||||
|
||||
use Fragen\Singleton;
|
||||
use Fragen\GitHub_Updater\API;
|
||||
use Fragen\GitHub_Updater\Readme_Parser;
|
||||
|
||||
/*
|
||||
* Exit if called directly.
|
||||
*/
|
||||
if ( ! defined( 'WPINC' ) ) {
|
||||
die;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Bitbucket_Server_API
|
||||
*
|
||||
* Get remote data from a self-hosted Bitbucket Server repo.
|
||||
* Assumes an owner == project_key
|
||||
* Group URI: https://bitbucket.example.com/projects/<owner>/<repo>
|
||||
* User URI: https://bitbucket.example.com/users/<owner>/<repo>
|
||||
*
|
||||
* @link https://docs.atlassian.com/bitbucket-server/rest/5.3.1/bitbucket-rest.html
|
||||
*
|
||||
* @author Andy Fragen
|
||||
* @author Bjorn Wijers
|
||||
*/
|
||||
class Bitbucket_Server_API extends Bitbucket_API {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \stdClass $type
|
||||
*/
|
||||
public function __construct( $type ) {
|
||||
parent::__construct( $type );
|
||||
$this->add_settings_subtab();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the remote file and parse headers.
|
||||
*
|
||||
* @param string $file Filename.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_remote_info( $file ) {
|
||||
return $this->get_remote_api_info( 'bbserver', $file, "/1.0/:owner/repos/:repo/browse/{$file}" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the repository meta from API
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_repo_meta() {
|
||||
return $this->get_remote_api_repo_meta( 'bbserver', '/1.0/:owner/repos/:repo' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the remote info for tags.
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_remote_tag() {
|
||||
return $this->get_remote_api_tag( 'bbserver', '/1.0/:owner/repos/:repo/tags' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and parse remote readme.txt.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_remote_readme() {
|
||||
return $this->get_remote_api_readme( 'bbserver', '/1.0/:owner/repos/:repo/raw/readme.txt' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the remote CHANGES.md file
|
||||
*
|
||||
* @param string $changes Changelog filename.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_remote_changes( $changes ) {
|
||||
return $this->get_remote_api_changes( 'bbserver', $changes, "/1.0/:owner/repos/:repo/raw/{$changes}" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create array of branches and download links as array.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_remote_branches() {
|
||||
return $this->get_remote_api_branches( 'bbserver', '/1.0/:owner/repos/:repo/branches' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Bitbucket Sever release asset URL.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_release_asset() {
|
||||
// TODO: make this work.
|
||||
// return $this->get_api_release_asset( 'bbserver', '/1.0/:owner/:repo/downloads' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct $this->type->download_link using Bitbucket Server API.
|
||||
*
|
||||
* Downloads requires the official stash-archive plugin which enables
|
||||
* subdirectory support using the prefix query argument.
|
||||
*
|
||||
* @link https://bitbucket.org/atlassian/stash-archive
|
||||
*
|
||||
* @param boolean $branch_switch for direct branch changing.
|
||||
*
|
||||
* @return string $endpoint
|
||||
*/
|
||||
public function construct_download_link( $branch_switch = false ) {
|
||||
self::$method = 'download_link';
|
||||
$download_link_base = $this->get_api_url( '/latest/:owner/repos/:repo/archive', true );
|
||||
$endpoint = $this->add_endpoints( $this, '' );
|
||||
|
||||
if ( $branch_switch ) {
|
||||
$endpoint = urldecode( add_query_arg( 'at', $branch_switch, $endpoint ) );
|
||||
}
|
||||
|
||||
return $download_link_base . $endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Bitbucket Server API endpoints.
|
||||
*
|
||||
* @param Bitbucket_Server_API|API $git
|
||||
* @param string $endpoint
|
||||
*
|
||||
* @return string $endpoint
|
||||
*/
|
||||
public function add_endpoints( $git, $endpoint ) {
|
||||
switch ( self::$method ) {
|
||||
case 'meta':
|
||||
case 'translation':
|
||||
case 'branches':
|
||||
break;
|
||||
case 'file':
|
||||
case 'readme':
|
||||
$endpoint = add_query_arg( 'at', $git->type->branch, $endpoint );
|
||||
break;
|
||||
case 'changes':
|
||||
$endpoint = add_query_arg(
|
||||
[
|
||||
'at' => $git->type->branch,
|
||||
'raw' => '',
|
||||
],
|
||||
$endpoint
|
||||
);
|
||||
break;
|
||||
case 'tags':
|
||||
case 'download_link':
|
||||
/*
|
||||
* Add a prefix query argument to create a subdirectory with the same name
|
||||
* as the repo, e.g. 'my-repo' becomes 'my-repo/'
|
||||
* Required for using stash-archive.
|
||||
*/
|
||||
$defaults = [
|
||||
'prefix' => $git->type->slug . '/',
|
||||
'at' => $git->type->branch,
|
||||
'format' => 'zip',
|
||||
];
|
||||
$endpoint = add_query_arg( $defaults, $endpoint );
|
||||
if ( ! empty( $git->type->tags ) ) {
|
||||
$endpoint = urldecode( add_query_arg( 'at', $git->type->newest_tag, $endpoint ) );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return $endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines separate text lines from API response into one string with \n line endings.
|
||||
* Code relying on raw text can now parse it.
|
||||
*
|
||||
* @param string|\stdClass|mixed $response
|
||||
*
|
||||
* @return string Combined lines of text returned by API
|
||||
*/
|
||||
protected function bbserver_recombine_response( $response ) {
|
||||
if ( $this->validate_response( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
$remote_info_file = '';
|
||||
if ( isset( $response->lines ) ) {
|
||||
foreach ( (array) $response->lines as $line ) {
|
||||
$remote_info_file .= $line->text . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
return $remote_info_file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse API response and return array of meta variables.
|
||||
*
|
||||
* @param \stdClass|array $response Response from API call.
|
||||
*
|
||||
* @return array $arr Array of meta variables.
|
||||
*/
|
||||
public function parse_meta_response( $response ) {
|
||||
if ( $this->validate_response( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
$arr = [];
|
||||
$response = [ $response ];
|
||||
|
||||
array_filter(
|
||||
$response,
|
||||
function ( $e ) use ( &$arr ) {
|
||||
$arr['private'] = ! $e->public;
|
||||
$arr['last_updated'] = null;
|
||||
$arr['watchers'] = 0;
|
||||
$arr['forks'] = 0;
|
||||
$arr['open_issues'] = 0;
|
||||
}
|
||||
);
|
||||
|
||||
return $arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse API response and return array with changelog.
|
||||
*
|
||||
* @param string $response Response from API call.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function parse_changelog_response( $response ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse API response and return object with readme body.
|
||||
*
|
||||
* @param string|\stdClass $response
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function parse_readme_response( $response ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse API response and return array of branch data.
|
||||
*
|
||||
* @param \stdClass $response API response.
|
||||
*
|
||||
* @return array Array of branch data.
|
||||
*/
|
||||
public function parse_branch_response( $response ) {
|
||||
if ( $this->validate_response( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
$branches = [];
|
||||
foreach ( $response as $branch ) {
|
||||
$branches[ $branch->displayId ]['download'] = $this->construct_download_link( $branch->displayId );
|
||||
$branches[ $branch->displayId ]['commit_hash'] = $branch->latestCommit;
|
||||
}
|
||||
return $branches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse API response call and return only array of tag numbers.
|
||||
*
|
||||
* @param \stdClass $response Response from API call.
|
||||
*
|
||||
* @return array|\stdClass Array of tag numbers, object is error.
|
||||
*/
|
||||
public function parse_tag_response( $response ) {
|
||||
if ( ! isset( $response->values ) || $this->validate_response( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$arr = [];
|
||||
array_map(
|
||||
function ( $e ) use ( &$arr ) {
|
||||
$arr[] = $e->displayId;
|
||||
|
||||
return $arr;
|
||||
},
|
||||
(array) $response->values
|
||||
);
|
||||
|
||||
return $arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse tags and create download links.
|
||||
*
|
||||
* @param \stdClass|array $response Response from API call.
|
||||
* @param string $repo_type
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function parse_tags( $response, $repo_type ) {
|
||||
$tags = [];
|
||||
$rollback = [];
|
||||
|
||||
foreach ( (array) $response as $tag ) {
|
||||
$download_base = "{$repo_type['base_uri']}/latest/{$this->type->owner}/repos/{$this->type->slug}/archive";
|
||||
$download_base = $this->add_endpoints( $this, $download_base );
|
||||
$tags[] = $tag;
|
||||
$rollback[ $tag ] = add_query_arg( 'at', $tag, $download_base );
|
||||
}
|
||||
|
||||
return [ $tags, $rollback ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add settings for Bitbucket Server Username and Password.
|
||||
*
|
||||
* @param array $auth_required
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add_settings( $auth_required ) {
|
||||
add_settings_section(
|
||||
'bitbucket_server_user',
|
||||
esc_html__( 'Bitbucket Server Private Settings', 'github-updater' ),
|
||||
[ $this, 'print_section_bitbucket_username' ],
|
||||
'github_updater_bbserver_install_settings'
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'bitbucket_server_username',
|
||||
esc_html__( 'Bitbucket Server Username', 'github-updater' ),
|
||||
[ Singleton::get_instance( 'Settings', $this ), 'token_callback_text' ],
|
||||
'github_updater_bbserver_install_settings',
|
||||
'bitbucket_server_user',
|
||||
[ 'id' => 'bitbucket_server_username' ]
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'bitbucket_server_password',
|
||||
esc_html__( 'Bitbucket Server Password', 'github-updater' ),
|
||||
[ Singleton::get_instance( 'Settings', $this ), 'token_callback_text' ],
|
||||
'github_updater_bbserver_install_settings',
|
||||
'bitbucket_server_user',
|
||||
[
|
||||
'id' => 'bitbucket_server_password',
|
||||
'token' => true,
|
||||
]
|
||||
);
|
||||
|
||||
/*
|
||||
* Show section for private Bitbucket Server repositories.
|
||||
*/
|
||||
if ( $auth_required['bitbucket_server'] ) {
|
||||
add_settings_section(
|
||||
'bitbucket_server_id',
|
||||
esc_html__( 'Bitbucket Server Private Repositories', 'github-updater' ),
|
||||
[ $this, 'print_section_bitbucket_info' ],
|
||||
'github_updater_bbserver_install_settings'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add values for individual repo add_setting_field().
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function add_repo_setting_field() {
|
||||
$setting_field['page'] = 'github_updater_bbserver_install_settings';
|
||||
$setting_field['section'] = 'bitbucket_server_id';
|
||||
$setting_field['callback_method'] = [
|
||||
Singleton::get_instance( 'Settings', $this ),
|
||||
'token_callback_checkbox',
|
||||
];
|
||||
|
||||
return $setting_field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add subtab to Settings page.
|
||||
*/
|
||||
private function add_settings_subtab() {
|
||||
add_filter(
|
||||
'github_updater_add_settings_subtabs',
|
||||
function ( $subtabs ) {
|
||||
return array_merge( $subtabs, [ 'bbserver' => esc_html__( 'Bitbucket Server', 'github-updater' ) ] );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add remote install feature, create endpoint.
|
||||
*
|
||||
* @param array $headers
|
||||
* @param array $install
|
||||
*
|
||||
* @return array $install
|
||||
*/
|
||||
public function remote_install( $headers, $install ) {
|
||||
$bitbucket_org = true;
|
||||
|
||||
if ( 'bitbucket.org' === $headers['host'] || empty( $headers['host'] ) ) {
|
||||
$base = 'https://bitbucket.org';
|
||||
$headers['host'] = 'bitbucket.org';
|
||||
} else {
|
||||
$base = $headers['base_uri'];
|
||||
$bitbucket_org = false;
|
||||
}
|
||||
|
||||
if ( ! $bitbucket_org ) {
|
||||
$install['download_link'] = "{$base}/rest/api/latest/{$headers['owner']}/repos/{$headers['repo']}/archive";
|
||||
|
||||
$install['download_link'] = add_query_arg(
|
||||
[
|
||||
'prefix' => $headers['repo'] . '/',
|
||||
'at' => $install['github_updater_branch'],
|
||||
'format' => 'zip',
|
||||
],
|
||||
$install['download_link']
|
||||
);
|
||||
|
||||
if ( isset( $install['is_private'] ) ) {
|
||||
$install['options'][ $install['repo'] ] = 1;
|
||||
}
|
||||
if ( ! empty( $install['bitbucket_username'] ) ) {
|
||||
$install['options']['bitbucket_server_username'] = $install['bitbucket_username'];
|
||||
}
|
||||
if ( ! empty( $install['bitbucket_password'] ) ) {
|
||||
$install['options']['bitbucket_server_password'] = $install['bitbucket_password'];
|
||||
}
|
||||
}
|
||||
|
||||
return $install;
|
||||
}
|
||||
}
|
||||
549
plugins/github-updater/src/GitHub_Updater/API/GitHub_API.php
Normal file
549
plugins/github-updater/src/GitHub_Updater/API/GitHub_API.php
Normal file
@@ -0,0 +1,549 @@
|
||||
<?php
|
||||
/**
|
||||
* GitHub Updater
|
||||
*
|
||||
* @author Andy Fragen
|
||||
* @license GPL-2.0+
|
||||
* @link https://github.com/afragen/github-updater
|
||||
* @package github-updater
|
||||
*/
|
||||
|
||||
namespace Fragen\GitHub_Updater\API;
|
||||
|
||||
use Fragen\Singleton;
|
||||
use Fragen\GitHub_Updater\API;
|
||||
use Fragen\GitHub_Updater\Branch;
|
||||
|
||||
/*
|
||||
* Exit if called directly.
|
||||
*/
|
||||
if ( ! defined( 'WPINC' ) ) {
|
||||
die;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class GitHub_API
|
||||
*
|
||||
* Get remote data from a GitHub repo.
|
||||
*
|
||||
* @author Andy Fragen
|
||||
*/
|
||||
class GitHub_API extends API implements API_Interface {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \stdClass $type
|
||||
*/
|
||||
public function __construct( $type ) {
|
||||
parent::__construct();
|
||||
$this->type = $type;
|
||||
$this->response = $this->get_repo_cache();
|
||||
$branch = new Branch( $this->response );
|
||||
if ( ! empty( $type->branch ) ) {
|
||||
$this->type->branch = ! empty( $branch->cache['current_branch'] )
|
||||
? $branch->cache['current_branch']
|
||||
: $type->branch;
|
||||
}
|
||||
$this->settings_hook( $this );
|
||||
$this->add_settings_subtab();
|
||||
$this->add_install_fields( $this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the remote file and parse headers.
|
||||
*
|
||||
* @param string $file Filename.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_remote_info( $file ) {
|
||||
return $this->get_remote_api_info( 'github', $file, "/repos/:owner/:repo/contents/{$file}" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get remote info for tags.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_remote_tag() {
|
||||
return $this->get_remote_api_tag( 'github', '/repos/:owner/:repo/tags' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the remote CHANGES.md file.
|
||||
*
|
||||
* @param string $changes Changelog filename.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_remote_changes( $changes ) {
|
||||
return $this->get_remote_api_changes( 'github', $changes, "/repos/:owner/:repo/contents/{$changes}" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and parse remote readme.txt.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_remote_readme() {
|
||||
$this->get_remote_api_readme( 'github', '/repos/:owner/:repo/contents/readme.txt' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the repository meta from API.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_repo_meta() {
|
||||
return $this->get_remote_api_repo_meta( 'github', '/repos/:owner/:repo' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create array of branches and download links as array.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_remote_branches() {
|
||||
return $this->get_remote_api_branches( 'github', '/repos/:owner/:repo/branches' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the GitHub release asset URL.
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
public function get_release_asset() {
|
||||
return $this->get_api_release_asset( 'github', '/repos/:owner/:repo/releases/latest' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct $this->type->download_link using Repository Contents API.
|
||||
*
|
||||
* @url http://developer.github.com/v3/repos/contents/#get-archive-link
|
||||
*
|
||||
* @param boolean $branch_switch for direct branch changing.
|
||||
*
|
||||
* @return string $endpoint
|
||||
*/
|
||||
public function construct_download_link( $branch_switch = false ) {
|
||||
self::$method = 'download_link';
|
||||
$download_link_base = $this->get_api_url( '/repos/:owner/:repo/zipball/', true );
|
||||
$endpoint = '';
|
||||
|
||||
// Release asset.
|
||||
if ( $this->type->release_asset && '0.0.0' !== $this->type->newest_tag ) {
|
||||
$release_asset = $this->get_release_asset();
|
||||
if ( property_exists( $this->type, 'is_private' ) && $this->type->is_private ) {
|
||||
return $this->get_release_asset_redirect( $release_asset, true );
|
||||
}
|
||||
return $release_asset;
|
||||
}
|
||||
|
||||
/*
|
||||
* If a branch has been given, use branch.
|
||||
* If branch is master (default) and tags are used, use newest tag.
|
||||
*/
|
||||
if ( 'master' !== $this->type->branch || empty( $this->type->tags ) ) {
|
||||
$endpoint .= $this->type->branch;
|
||||
} else {
|
||||
$endpoint .= $this->type->newest_tag;
|
||||
}
|
||||
|
||||
// Create endpoint for branch switching.
|
||||
if ( $branch_switch ) {
|
||||
$endpoint = $branch_switch;
|
||||
}
|
||||
|
||||
$endpoint = $this->add_access_token_endpoint( $this, $endpoint );
|
||||
$download_link = $download_link_base . $endpoint;
|
||||
|
||||
/**
|
||||
* Filter download link so developers can point to specific ZipFile
|
||||
* to use as a download link during a branch switch.
|
||||
*
|
||||
* @since 8.8.0
|
||||
*
|
||||
* @param string $download_link Download URL.
|
||||
* @param /stdClass $this->type Repository object.
|
||||
* @param string $branch_switch Branch or tag for rollback or branch switching.
|
||||
*/
|
||||
return apply_filters( 'github_updater_post_construct_download_link', $download_link, $this->type, $branch_switch );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create GitHub API endpoints.
|
||||
*
|
||||
* @param GitHub_API|API $git
|
||||
* @param string $endpoint
|
||||
*
|
||||
* @return string $endpoint
|
||||
*/
|
||||
public function add_endpoints( $git, $endpoint ) {
|
||||
switch ( $git::$method ) {
|
||||
case 'file':
|
||||
case 'readme':
|
||||
case 'changes':
|
||||
$endpoint = add_query_arg( 'ref', $git->type->branch, $endpoint );
|
||||
break;
|
||||
case 'meta':
|
||||
case 'tags':
|
||||
case 'download_link':
|
||||
case 'release_asset':
|
||||
case 'translation':
|
||||
break;
|
||||
case 'branches':
|
||||
$endpoint = add_query_arg( 'per_page', '100', $endpoint );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
$endpoint = $this->add_access_token_endpoint( $git, $endpoint );
|
||||
|
||||
/*
|
||||
* If GitHub Enterprise return this endpoint.
|
||||
*/
|
||||
if ( ! empty( $git->type->enterprise_api ) ) {
|
||||
return $git->type->enterprise_api . $endpoint;
|
||||
}
|
||||
|
||||
return $endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate and store time until rate limit reset.
|
||||
*
|
||||
* @param array $response HTTP headers.
|
||||
* @param string $repo Repo name.
|
||||
*/
|
||||
public static function ratelimit_reset( $response, $repo ) {
|
||||
if ( isset( $response['headers']['x-ratelimit-reset'] ) ) {
|
||||
$reset = (int) $response['headers']['x-ratelimit-reset'];
|
||||
$wait = date( 'i', $reset - time() );
|
||||
static::$error_code[ $repo ] = array_merge(
|
||||
static::$error_code[ $repo ],
|
||||
[
|
||||
'git' => 'github',
|
||||
'wait' => $wait,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse API response call and return only array of tag numbers.
|
||||
*
|
||||
* @param \stdClass|array $response Response from API call.
|
||||
*
|
||||
* @return \stdClass|array $arr Array of tag numbers, object is error.
|
||||
*/
|
||||
public function parse_tag_response( $response ) {
|
||||
if ( $this->validate_response( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$arr = [];
|
||||
array_map(
|
||||
function ( $e ) use ( &$arr ) {
|
||||
$arr[] = $e->name;
|
||||
|
||||
return $arr;
|
||||
},
|
||||
(array) $response
|
||||
);
|
||||
|
||||
return $arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse API response and return array of meta variables.
|
||||
*
|
||||
* @param \stdClass|array $response Response from API call.
|
||||
*
|
||||
* @return array $arr Array of meta variables.
|
||||
*/
|
||||
public function parse_meta_response( $response ) {
|
||||
if ( $this->validate_response( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
$arr = [];
|
||||
$response = [ $response ];
|
||||
|
||||
array_filter(
|
||||
$response,
|
||||
function ( $e ) use ( &$arr ) {
|
||||
$arr['private'] = $e->private;
|
||||
$arr['last_updated'] = $e->pushed_at;
|
||||
$arr['watchers'] = $e->watchers;
|
||||
$arr['forks'] = $e->forks;
|
||||
$arr['open_issues'] = $e->open_issues;
|
||||
}
|
||||
);
|
||||
|
||||
return $arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse API response and return array with changelog in base64.
|
||||
*
|
||||
* @param \stdClass|array $response Response from API call.
|
||||
*
|
||||
* @return array $arr Array of changes in base64.
|
||||
*/
|
||||
public function parse_changelog_response( $response ) {
|
||||
if ( $this->validate_response( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
$arr = [];
|
||||
$response = [ $response ];
|
||||
|
||||
array_filter(
|
||||
$response,
|
||||
function ( $e ) use ( &$arr ) {
|
||||
$arr['changes'] = $e->content;
|
||||
}
|
||||
);
|
||||
|
||||
return $arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse API response and return array of branch data.
|
||||
*
|
||||
* @param \stdClass $response API response.
|
||||
*
|
||||
* @return array Array of branch data.
|
||||
*/
|
||||
public function parse_branch_response( $response ) {
|
||||
if ( $this->validate_response( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
$branches = [];
|
||||
foreach ( $response as $branch ) {
|
||||
$branches[ $branch->name ]['download'] = $this->construct_download_link( $branch->name );
|
||||
$branches[ $branch->name ]['commit_hash'] = $branch->commit->sha;
|
||||
$branches[ $branch->name ]['commit_api'] = $branch->commit->url;
|
||||
}
|
||||
return $branches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse tags and create download links.
|
||||
*
|
||||
* @param \stdClass|array $response Response from API call.
|
||||
* @param array $repo_type
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function parse_tags( $response, $repo_type ) {
|
||||
$tags = [];
|
||||
$rollback = [];
|
||||
|
||||
foreach ( (array) $response as $tag ) {
|
||||
$download_base = implode(
|
||||
'/',
|
||||
[
|
||||
$repo_type['base_uri'],
|
||||
'repos',
|
||||
$this->type->owner,
|
||||
$this->type->slug,
|
||||
'zipball/',
|
||||
]
|
||||
);
|
||||
$tags[] = $tag;
|
||||
$rollback[ $tag ] = $download_base . $tag;
|
||||
}
|
||||
|
||||
return [ $tags, $rollback ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add settings for GitHub Personal Access Token.
|
||||
*
|
||||
* @param array $auth_required
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add_settings( $auth_required ) {
|
||||
add_settings_section(
|
||||
'github_access_token',
|
||||
esc_html__( 'GitHub Personal Access Token', 'github-updater' ),
|
||||
[ $this, 'print_section_github_access_token' ],
|
||||
'github_updater_github_install_settings'
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'github_access_token',
|
||||
esc_html__( 'GitHub.com Access Token', 'github-updater' ),
|
||||
[ Singleton::get_instance( 'Settings', $this ), 'token_callback_text' ],
|
||||
'github_updater_github_install_settings',
|
||||
'github_access_token',
|
||||
[
|
||||
'id' => 'github_access_token',
|
||||
'token' => true,
|
||||
]
|
||||
);
|
||||
|
||||
if ( $auth_required['github_enterprise'] ) {
|
||||
add_settings_field(
|
||||
'github_enterprise_token',
|
||||
esc_html__( 'GitHub Enterprise Access Token', 'github-updater' ),
|
||||
[ Singleton::get_instance( 'Settings', $this ), 'token_callback_text' ],
|
||||
'github_updater_github_install_settings',
|
||||
'github_access_token',
|
||||
[
|
||||
'id' => 'github_enterprise_token',
|
||||
'token' => true,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Show section for private GitHub repositories.
|
||||
*/
|
||||
if ( $auth_required['github_private'] || $auth_required['github_enterprise'] ) {
|
||||
add_settings_section(
|
||||
'github_id',
|
||||
esc_html__( 'GitHub Private Settings', 'github-updater' ),
|
||||
[ $this, 'print_section_github_info' ],
|
||||
'github_updater_github_install_settings'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add values for individual repo add_setting_field().
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function add_repo_setting_field() {
|
||||
$setting_field['page'] = 'github_updater_github_install_settings';
|
||||
$setting_field['section'] = 'github_id';
|
||||
$setting_field['callback_method'] = [
|
||||
Singleton::get_instance( 'Settings', $this ),
|
||||
'token_callback_text',
|
||||
];
|
||||
|
||||
return $setting_field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the GitHub text.
|
||||
*/
|
||||
public function print_section_github_info() {
|
||||
esc_html_e( 'Enter your GitHub Access Token. Leave empty for public repositories.', 'github-updater' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the GitHub Personal Access Token text.
|
||||
*/
|
||||
public function print_section_github_access_token() {
|
||||
esc_html_e( 'Enter your personal GitHub.com or GitHub Enterprise Access Token to avoid API access limits.', 'github-updater' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add remote install settings fields.
|
||||
*
|
||||
* @param string $type plugin|theme.
|
||||
*/
|
||||
public function add_install_settings_fields( $type ) {
|
||||
add_settings_field(
|
||||
'github_access_token',
|
||||
esc_html__( 'GitHub Access Token', 'github-updater' ),
|
||||
[ $this, 'github_access_token' ],
|
||||
'github_updater_install_' . $type,
|
||||
$type
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add subtab to Settings page.
|
||||
*/
|
||||
private function add_settings_subtab() {
|
||||
add_filter(
|
||||
'github_updater_add_settings_subtabs',
|
||||
function ( $subtabs ) {
|
||||
return array_merge( $subtabs, [ 'github' => esc_html__( 'GitHub', 'github-updater' ) ] );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* GitHub Access Token for remote install.
|
||||
*/
|
||||
public function github_access_token() {
|
||||
?>
|
||||
<label for="github_access_token">
|
||||
<input class="github_setting" type="password" style="width:50%;" id="github_access_token" name="github_access_token" value="" autocomplete="new-password">
|
||||
<br>
|
||||
<span class="description">
|
||||
<?php esc_html_e( 'Enter GitHub Access Token for private GitHub repositories.', 'github-updater' ); ?>
|
||||
</span>
|
||||
</label>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Add remote install feature, create endpoint.
|
||||
*
|
||||
* @param array $headers
|
||||
* @param array $install
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function remote_install( $headers, $install ) {
|
||||
$github_com = true;
|
||||
$options['github_access_token'] = isset( static::$options['github_access_token'] ) ? static::$options['github_access_token'] : null;
|
||||
$options['github_enterprise_token'] = isset( static::$options['github_enterprise_token'] ) ? static::$options['github_enterprise_token'] : null;
|
||||
|
||||
if ( 'github.com' === $headers['host'] || empty( $headers['host'] ) ) {
|
||||
$base = 'https://api.github.com';
|
||||
$headers['host'] = 'github.com';
|
||||
} else {
|
||||
$base = $headers['base_uri'] . '/api/v3';
|
||||
$github_com = false;
|
||||
}
|
||||
|
||||
$install['download_link'] = "{$base}/repos/{$install['github_updater_repo']}/zipball/{$install['github_updater_branch']}";
|
||||
|
||||
// If asset is entered install it.
|
||||
if ( false !== stripos( $headers['uri'], 'releases/download' ) ) {
|
||||
$install['download_link'] = $headers['uri'];
|
||||
}
|
||||
|
||||
/*
|
||||
* Add/Save access token if present.
|
||||
*/
|
||||
if ( ! empty( $install['github_access_token'] ) ) {
|
||||
$install['options'][ $install['repo'] ] = $install['github_access_token'];
|
||||
if ( $github_com ) {
|
||||
$install['options']['github_access_token'] = $install['github_access_token'];
|
||||
} else {
|
||||
$install['options']['github_enterprise_token'] = $install['github_access_token'];
|
||||
}
|
||||
}
|
||||
if ( $github_com ) {
|
||||
$token = ! empty( $install['options']['github_access_token'] )
|
||||
? $install['options']['github_access_token']
|
||||
: $options['github_access_token'];
|
||||
} else {
|
||||
$token = ! empty( $install['options']['github_enterprise_token'] )
|
||||
? $install['options']['github_enterprise_token']
|
||||
: $options['github_enterprise_token'];
|
||||
}
|
||||
|
||||
if ( ! empty( $token ) ) {
|
||||
$install['download_link'] = add_query_arg( 'access_token', $token, $install['download_link'] );
|
||||
}
|
||||
|
||||
if ( ! empty( static::$options['github_access_token'] ) ) {
|
||||
unset( $install['options']['github_access_token'] );
|
||||
}
|
||||
if ( ! empty( static::$options['github_enterprise_token'] ) ) {
|
||||
unset( $install['options']['github_enterprise_token'] );
|
||||
}
|
||||
|
||||
return $install;
|
||||
}
|
||||
}
|
||||
645
plugins/github-updater/src/GitHub_Updater/API/GitLab_API.php
Normal file
645
plugins/github-updater/src/GitHub_Updater/API/GitLab_API.php
Normal file
@@ -0,0 +1,645 @@
|
||||
<?php
|
||||
/**
|
||||
* GitHub Updater
|
||||
*
|
||||
* @author Andy Fragen
|
||||
* @license GPL-2.0+
|
||||
* @link https://github.com/afragen/github-updater
|
||||
* @package github-updater
|
||||
*/
|
||||
|
||||
namespace Fragen\GitHub_Updater\API;
|
||||
|
||||
use Fragen\Singleton;
|
||||
use Fragen\GitHub_Updater\API;
|
||||
use Fragen\GitHub_Updater\Branch;
|
||||
|
||||
/*
|
||||
* Exit if called directly.
|
||||
*/
|
||||
if ( ! defined( 'WPINC' ) ) {
|
||||
die;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class GitLab_API
|
||||
*
|
||||
* Get remote data from a GitLab repo.
|
||||
*
|
||||
* @author Andy Fragen
|
||||
*/
|
||||
class GitLab_API extends API implements API_Interface {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \stdClass $type
|
||||
*/
|
||||
public function __construct( $type ) {
|
||||
parent::__construct();
|
||||
$this->type = $type;
|
||||
$this->response = $this->get_repo_cache();
|
||||
$branch = new Branch( $this->response );
|
||||
if ( ! empty( $type->branch ) ) {
|
||||
$this->type->branch = ! empty( $branch->cache['current_branch'] )
|
||||
? $branch->cache['current_branch']
|
||||
: $type->branch;
|
||||
}
|
||||
$this->set_default_credentials();
|
||||
$this->settings_hook( $this );
|
||||
$this->add_settings_subtab();
|
||||
$this->add_install_fields( $this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default credentials if option not set.
|
||||
*/
|
||||
protected function set_default_credentials() {
|
||||
$running_servers = Singleton::get_instance( 'Base', $this )->get_running_git_servers();
|
||||
$set_credentials = false;
|
||||
if ( ! isset( static::$options['gitlab_access_token'] ) ) {
|
||||
static::$options['gitlab_access_token'] = null;
|
||||
$set_credentials = true;
|
||||
}
|
||||
if ( ! isset( static::$options['gitlab_enterprise_token'] ) ) {
|
||||
static::$options['gitlab_enterprise_token'] = null;
|
||||
$set_credentials = true;
|
||||
}
|
||||
if ( ( empty( static::$options['gitlab_enterprise_token'] ) &&
|
||||
in_array( 'gitlabce', $running_servers, true ) ) ||
|
||||
( empty( static::$options['gitlab_access_token'] ) &&
|
||||
in_array( 'gitlab', $running_servers, true ) )
|
||||
) {
|
||||
$this->gitlab_error_notices();
|
||||
}
|
||||
if ( $set_credentials ) {
|
||||
add_site_option( 'github_updater', static::$options );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the remote file and parse headers.
|
||||
*
|
||||
* @param string $file Filename.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_remote_info( $file ) {
|
||||
$id = $this->get_gitlab_id();
|
||||
return $this->get_remote_api_info( 'gitlab', $file, "/projects/{$id}/repository/files/{$file}" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get remote info for tags.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_remote_tag() {
|
||||
$id = $this->get_gitlab_id();
|
||||
return $this->get_remote_api_tag( 'gitlab', "/projects/{$id}/repository/tags" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the remote CHANGES.md file.
|
||||
*
|
||||
* @param string $changes Changelog filename.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_remote_changes( $changes ) {
|
||||
$id = $this->get_gitlab_id();
|
||||
return $this->get_remote_api_changes( 'gitlab', $changes, "/projects/{$id}/repository/files/{$changes}" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and parse remote readme.txt.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_remote_readme() {
|
||||
$id = $this->get_gitlab_id();
|
||||
return $this->get_remote_api_readme( 'gitlab', "/projects/{$id}/repository/files/readme.txt" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the repository meta from API.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_repo_meta() {
|
||||
$response = isset( $this->response['meta'] ) ? $this->response['meta'] : false;
|
||||
|
||||
if ( ! $response ) {
|
||||
self::$method = 'meta';
|
||||
$project = isset( $this->response['project'] ) ? $this->response['project'] : false;
|
||||
|
||||
// exit if transient is empty.
|
||||
if ( ! $project ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$response = ( $this->type->slug === $project->path ) ? $project : false;
|
||||
|
||||
if ( $response ) {
|
||||
$response = $this->parse_meta_response( $response );
|
||||
$this->set_repo_cache( 'meta', $response );
|
||||
$this->set_repo_cache( 'project', null );
|
||||
}
|
||||
}
|
||||
|
||||
if ( $this->validate_response( $response ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->type->repo_meta = $response;
|
||||
$this->add_meta_repo_object();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create array of branches and download links as array.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_remote_branches() {
|
||||
$id = $this->get_gitlab_id();
|
||||
return $this->get_remote_api_branches( 'gitlab', "/projects/{$id}/repository/branches" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get GitLab release asset download link.
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
public function get_release_asset() {
|
||||
return $this->get_api_release_asset( 'gitlab', "/projects/{$this->response['project_id']}/jobs/artifacts/{$this->type->newest_tag}/download" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct $this->type->download_link using GitLab API v4.
|
||||
*
|
||||
* @param boolean $branch_switch for direct branch changing.
|
||||
*
|
||||
* @return string $endpoint
|
||||
*/
|
||||
public function construct_download_link( $branch_switch = false ) {
|
||||
self::$method = 'download_link';
|
||||
$download_link_base = $this->get_api_url( "/projects/{$this->get_gitlab_id()}/repository/archive.zip" );
|
||||
$download_link_base = remove_query_arg( 'private_token', $download_link_base );
|
||||
|
||||
$endpoint = '';
|
||||
$endpoint = add_query_arg( 'sha', $this->type->branch, $endpoint );
|
||||
|
||||
// Release asset.
|
||||
if ( $this->type->ci_job && '0.0.0' !== $this->type->newest_tag ) {
|
||||
$release_asset = $this->get_release_asset();
|
||||
return $release_asset;
|
||||
}
|
||||
|
||||
// If branch is master (default) and tags are used, use newest tag.
|
||||
if ( 'master' === $this->type->branch && ! empty( $this->type->tags ) ) {
|
||||
$endpoint = add_query_arg( 'sha', $this->type->newest_tag, $endpoint );
|
||||
}
|
||||
|
||||
// Create endpoint for branch switching.
|
||||
if ( $branch_switch ) {
|
||||
$endpoint = add_query_arg( 'sha', $branch_switch, $endpoint );
|
||||
}
|
||||
|
||||
$endpoint = $this->add_access_token_endpoint( $this, $endpoint );
|
||||
$download_link = $download_link_base . $endpoint;
|
||||
|
||||
/**
|
||||
* Filter download link so developers can point to specific ZipFile
|
||||
* to use as a download link during a branch switch.
|
||||
*
|
||||
* @since 8.8.0
|
||||
*
|
||||
* @param string $download_link Download URL.
|
||||
* @param /stdClass $this->type Repository object.
|
||||
* @param string $branch_switch Branch or tag for rollback or branch switching.
|
||||
*/
|
||||
return apply_filters( 'github_updater_post_construct_download_link', $download_link, $this->type, $branch_switch );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create GitLab API endpoints.
|
||||
*
|
||||
* @param GitLab_API|API $git
|
||||
* @param string $endpoint
|
||||
*
|
||||
* @return string $endpoint
|
||||
*/
|
||||
public function add_endpoints( $git, $endpoint ) {
|
||||
switch ( $git::$method ) {
|
||||
case 'projects':
|
||||
$endpoint = add_query_arg( 'per_page', '100', $endpoint );
|
||||
break;
|
||||
case 'meta':
|
||||
case 'tags':
|
||||
case 'branches':
|
||||
case 'download_link':
|
||||
break;
|
||||
case 'file':
|
||||
case 'changes':
|
||||
case 'readme':
|
||||
$endpoint = add_query_arg( 'ref', $git->type->branch, $endpoint );
|
||||
break;
|
||||
case 'translation':
|
||||
$endpoint = add_query_arg( 'ref', 'master', $endpoint );
|
||||
break;
|
||||
case 'release_asset':
|
||||
$endpoint = add_query_arg( 'job', $git->type->ci_job, $endpoint );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
$endpoint = $this->add_access_token_endpoint( $git, $endpoint );
|
||||
|
||||
/*
|
||||
* If GitLab CE/Enterprise return this endpoint.
|
||||
*/
|
||||
if ( ! empty( $git->type->enterprise_api ) ) {
|
||||
return $git->type->enterprise_api . $endpoint;
|
||||
}
|
||||
|
||||
return $endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get GitLab project ID and project meta.
|
||||
*
|
||||
* @return string|int
|
||||
*/
|
||||
public function get_gitlab_id() {
|
||||
$id = null;
|
||||
$response = isset( $this->response['project_id'] ) ? $this->response['project_id'] : false;
|
||||
|
||||
if ( ! $response ) {
|
||||
self::$method = 'projects';
|
||||
$id = implode( '/', [ $this->type->owner, $this->type->slug ] );
|
||||
$id = rawurlencode( $id );
|
||||
$response = $this->api( '/projects/' . $id );
|
||||
|
||||
if ( $this->validate_response( $response ) ) {
|
||||
return $id;
|
||||
}
|
||||
|
||||
if ( $response && $this->type->slug === $response->path ) {
|
||||
$id = $response->id;
|
||||
$this->set_repo_cache( 'project_id', $id );
|
||||
$this->set_repo_cache( 'project', $response );
|
||||
}
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse API response call and return only array of tag numbers.
|
||||
*
|
||||
* @param \stdClass|array $response Response from API call for tags.
|
||||
*
|
||||
* @return \stdClass|array Array of tag numbers, object is error.
|
||||
*/
|
||||
public function parse_tag_response( $response ) {
|
||||
if ( $this->validate_response( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$arr = [];
|
||||
array_map(
|
||||
function ( $e ) use ( &$arr ) {
|
||||
$arr[] = $e->name;
|
||||
|
||||
return $arr;
|
||||
},
|
||||
(array) $response
|
||||
);
|
||||
|
||||
return $arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse API response and return array of meta variables.
|
||||
*
|
||||
* @param \stdClass|array $response Response from API call.
|
||||
*
|
||||
* @return array $arr Array of meta variables.
|
||||
*/
|
||||
public function parse_meta_response( $response ) {
|
||||
if ( $this->validate_response( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
$arr = [];
|
||||
$response = [ $response ];
|
||||
|
||||
array_filter(
|
||||
$response,
|
||||
function ( $e ) use ( &$arr ) {
|
||||
$arr['private'] = isset( $e->visibility ) && 'private' === $e->visibility ? true : false;
|
||||
$arr['private'] = isset( $e->public ) ? ! $e->public : $arr['private'];
|
||||
$arr['last_updated'] = $e->last_activity_at;
|
||||
$arr['watchers'] = 0;
|
||||
$arr['forks'] = $e->forks_count;
|
||||
$arr['open_issues'] = isset( $e->open_issues_count ) ? $e->open_issues_count : 0;
|
||||
}
|
||||
);
|
||||
|
||||
return $arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse API response and return array with changelog in base64.
|
||||
*
|
||||
* @param \stdClass|array $response Response from API call.
|
||||
*
|
||||
* @return array|\stdClass $arr Array of changes in base64, object if error.
|
||||
*/
|
||||
public function parse_changelog_response( $response ) {
|
||||
if ( $this->validate_response( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$arr = [];
|
||||
$response = [ $response ];
|
||||
|
||||
array_filter(
|
||||
$response,
|
||||
function ( $e ) use ( &$arr ) {
|
||||
$arr['changes'] = $e->content;
|
||||
}
|
||||
);
|
||||
|
||||
return $arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse API response and return array of branch data.
|
||||
*
|
||||
* @param \stdClass $response API response.
|
||||
*
|
||||
* @return array Array of branch data.
|
||||
*/
|
||||
public function parse_branch_response( $response ) {
|
||||
if ( $this->validate_response( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
$branches = [];
|
||||
foreach ( $response as $branch ) {
|
||||
$branches[ $branch->name ]['download'] = $this->construct_download_link( $branch->name );
|
||||
$branches[ $branch->name ]['commit_hash'] = $branch->commit->id;
|
||||
$branches[ $branch->name ]['commit_timestamp'] = $branch->commit->committed_date;
|
||||
}
|
||||
return $branches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse tags and create download links.
|
||||
*
|
||||
* @param \stdClass|array $response Response from API call.
|
||||
* @param array $repo_type
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function parse_tags( $response, $repo_type ) {
|
||||
$tags = [];
|
||||
$rollback = [];
|
||||
|
||||
foreach ( (array) $response as $tag ) {
|
||||
$download_link = "/projects/{$this->get_gitlab_id()}/repository/archive.zip";
|
||||
$download_link = $this->get_api_url( $download_link );
|
||||
$download_link = add_query_arg( 'sha', $tag, $download_link );
|
||||
$tags[] = $tag;
|
||||
$rollback[ $tag ] = $download_link;
|
||||
}
|
||||
|
||||
return [ $tags, $rollback ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add settings for GitLab.com, GitLab Community Edition.
|
||||
* or GitLab Enterprise Access Token.
|
||||
*
|
||||
* @param array $auth_required
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add_settings( $auth_required ) {
|
||||
if ( $auth_required['gitlab'] || $auth_required['gitlab_enterprise'] ) {
|
||||
add_settings_section(
|
||||
'gitlab_settings',
|
||||
esc_html__( 'GitLab Personal Access Token', 'github-updater' ),
|
||||
[ $this, 'print_section_gitlab_token' ],
|
||||
'github_updater_gitlab_install_settings'
|
||||
);
|
||||
}
|
||||
|
||||
if ( $auth_required['gitlab_private'] ) {
|
||||
add_settings_section(
|
||||
'gitlab_id',
|
||||
esc_html__( 'GitLab Private Settings', 'github-updater' ),
|
||||
[ $this, 'print_section_gitlab_info' ],
|
||||
'github_updater_gitlab_install_settings'
|
||||
);
|
||||
}
|
||||
|
||||
if ( $auth_required['gitlab'] ) {
|
||||
add_settings_field(
|
||||
'gitlab_access_token',
|
||||
esc_html__( 'GitLab.com Access Token', 'github-updater' ),
|
||||
[ Singleton::get_instance( 'Settings', $this ), 'token_callback_text' ],
|
||||
'github_updater_gitlab_install_settings',
|
||||
'gitlab_settings',
|
||||
[
|
||||
'id' => 'gitlab_access_token',
|
||||
'token' => true,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
if ( $auth_required['gitlab_enterprise'] ) {
|
||||
add_settings_field(
|
||||
'gitlab_enterprise_token',
|
||||
esc_html__( 'GitLab CE or GitLab Enterprise Personal Access Token', 'github-updater' ),
|
||||
[ Singleton::get_instance( 'Settings', $this ), 'token_callback_text' ],
|
||||
'github_updater_gitlab_install_settings',
|
||||
'gitlab_settings',
|
||||
[
|
||||
'id' => 'gitlab_enterprise_token',
|
||||
'token' => true,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add values for individual repo add_setting_field().
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function add_repo_setting_field() {
|
||||
$setting_field['page'] = 'github_updater_gitlab_install_settings';
|
||||
$setting_field['section'] = 'gitlab_id';
|
||||
$setting_field['callback_method'] = [
|
||||
Singleton::get_instance( 'Settings', $this ),
|
||||
'token_callback_text',
|
||||
];
|
||||
|
||||
return $setting_field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add subtab to Settings page.
|
||||
*/
|
||||
private function add_settings_subtab() {
|
||||
add_filter(
|
||||
'github_updater_add_settings_subtabs',
|
||||
function ( $subtabs ) {
|
||||
return array_merge( $subtabs, [ 'gitlab' => esc_html__( 'GitLab', 'github-updater' ) ] );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the GitLab Settings text.
|
||||
*/
|
||||
public function print_section_gitlab_info() {
|
||||
esc_html_e( 'Enter your repository specific GitLab Access Token.', 'github-updater' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the GitLab Access Token Settings text.
|
||||
*/
|
||||
public function print_section_gitlab_token() {
|
||||
esc_html_e( 'Enter your GitLab.com, GitLab CE, or GitLab Enterprise Access Token.', 'github-updater' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add remote install settings fields.
|
||||
*
|
||||
* @param string $type
|
||||
*/
|
||||
public function add_install_settings_fields( $type ) {
|
||||
add_settings_field(
|
||||
'gitlab_access_token',
|
||||
esc_html__( 'GitLab Access Token', 'github-updater' ),
|
||||
[ $this, 'gitlab_access_token' ],
|
||||
'github_updater_install_' . $type,
|
||||
$type
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* GitLab Access Token for remote install.
|
||||
*/
|
||||
public function gitlab_access_token() {
|
||||
?>
|
||||
<label for="gitlab_access_token">
|
||||
<input class="gitlab_setting" type="password" style="width:50%;" id="gitlab_access_token" name="gitlab_access_token" value="" autocomplete="new-password">
|
||||
<br>
|
||||
<span class="description">
|
||||
<?php esc_html_e( 'Enter GitLab Access Token for private GitLab repositories.', 'github-updater' ); ?>
|
||||
</span>
|
||||
</label>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Display GitLab error admin notices.
|
||||
*/
|
||||
public function gitlab_error_notices() {
|
||||
add_action( is_multisite() ? 'network_admin_notices' : 'admin_notices', [ $this, 'gitlab_error' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate error message for missing GitLab Private Token.
|
||||
*/
|
||||
public function gitlab_error() {
|
||||
$auth_required = $this->get_class_vars( 'Settings', 'auth_required' );
|
||||
$error_code = $this->get_error_codes();
|
||||
|
||||
if ( ! isset( $error_code['gitlab'] ) &&
|
||||
( ( empty( static::$options['gitlab_enterprise_token'] ) &&
|
||||
$auth_required['gitlab_enterprise'] ) ||
|
||||
( empty( static::$options['gitlab_access_token'] ) &&
|
||||
$auth_required['gitlab'] ) )
|
||||
) {
|
||||
self::$error_code['gitlab'] = [ 'error' => true ];
|
||||
if ( ! \PAnD::is_admin_notice_active( 'gitlab-error-1' ) ) {
|
||||
return;
|
||||
}
|
||||
?>
|
||||
<div data-dismissible="gitlab-error-1" class="error notice is-dismissible">
|
||||
<p>
|
||||
<?php esc_html_e( 'You must set a GitLab.com, GitLab CE, or GitLab Enterprise Access Token.', 'github-updater' ); ?>
|
||||
</p>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add remote install feature, create endpoint.
|
||||
*
|
||||
* @param array $headers
|
||||
* @param array $install
|
||||
*
|
||||
* @return mixed $install
|
||||
*/
|
||||
public function remote_install( $headers, $install ) {
|
||||
$gitlab_com = true;
|
||||
$options['gitlab_access_token'] = isset( static::$options['gitlab_access_token'] ) ? static::$options['gitlab_access_token'] : null;
|
||||
$options['gitlab_enterprise_token'] = isset( static::$options['gitlab_enterprise_token'] ) ? static::$options['gitlab_enterprise_token'] : null;
|
||||
|
||||
if ( 'gitlab.com' === $headers['host'] || empty( $headers['host'] ) ) {
|
||||
$base = 'https://gitlab.com';
|
||||
$headers['host'] = 'gitlab.com';
|
||||
} else {
|
||||
$base = $headers['base_uri'];
|
||||
$gitlab_com = false;
|
||||
}
|
||||
|
||||
$id = rawurlencode( $install['github_updater_repo'] );
|
||||
$install['download_link'] = "{$base}/api/v4/projects/{$id}/repository/archive.zip";
|
||||
$install['download_link'] = add_query_arg( 'sha', $install['github_updater_branch'], $install['download_link'] );
|
||||
|
||||
/*
|
||||
* Add/Save access token if present.
|
||||
*/
|
||||
if ( ! empty( $install['gitlab_access_token'] ) ) {
|
||||
$install['options'][ $install['repo'] ] = $install['gitlab_access_token'];
|
||||
if ( $gitlab_com ) {
|
||||
$install['options']['gitlab_access_token'] = $install['gitlab_access_token'];
|
||||
} else {
|
||||
$install['options']['gitlab_enterprise_token'] = $install['gitlab_access_token'];
|
||||
}
|
||||
}
|
||||
if ( $gitlab_com ) {
|
||||
$token = ! empty( $install['options']['gitlab_access_token'] )
|
||||
? $install['options']['gitlab_access_token']
|
||||
: $options['gitlab_access_token'];
|
||||
} else {
|
||||
$token = ! empty( $install['options']['gitlab_enterprise_token'] )
|
||||
? $install['options']['gitlab_enterprise_token']
|
||||
: $options['gitlab_enterprise_token'];
|
||||
}
|
||||
|
||||
if ( ! empty( $token ) ) {
|
||||
$install['download_link'] = add_query_arg( 'private_token', $token, $install['download_link'] );
|
||||
}
|
||||
|
||||
if ( ! empty( static::$options['gitlab_access_token'] ) ) {
|
||||
unset( $install['options']['gitlab_access_token'] );
|
||||
}
|
||||
if ( ! empty( static::$options['gitlab_enterprise_token'] ) ) {
|
||||
unset( $install['options']['gitlab_enterprise_token'] );
|
||||
}
|
||||
|
||||
return $install;
|
||||
}
|
||||
}
|
||||
514
plugins/github-updater/src/GitHub_Updater/API/Gitea_API.php
Normal file
514
plugins/github-updater/src/GitHub_Updater/API/Gitea_API.php
Normal file
@@ -0,0 +1,514 @@
|
||||
<?php
|
||||
/**
|
||||
* GitHub Updater
|
||||
*
|
||||
* @author Andy Fragen
|
||||
* @license GPL-2.0+
|
||||
* @link https://github.com/afragen/github-updater
|
||||
* @package github-updater
|
||||
*/
|
||||
|
||||
namespace Fragen\GitHub_Updater\API;
|
||||
|
||||
use Fragen\Singleton;
|
||||
use Fragen\GitHub_Updater\API;
|
||||
use Fragen\GitHub_Updater\Branch;
|
||||
use Fragen\GitHub_Updater\Traits\GHU_Trait;
|
||||
|
||||
/*
|
||||
* Exit if called directly.
|
||||
*/
|
||||
if ( ! defined( 'WPINC' ) ) {
|
||||
die;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Gitea_API
|
||||
*
|
||||
* Get remote data from a Gitea repo.
|
||||
*
|
||||
* @author Andy Fragen
|
||||
* @author Marco Betschart
|
||||
*/
|
||||
class Gitea_API extends API implements API_Interface {
|
||||
use GHU_Trait;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \stdClass $type
|
||||
*/
|
||||
public function __construct( $type ) {
|
||||
parent::__construct();
|
||||
$this->type = $type;
|
||||
$this->response = $this->get_repo_cache();
|
||||
$branch = new Branch( $this->response );
|
||||
if ( ! empty( $type->branch ) ) {
|
||||
$this->type->branch = ! empty( $branch->cache['current_branch'] )
|
||||
? $branch->cache['current_branch']
|
||||
: $type->branch;
|
||||
}
|
||||
$this->set_default_credentials();
|
||||
$this->settings_hook( $this );
|
||||
$this->add_settings_subtab();
|
||||
$this->add_install_fields( $this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default credentials if option not set.
|
||||
*/
|
||||
protected function set_default_credentials() {
|
||||
$running_servers = Singleton::get_instance( 'Base', $this )->get_running_git_servers();
|
||||
$set_credentials = false;
|
||||
if ( ! isset( static::$options['gitea_access_token'] ) ) {
|
||||
static::$options['gitea_access_token'] = null;
|
||||
$set_credentials = true;
|
||||
}
|
||||
if ( empty( static::$options['gitea_access_token'] ) &&
|
||||
in_array( 'gitea', $running_servers, true )
|
||||
) {
|
||||
$this->gitea_error_notices();
|
||||
}
|
||||
|
||||
if ( $set_credentials ) {
|
||||
add_site_option( 'github_updater', static::$options );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the remote file and parse headers.
|
||||
*
|
||||
* @param string $file Filename.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_remote_info( $file ) {
|
||||
return $this->get_remote_api_info( 'gitea', $file, "/repos/:owner/:repo/raw/:branch/{$file}" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get remote info for tags.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_remote_tag() {
|
||||
return $this->get_remote_api_tag( 'gitea', '/repos/:owner/:repo/releases' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the remote CHANGES.md file.
|
||||
*
|
||||
* @param string $changes Changelog filename.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_remote_changes( $changes ) {
|
||||
return $this->get_remote_api_changes( 'gitea', $changes, "/repos/:owner/:repo/raw/:branch/{$changes}" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and parse remote readme.txt.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_remote_readme() {
|
||||
return $this->get_remote_api_readme( 'gitea', '/repos/:owner/:repo/raw/:branch/readme.txt' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the repository meta from API.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_repo_meta() {
|
||||
return $this->get_remote_api_repo_meta( 'gitea', '/repos/:owner/:repo' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create array of branches and download links as array.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_remote_branches() {
|
||||
return $this->get_remote_api_branches( 'gitea', '/repos/:owner/:repo/branches' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Gitea release asset.
|
||||
*
|
||||
* @return false
|
||||
*/
|
||||
public function get_release_asset() {
|
||||
// TODO: eventually figure this out.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct $this->type->download_link using Gitea API.
|
||||
*
|
||||
* @param boolean $branch_switch for direct branch changing.
|
||||
*
|
||||
* @return string $endpoint
|
||||
*/
|
||||
public function construct_download_link( $branch_switch = false ) {
|
||||
self::$method = 'download_link';
|
||||
$download_link_base = $this->get_api_url( '/repos/:owner/:repo/archive/', true );
|
||||
$endpoint = '';
|
||||
|
||||
/*
|
||||
* If a branch has been given, use branch.
|
||||
* If branch is master (default) and tags are used, use newest tag.
|
||||
*/
|
||||
if ( 'master' !== $this->type->branch || empty( $this->type->tags ) ) {
|
||||
$endpoint .= $this->type->branch . '.zip';
|
||||
} else {
|
||||
$endpoint .= $this->type->newest_tag . '.zip';
|
||||
}
|
||||
|
||||
// Create endpoint for branch switching.
|
||||
if ( $branch_switch ) {
|
||||
$endpoint = $branch_switch . '.zip';
|
||||
}
|
||||
|
||||
$endpoint = $this->add_access_token_endpoint( $this, $endpoint );
|
||||
$download_link = $download_link_base . $endpoint;
|
||||
|
||||
/**
|
||||
* Filter download link so developers can point to specific ZipFile
|
||||
* to use as a download link during a branch switch.
|
||||
*
|
||||
* @since 8.8.0
|
||||
*
|
||||
* @param string $download_link Download URL.
|
||||
* @param /stdClass $this->type Repository object.
|
||||
* @param string $branch_switch Branch or tag for rollback or branch switching.
|
||||
*/
|
||||
return apply_filters( 'github_updater_post_construct_download_link', $download_link, $this->type, $branch_switch );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Gitea API endpoints.
|
||||
*
|
||||
* @param Gitea_API|API $git
|
||||
* @param string $endpoint
|
||||
*
|
||||
* @return string $endpoint
|
||||
*/
|
||||
public function add_endpoints( $git, $endpoint ) {
|
||||
switch ( $git::$method ) {
|
||||
case 'file':
|
||||
case 'readme':
|
||||
case 'meta':
|
||||
case 'tags':
|
||||
case 'changes':
|
||||
case 'translation':
|
||||
case 'download_link':
|
||||
break;
|
||||
case 'branches':
|
||||
$endpoint = add_query_arg( 'per_page', '100', $endpoint );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
$endpoint = $this->add_access_token_endpoint( $git, $endpoint );
|
||||
|
||||
return $endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse API response call and return only array of tag numbers.
|
||||
*
|
||||
* @param \stdClass|array $response Response from API call for tags.
|
||||
*
|
||||
* @return \stdClass|array Array of tag numbers, object is error.
|
||||
*/
|
||||
public function parse_tag_response( $response ) {
|
||||
if ( $this->validate_response( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$arr = [];
|
||||
array_map(
|
||||
function ( $e ) use ( &$arr ) {
|
||||
$arr[] = $e->tag_name;
|
||||
|
||||
return $arr;
|
||||
},
|
||||
(array) $response
|
||||
);
|
||||
|
||||
return $arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse API response and return array of meta variables.
|
||||
*
|
||||
* @param \stdClass|array $response Response from API call.
|
||||
*
|
||||
* @return array $arr Array of meta variables.
|
||||
*/
|
||||
public function parse_meta_response( $response ) {
|
||||
if ( $this->validate_response( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
$arr = [];
|
||||
$response = [ $response ];
|
||||
|
||||
array_filter(
|
||||
$response,
|
||||
function ( $e ) use ( &$arr ) {
|
||||
$arr['private'] = $e->private;
|
||||
$arr['last_updated'] = $e->updated_at;
|
||||
$arr['watchers'] = $e->watchers_count;
|
||||
$arr['forks'] = $e->forks_count;
|
||||
$arr['open_issues'] = isset( $e->open_issues_count ) ? $e->open_issues_count : 0;
|
||||
}
|
||||
);
|
||||
|
||||
return $arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse API response and return array with changelog in base64.
|
||||
*
|
||||
* @param \stdClass|array $response Response from API call.
|
||||
*
|
||||
* @return array|\stdClass $arr Array of changes in base64, object if error.
|
||||
*/
|
||||
public function parse_changelog_response( $response ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse API response and return array of branch data.
|
||||
*
|
||||
* @param \stdClass $response API response.
|
||||
*
|
||||
* @return array Array of branch data.
|
||||
*/
|
||||
public function parse_branch_response( $response ) {
|
||||
if ( $this->validate_response( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
$branches = [];
|
||||
foreach ( $response as $branch ) {
|
||||
$branches[ $branch->name ]['download'] = $this->construct_download_link( $branch->name );
|
||||
$branches[ $branch->name ]['commit_hash'] = $branch->commit->id;
|
||||
$branches[ $branch->name ]['commit_timestamp'] = $branch->commit->timestamp;
|
||||
}
|
||||
return $branches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse tags and create download links.
|
||||
*
|
||||
* @param \stdClass|array $response Response from API call.
|
||||
* @param array $repo_type
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function parse_tags( $response, $repo_type ) {
|
||||
$tags = [];
|
||||
$rollback = [];
|
||||
|
||||
foreach ( (array) $response as $tag ) {
|
||||
$download_link = implode(
|
||||
'/',
|
||||
[
|
||||
$repo_type['base_uri'],
|
||||
'repos',
|
||||
$this->type->owner,
|
||||
$this->type->slug,
|
||||
'archive/',
|
||||
]
|
||||
);
|
||||
$tags[] = $tag;
|
||||
$rollback[ $tag ] = $download_link . $tag . '.zip';
|
||||
}
|
||||
|
||||
return [ $tags, $rollback ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add settings for Gitea Access Token.
|
||||
*
|
||||
* @param array $auth_required
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add_settings( $auth_required ) {
|
||||
if ( $auth_required['gitea'] ) {
|
||||
add_settings_section(
|
||||
'gitea_settings',
|
||||
esc_html__( 'Gitea Access Token', 'github-updater' ),
|
||||
[ $this, 'print_section_gitea_token' ],
|
||||
'github_updater_gitea_install_settings'
|
||||
);
|
||||
}
|
||||
|
||||
if ( $auth_required['gitea_private'] ) {
|
||||
add_settings_section(
|
||||
'gitea_id',
|
||||
esc_html__( 'Gitea Private Settings', 'github-updater' ),
|
||||
[ $this, 'print_section_gitea_info' ],
|
||||
'github_updater_gitea_install_settings'
|
||||
);
|
||||
}
|
||||
|
||||
if ( $auth_required['gitea'] ) {
|
||||
add_settings_field(
|
||||
'gitea_access_token',
|
||||
esc_html__( 'Gitea Access Token', 'github-updater' ),
|
||||
[ Singleton::get_instance( 'Settings', $this ), 'token_callback_text' ],
|
||||
'github_updater_gitea_install_settings',
|
||||
'gitea_settings',
|
||||
[
|
||||
'id' => 'gitea_access_token',
|
||||
'token' => true,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add values for individual repo add_setting_field().
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function add_repo_setting_field() {
|
||||
$setting_field['page'] = 'github_updater_gitea_install_settings';
|
||||
$setting_field['section'] = 'gitea_id';
|
||||
$setting_field['callback_method'] = [
|
||||
Singleton::get_instance( 'Settings', $this ),
|
||||
'token_callback_text',
|
||||
];
|
||||
|
||||
return $setting_field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add subtab to Settings page.
|
||||
*/
|
||||
private function add_settings_subtab() {
|
||||
add_filter(
|
||||
'github_updater_add_settings_subtabs',
|
||||
function ( $subtabs ) {
|
||||
return array_merge( $subtabs, [ 'gitea' => esc_html__( 'Gitea', 'github-updater' ) ] );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the Gitea Settings text.
|
||||
*/
|
||||
public function print_section_gitea_info() {
|
||||
esc_html_e( 'Enter your repository specific Gitea Access Token.', 'github-updater' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the Gitea Access Token Settings text.
|
||||
*/
|
||||
public function print_section_gitea_token() {
|
||||
esc_html_e( 'Enter your Gitea Access Token.', 'github-updater' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add remote install settings fields.
|
||||
*
|
||||
* @param string $type
|
||||
*/
|
||||
public function add_install_settings_fields( $type ) {
|
||||
add_settings_field(
|
||||
'gitea_access_token',
|
||||
esc_html__( 'Gitea Access Token', 'github-updater' ),
|
||||
[ $this, 'gitea_access_token' ],
|
||||
'github_updater_install_' . $type,
|
||||
$type
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gitea Access Token for remote install.
|
||||
*/
|
||||
public function gitea_access_token() {
|
||||
?>
|
||||
<label for="gitea_access_token">
|
||||
<input class="gitea_setting" type="password" style="width:50%;" id="gitea_access_token" name="gitea_access_token" value="" autocomplete="new-password">
|
||||
<br>
|
||||
<span class="description">
|
||||
<?php esc_html_e( 'Enter Gitea Access Token for private Gitea repositories.', 'github-updater' ); ?>
|
||||
</span>
|
||||
</label>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Display Gitea error admin notices.
|
||||
*/
|
||||
public function gitea_error_notices() {
|
||||
add_action( is_multisite() ? 'network_admin_notices' : 'admin_notices', [ $this, 'gitea_error' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate error message for missing Gitea Access Token.
|
||||
*/
|
||||
public function gitea_error() {
|
||||
$auth_required = $this->get_class_vars( 'Settings', 'auth_required' );
|
||||
$error_code = $this->get_error_codes();
|
||||
|
||||
if ( ! isset( $error_code['gitea'] ) &&
|
||||
empty( static::$options['gitea_access_token'] ) &&
|
||||
$auth_required['gitea']
|
||||
) {
|
||||
self::$error_code['gitea'] = [ 'error' => true ];
|
||||
if ( ! \PAnD::is_admin_notice_active( 'gitea-error-1' ) ) {
|
||||
return;
|
||||
}
|
||||
?>
|
||||
<div data-dismissible="gitea-error-1" class="error notice is-dismissible">
|
||||
<p>
|
||||
<?php esc_html_e( 'You must set a Gitea Access Token.', 'github-updater' ); ?>
|
||||
</p>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add remote install feature, create endpoint.
|
||||
*
|
||||
* @param array $headers
|
||||
* @param array $install
|
||||
*
|
||||
* @return mixed $install
|
||||
*/
|
||||
public function remote_install( $headers, $install ) {
|
||||
$options['gitea_access_token'] = isset( static::$options['gitea_access_token'] ) ? static::$options['gitea_access_token'] : null;
|
||||
|
||||
$base = $headers['base_uri'] . '/api/v1';
|
||||
|
||||
$install['download_link'] = "{$base}/repos/{$install['github_updater_repo']}/archive/{$install['github_updater_branch']}.zip";
|
||||
|
||||
/*
|
||||
* Add/Save access token if present.
|
||||
*/
|
||||
if ( ! empty( $install['gitea_access_token'] ) ) {
|
||||
$install['options'][ $install['repo'] ] = $install['gitea_access_token'];
|
||||
$install['options']['gitea_access_token'] = $install['gitea_access_token'];
|
||||
}
|
||||
|
||||
$token = ! empty( $install['options']['gitea_access_token'] )
|
||||
? $install['options']['gitea_access_token']
|
||||
: $options['gitea_access_token'];
|
||||
|
||||
if ( ! empty( $token ) ) {
|
||||
$install['download_link'] = add_query_arg( 'access_token', $token, $install['download_link'] );
|
||||
}
|
||||
|
||||
if ( ! empty( static::$options['gitea_access_token'] ) ) {
|
||||
unset( $install['options']['gitea_access_token'] );
|
||||
}
|
||||
|
||||
return $install;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
/**
|
||||
* GitHub Updater
|
||||
*
|
||||
* @author Andy Fragen
|
||||
* @license GPL-2.0+
|
||||
* @link https://github.com/afragen/github-updater
|
||||
* @package github-updater
|
||||
*/
|
||||
|
||||
namespace Fragen\GitHub_Updater\API;
|
||||
|
||||
use Fragen\GitHub_Updater\API;
|
||||
use Fragen\GitHub_Updater\Traits\GHU_Trait;
|
||||
|
||||
/**
|
||||
* Class Language_Pack_API
|
||||
*/
|
||||
class Language_Pack_API extends API {
|
||||
use GHU_Trait;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \stdClass $type
|
||||
*/
|
||||
public function __construct( $type ) {
|
||||
parent::__construct();
|
||||
self::$method = 'translation';
|
||||
$this->type = $type;
|
||||
$this->response = $this->get_repo_cache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get/process Language Packs.
|
||||
*
|
||||
* @param array $headers Array of headers of Language Pack.
|
||||
*
|
||||
* @return bool When invalid response.
|
||||
*/
|
||||
public function get_language_pack( $headers ) {
|
||||
$response = ! empty( $this->response['languages'] ) ? $this->response['languages'] : false;
|
||||
|
||||
if ( ! $response ) {
|
||||
$response = $this->get_language_pack_json( $this->type->git, $headers, $response );
|
||||
|
||||
if ( $response ) {
|
||||
foreach ( $response as $locale ) {
|
||||
$package = $this->process_language_pack_package( $this->type->git, $locale, $headers );
|
||||
|
||||
$response->{$locale->language}->package = $package;
|
||||
$response->{$locale->language}->type = $this->type->type;
|
||||
$response->{$locale->language}->version = $this->type->local_version;
|
||||
}
|
||||
|
||||
$this->set_repo_cache( 'languages', $response );
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$this->type->language_packs = $response;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get language-pack.json from appropriate host.
|
||||
*
|
||||
* @param string $git ( github|bitbucket|gitlab|gitea ).
|
||||
* @param array $headers
|
||||
* @param mixed $response API response.
|
||||
*
|
||||
* @return array|bool|mixed
|
||||
*/
|
||||
private function get_language_pack_json( $git, $headers, $response ) {
|
||||
switch ( $git ) {
|
||||
case 'github':
|
||||
$response = $this->api( '/repos/' . $headers['owner'] . '/' . $headers['repo'] . '/contents/language-pack.json' );
|
||||
$response = isset( $response->content )
|
||||
? json_decode( base64_decode( $response->content ) )
|
||||
: null;
|
||||
break;
|
||||
case 'bitbucket':
|
||||
$response = $this->api( '/2.0/repositories/' . $headers['owner'] . '/' . $headers['repo'] . '/src/master/language-pack.json' );
|
||||
break;
|
||||
case 'gitlab':
|
||||
$id = rawurlencode( $headers['owner'] . '/' . $headers['repo'] );
|
||||
$response = $this->api( '/projects/' . $id . '/repository/files/language-pack.json' );
|
||||
$response = isset( $response->content )
|
||||
? json_decode( base64_decode( $response->content ) )
|
||||
: null;
|
||||
break;
|
||||
case 'gitea':
|
||||
$response = $this->api( '/repos/' . $headers['owner'] . '/' . $headers['repo'] . '/raw/master/language-pack.json' );
|
||||
$response = isset( $response->content )
|
||||
? json_decode( base64_decode( $response->content ) )
|
||||
: null;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( $this->validate_response( $response ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process $package for update transient.
|
||||
*
|
||||
* @param string $git ( github|bitbucket|gitlab|gitea ).
|
||||
* @param string $locale
|
||||
* @param array $headers
|
||||
*
|
||||
* @return array|null|string
|
||||
*/
|
||||
private function process_language_pack_package( $git, $locale, $headers ) {
|
||||
$package = null;
|
||||
switch ( $git ) {
|
||||
case 'github':
|
||||
$package = [ 'https://github.com', $headers['owner'], $headers['repo'], 'blob/master' ];
|
||||
$package = implode( '/', $package ) . $locale->package;
|
||||
$package = add_query_arg( [ 'raw' => 'true' ], $package );
|
||||
break;
|
||||
case 'bitbucket':
|
||||
$package = [ 'https://bitbucket.org', $headers['owner'], $headers['repo'], 'raw/master' ];
|
||||
$package = implode( '/', $package ) . $locale->package;
|
||||
break;
|
||||
case 'gitlab':
|
||||
$package = [ 'https://gitlab.com', $headers['owner'], $headers['repo'], 'raw/master' ];
|
||||
$package = implode( '/', $package ) . $locale->package;
|
||||
break;
|
||||
case 'gitea':
|
||||
// TODO: make sure this works as expected.
|
||||
$package = [ $headers['uri'], 'raw/master' ];
|
||||
$package = implode( '/', $package ) . $local->package;
|
||||
break;
|
||||
}
|
||||
|
||||
return $package;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
/**
|
||||
* GitHub Updater
|
||||
*
|
||||
* @author Andy Fragen
|
||||
* @license GPL-2.0+
|
||||
* @link https://github.com/afragen/github-updater
|
||||
* @package github-updater
|
||||
*/
|
||||
|
||||
namespace Fragen\GitHub_Updater\API;
|
||||
|
||||
/*
|
||||
* Exit if called directly.
|
||||
*/
|
||||
if ( ! defined( 'WPINC' ) ) {
|
||||
die;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Zipfile_API
|
||||
*
|
||||
* Remote install from a Zipfile.
|
||||
*
|
||||
* @author Andy Fragen
|
||||
*/
|
||||
class Zipfile_API {
|
||||
|
||||
/**
|
||||
* Add remote install settings fields.
|
||||
*
|
||||
* @param string $type plugin|theme.
|
||||
*/
|
||||
public function add_install_settings_fields( $type ) {
|
||||
add_settings_field(
|
||||
'zipfile_slug',
|
||||
esc_html__( 'Zipfile Slug', 'github-updater' ),
|
||||
[ $this, 'zipfile_slug' ],
|
||||
'github_updater_install_' . $type,
|
||||
$type
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set repo slug for remote install.
|
||||
*/
|
||||
public function zipfile_slug() {
|
||||
?>
|
||||
<label for="zipfile_slug">
|
||||
<input class="zipfile_setting" type="text" style="width:50%;" id="zipfile_slug" name="zipfile_slug" value="" placeholder="my-repo-slug">
|
||||
<br>
|
||||
<span class="description">
|
||||
<?php esc_html_e( 'Enter plugin or theme slug.', 'github-updater' ); ?>
|
||||
</span>
|
||||
</label>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Add remote install feature, create endpoint.
|
||||
*
|
||||
* @param array $headers
|
||||
* @param array $install
|
||||
*
|
||||
* @return mixed $install
|
||||
*/
|
||||
public function remote_install( $headers, $install ) {
|
||||
$install['download_link'] = ! empty( $headers['uri'] ) ? $headers['uri'] : $headers['original'];
|
||||
$install['github_updater_install_repo'] = $install['zipfile_slug'];
|
||||
|
||||
return $install;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user