diff --git a/Puc/v4p11/Vcs/GitLabApi.php b/Puc/v4p11/Vcs/GitLabApi.php index 8fd3f45..32b62f5 100644 --- a/Puc/v4p11/Vcs/GitLabApi.php +++ b/Puc/v4p11/Vcs/GitLabApi.php @@ -28,6 +28,16 @@ if ( !class_exists('Puc_v4p11_Vcs_GitLabApi', false) ): */ protected $accessToken; + /** + * @var bool Whether to download release assets instead of the auto-generated source code archives. + */ + protected $releaseAssetsEnabled = false; + + /** + * @var bool Whether to download release asset package rather than release asset source. + */ + protected $releasePackageEnabled = false; + public function __construct($repositoryUrl, $accessToken = null, $subgroup = null) { //Parse the repository host to support custom hosts. $port = parse_url($repositoryUrl, PHP_URL_PORT); @@ -94,8 +104,74 @@ if ( !class_exists('Puc_v4p11_Vcs_GitLabApi', false) ): * @return Puc_v4p11_Vcs_Reference|null */ public function getLatestRelease() { - return $this->getLatestTag(); - } + $releases = $this->api('/:id/releases'); + if ( is_wp_error($releases) || empty($releases) || !is_array($releases) ) { + return null; + } + + foreach ($releases as $release) { + if ( true !== $release->upcoming_release ) { + break 1; //Break the loop on the first release we find that isn't an upcoming release + } + } + if ( is_wp_error($release) || !is_object($release) || !isset($release->tag_name) ) { + return null; + } + + $reference = new Puc_v4p11_Vcs_Reference(array( + 'name' => $release->tag_name, + 'version' => ltrim($release->tag_name, 'v'), //Remove the "v" prefix from "v1.2.3". + 'downloadUrl' => '', + 'updated' => $release->released_at, + 'apiResponse' => $release, + )); + $download_url = false; + + if ( $this->releasePackageEnabled && isset($release->assets, $release->assets->links) ) { + /** + * Use the first asset LINK that is a zip format file generated by a Gitlab Release Pipeline + * + * @link https://gist.github.com/timwiel/9dfd3526c768efad4973254085e065ce + */ + foreach ($release->assets->links as $link) { + if ( 'zip' === substr($link->url, -3) ) { + $download_url = $link->url; + break 1; + } + } + if ( empty( $download_url ) ) { + return null; + } + if ( ! empty( $this->accessToken ) ) { + $download_url = add_query_arg('private_token', $this->accessToken, $download_url); + } + $reference->downloadUrl = $download_url; + return $reference; + + } elseif ( isset($release->assets) ) { + /** + * Use the first asset SOURCE file that is a zip format from a Gitlab Release which should be a zip file + */ + foreach ($release->assets->sources as $source) { + if ( 'zip' === $source->format ) { + $download_url = $source->url; + break 1; + } + } + if ( empty( $download_url ) ) { + return null; + } + if ( ! empty( $this->accessToken ) ) { + $download_url = add_query_arg('private_token', $this->accessToken, $download_url); + } + $reference->downloadUrl = $download_url; + return $reference; + + } + + //If we get this far without a return then obviosuly noi release download urls were found + return null; + } /** * Get the tag that looks like the highest version number. @@ -286,13 +362,16 @@ if ( !class_exists('Puc_v4p11_Vcs_GitLabApi', false) ): * @return null|Puc_v4p11_Vcs_Reference */ public function chooseReference($configBranch) { - $updateSource = null; - // GitLab doesn't handle releases the same as GitHub so just use the latest tag - if ( $configBranch === 'master' ) { - $updateSource = $this->getLatestTag(); + if ( $configBranch === 'main' || $configBranch === 'master' ) { + //Use the latest release. + $updateSource = $this->getLatestRelease(); + if ( $updateSource === null ) { + //Failing that, use the tag with the highest version number. + $updateSource = $this->getLatestTag(); + } } - + //Alternatively, just use the branch itself. if ( empty($updateSource) ) { $updateSource = $this->getBranch($configBranch); } @@ -304,6 +383,17 @@ if ( !class_exists('Puc_v4p11_Vcs_GitLabApi', false) ): parent::setAuthentication($credentials); $this->accessToken = is_string($credentials) ? $credentials : null; } + + public function enableReleaseAssets() { + $this->releaseAssetsEnabled = true; + $this->releasePackageEnabled = false; + } + + public function enableReleasePackage() { + $this->releaseAssetsEnabled = false; + $this->releasePackageEnabled = true; + } + } endif; diff --git a/README.md b/README.md index ed08b17..236ce23 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ From the users' perspective, it works just like with plugins and themes hosted o - [BitBucket Integration](#bitbucket-integration) - [How to Release an Update](#how-to-release-an-update-2) - [GitLab Integration](#gitlab-integration) - - [How to Release an Update](#how-to-release-an-update-3) + - [How to Release an Update](#how-to-release-a-gitlab-update) - [License Management](#license-management) - [Resources](#resources) @@ -227,7 +227,7 @@ BitBucket doesn't have an equivalent to GitHub's releases, so the process is sli ### GitLab Integration 1. Download [the latest release](https://github.com/YahnisElsts/plugin-update-checker/releases/latest) and copy the `plugin-update-checker` directory to your plugin or theme. -2. Add the following code to the main plugin file or `functions.php`: +2. Add the following code to the main plugin file or `functions.php` and define how you want to check for updates from Gitlab (refer to: [Gitlab: How to Release an Update](#how-to-release-a-gitlab-update)): ```php require 'plugin-update-checker/plugin-update-checker.php'; @@ -239,11 +239,8 @@ BitBucket doesn't have an equivalent to GitHub's releases, so the process is sli //Optional: If you're using a private repository, specify the access token like this: $myUpdateChecker->setAuthentication('your-token-here'); - - //Optional: Set the branch that contains the stable release. - $myUpdateChecker->setBranch('stable-branch-name'); ``` - + Alternatively, if you're using a self-hosted GitLab instance, initialize the update checker like this: ```php $myUpdateChecker = new Puc_v4p11_Vcs_PluginUpdateChecker( @@ -260,35 +257,63 @@ BitBucket doesn't have an equivalent to GitHub's releases, so the process is sli __FILE__, 'unique-plugin-or-theme-slug' ); - + ``` - + 3. Plugins only: Add a `readme.txt` file formatted according to the [WordPress.org plugin readme standard](https://wordpress.org/plugins/readme.txt) to your repository. The contents of this file will be shown when the user clicks the "View version 1.2.3 details" link. -#### How to Release an Update +#### How to Release a Gitlab Update +A Gitlab repository can be checked for updates using 4 different options. -GitLab doesn't have an equivalent to GitHub's releases, so the process is slightly different. You can use any of the following approaches: - -- **Tags** - - To release version 1.2.3, create a new Git tag named `v1.2.3` or `1.2.3`. That's it. - - PUC doesn't require strict adherence to [SemVer](http://semver.org/). These are all valid tag names: `v1.2.3`, `v1.2-foo`, `1.2.3_rc1-ABC`, `1.2.3.4.5`. However, be warned that it's not smart enough to filter out alpha/beta/RC versions. If that's a problem, you might want to use GitLab branches instead. +1. Update from any **Gitlab Stable branch** (other than `master` or `main`): + - Point the update checker at any stable, production-ready branch and PUC will periodically check the `Version` header in the main plugin file or `style.css` and display a notification if it's greater than the installed version. + - Add the following code: + ```php + //Add the following code to your main plugin file or `functions.php` file to check for an new update from a non-master branch + $myUpdateChecker->setBranch('stable-branch-name'); + ``` + - Caveats: + - If you set the branch to `main` (the default) or `master` (the historic default), the update checker will look for recent releases and tags first. It'll only use the `main` or `master` branch if it doesn't find anything else suitable. -- **Stable branch** - - Point the update checker at a stable, production-ready branch: - ```php - $updateChecker->setBranch('branch-name'); - ``` - PUC will periodically check the `Version` header in the main plugin file or `style.css` and display a notification if it's greater than the installed version. - - Caveat: If you set the branch to `master` (the default), the update checker will look for recent releases and tags first. It'll only use the `master` branch if it doesn't find anything else suitable. +2. Update from **GitLab Releases using Generic Packages**: + - Use a Gitlab CI/CD Pipeline to automatically generate your update on release using a Generic Package. The benefit of using Generic Package assets over the Source Code assets as it the code can already be built and production ready. + - Add the following code: + ```php + //Add the following code to your main plugin file or `functions.php` file to check for an new update from releases using generic packages + $myUpdateChecker->getVcsApi()->enableReleasePackage(); + ``` + - PUC will periodically check the release version (i.e. the tag name of the release) and will display a notification if the release is a greater version than the installed version. + - The release tag name should loosely follow [SemVer](http://semver.org/) but these are all valid release names: `v1.2.3`, `v1.2-foo`, `1.2.3_rc1-ABC`, `1.2.3.4.5` However, be warned that it's not smart enough to filter out alpha/beta/RC versions. If that's a problem, you might want to use GitLab branches instead. + - For more information about *Gitlab Release Generic Packages* refer to the following links: + - [Gitlab CI/CD Release Documentation](https://docs.gitlab.com/ee/user/project/releases/#create-release-from-gitlab-ci) + - [Gitlab Release Assets as Generic Package Documentation](https://gitlab.com/gitlab-org/release-cli/-/tree/master/docs/examples/release-assets-as-generic-package/) + - [Example .gitlab-ci.yml file using Release Generic Packages for generating a update package from the Sensei-LMS wordpress plugin](https://gist.github.com/timwiel/9dfd3526c768efad4973254085e065ce) + + +3. Update **GitLab Releases using Source Code Assets**: + - Create a new release using the "Releases" feature on Gitlab and PUC will periodically check the release version (based on release tag name) and display a notification if the release version is greater than the installed version. + - Add the following code: + ```php + //Add the following code to your main plugin file or `functions.php` file to check for an new update from releases using release assets + $myUpdateChecker->getVcsApi()->enableReleaseAssets(); + ``` + - The release name should loosely follow [SemVer](http://semver.org/) but these are all valid release names: `v1.2.3`, `v1.2-foo`, `1.2.3_rc1-ABC`, `1.2.3.4.5` However, be warned that it's not smart enough to filter out alpha/beta/RC versions. If that's a problem, you might want to use GitLab branches instead. + - PUC will periodically check the release version (based on release tag name) and display a notification the release has a greater than the installed version. + + +4. Update from **Tags** on the master branch (this is the default option): + - To release version 1.2.3, create a new Git tag named `v1.2.3` or `1.2.3`. That's it. + - Add the following code: + ```php + //Add the following code to your main plugin file or `functions.php` file to check for an new update from a non-master branch + $myUpdateChecker->setBranch('master'); + ``` + - PUC doesn't require strict adherence to [SemVer](http://semver.org/). These are all valid tag names: `v1.2.3`, `v1.2-foo`, `1.2.3_rc1-ABC`, `1.2.3.4.5`. However, be warned that it's not smart enough to filter out alpha/beta/RC versions. If that's a problem, you might want to use GitLab branches instead. License Management ------------------ -Currently, the update checker doesn't have any built-in license management features. It only provides some hooks that you can use to, for example, append license keys to update requests (`$updateChecker->addQueryArgFilter()`). If you're looking for ways to manage and verify licenses, please post your feedback in [this issue](https://github.com/YahnisElsts/plugin-update-checker/issues/222). +Currently, the update checker doesn't have any built-in license management features. It only provides some hooks that you can use to, for example, append license keys to update requests (`$updateChecker->addQueryArgFilter()`). If you're looking for ways to manage and verify licenses, please post your feedback in [this issue](https://github.com/YahnisElsts/plugin-update-checker/issues/222). Resources ---------