From 6dfdc232b90faf09bb2456108541995286355985 Mon Sep 17 00:00:00 2001 From: Liam Morland Date: Mon, 17 May 2021 16:34:33 -0400 Subject: [PATCH 01/23] Coding standards: Sort @see entries --- uw_wcms_tools.gitlab.inc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/uw_wcms_tools.gitlab.inc b/uw_wcms_tools.gitlab.inc index c28da4c..8fd56e9 100644 --- a/uw_wcms_tools.gitlab.inc +++ b/uw_wcms_tools.gitlab.inc @@ -4,10 +4,10 @@ * @file * Functions for interacting with the Gitlab API. * + * @see https://git.uwaterloo.ca/help/api/api_resources.md + * @see https://git.uwaterloo.ca/help/api/projects.md * @see https://git.uwaterloo.ca/help/api/README.md * @see https://git.uwaterloo.ca/help/api/services.md - * @see https://git.uwaterloo.ca/help/api/projects.md - * @see https://git.uwaterloo.ca/help/api/api_resources.md */ require_once 'uw_wcms_tools.lib.inc'; -- GitLab From 09d80555b5226eebabd21d3f9ceb5e72dbef63c1 Mon Sep 17 00:00:00 2001 From: Liam Morland Date: Mon, 17 May 2021 16:28:07 -0400 Subject: [PATCH 02/23] ISTWCMS-4802: Create uw_wcms_tools_shell_color() --- uw_wcms_tools.lib.inc | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/uw_wcms_tools.lib.inc b/uw_wcms_tools.lib.inc index 45dc919..a6e0679 100644 --- a/uw_wcms_tools.lib.inc +++ b/uw_wcms_tools.lib.inc @@ -146,3 +146,30 @@ function uw_wcms_tools_get_profile_makefile() { function uw_wcms_tools_remove_local_mod_version($tag) { return preg_replace('/-uw_(wcms|os)\d+$/', '', $tag); } + +/** + * Return text with shell coloring. + * + * @param string $string + * The string to color. + * @param string $color + * The color to make the text. + * + * @return string + * $string starting with the color code and ending in the reset code. + */ +function uw_wcms_tools_shell_color(string $string, string $color): string { + static $colors = [ + 'black' => 30, + 'red' => 31, + 'green' => 32, + 'yellow' => 33, + 'blue' => 34, + 'purple' => 35, + 'cyan' => 36, + 'white' => 37, + ]; + static $reset = "\e[0m"; + + return "\e[0;" . $colors[$color] . 'm' . $string . $reset; +} -- GitLab From 11fcab8baa81354f83cfe23ea5c1885b061cd5e4 Mon Sep 17 00:00:00 2001 From: Liam Morland Date: Mon, 17 May 2021 16:31:15 -0400 Subject: [PATCH 03/23] ISTWCMS-4802: Create uw_wcms_tools_get_branches() --- uw_wcms_tools.gitlab.inc | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/uw_wcms_tools.gitlab.inc b/uw_wcms_tools.gitlab.inc index 8fd56e9..6bb4f6a 100644 --- a/uw_wcms_tools.gitlab.inc +++ b/uw_wcms_tools.gitlab.inc @@ -5,6 +5,7 @@ * Functions for interacting with the Gitlab API. * * @see https://git.uwaterloo.ca/help/api/api_resources.md + * @see https://git.uwaterloo.ca/help/api/branches.md * @see https://git.uwaterloo.ca/help/api/projects.md * @see https://git.uwaterloo.ca/help/api/README.md * @see https://git.uwaterloo.ca/help/api/services.md @@ -503,3 +504,30 @@ function uw_wcms_tools_gitlab_project_create(string $group, string $path): array return $r; } + +/** + * Returns an array of branch objects in a project with caching. + * + * @param int $project_id + * The project ID of the project to search. + * + * @return object[]|null + * An array of branch objects or NULL on error. + */ +function uw_wcms_tools_get_branches(int $project_id): ?array { + if ($project_id < 1) { + return []; + } + static $cache = []; + if (!array_key_exists($project_id, $cache)) { + $query = ['per_page' => 100]; + $result = uw_wcms_tools_query_gitlab_api('projects/' . $project_id . '/repository/branches', $query); + if ($result['http_status'] === 200) { + $cache[$project_id] = $result['body']; + } + else { + $cache[$project_id] = NULL; + } + } + return $cache[$project_id]; +} -- GitLab From 3c795cc2511f70e5a7c55beb779bc111566418f4 Mon Sep 17 00:00:00 2001 From: Liam Morland Date: Mon, 17 May 2021 16:36:45 -0400 Subject: [PATCH 04/23] ISTWCMS-4802: Create uw_wcms_tools_get_branch_names() --- uw_wcms_tools.gitlab.inc | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/uw_wcms_tools.gitlab.inc b/uw_wcms_tools.gitlab.inc index 6bb4f6a..e4c056d 100644 --- a/uw_wcms_tools.gitlab.inc +++ b/uw_wcms_tools.gitlab.inc @@ -531,3 +531,24 @@ function uw_wcms_tools_get_branches(int $project_id): ?array { } return $cache[$project_id]; } + +/** + * Returns an array of branch names in a project with caching. + * + * @param int $project_id + * The project ID of the project to search. + * + * @return string[]|null + * An array of branch names or NULL on error. + */ +function uw_wcms_tools_get_branch_names(int $project_id): ?array { + $branches = uw_wcms_tools_get_branches($project_id); + if ($branches) { + $branch_names = []; + foreach ($branches as $branch) { + $branch_names[] = $branch->name; + } + return $branch_names; + } + return NULL; +} -- GitLab From fc05535371811a9e2a93050d65bf764e2377e1c1 Mon Sep 17 00:00:00 2001 From: Liam Morland Date: Mon, 17 May 2021 16:41:07 -0400 Subject: [PATCH 05/23] ISTWCMS-4802: Create uw_wcms_tools_get_semvar_branch_name() --- uw_wcms_tools.gitlab.inc | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/uw_wcms_tools.gitlab.inc b/uw_wcms_tools.gitlab.inc index e4c056d..17b7b79 100644 --- a/uw_wcms_tools.gitlab.inc +++ b/uw_wcms_tools.gitlab.inc @@ -552,3 +552,27 @@ function uw_wcms_tools_get_branch_names(int $project_id): ?array { } return NULL; } + +/** + * Return a valid semvar version of a branch name. + * + * @param string $branch + * The branch name. + * + * @return string|null + * If $branch is a valid semvar, return it. If it is an "8.x" branch name, + * return the semvar equivalent, for example, 8.x-2.x becomes 2.0.x. + * Otherwise, return NULL. + */ +function uw_wcms_tools_get_semvar_branch_name(string $branch): ?string { + // Already a valid semvar branch. + if (preg_match('/^\d+\.\d+\.x$/', $branch)) { + return $branch; + } + // Convert "8.x" branch name into semvar. + elseif (preg_match('/^8.x-(\d+)\.x$/', $branch, $matches)) { + return $matches[1] . '.0.x'; + } + // Invalid branch name. + return NULL; +} -- GitLab From a9d017be063fc16ad5a88bece75844f9fb9e1422 Mon Sep 17 00:00:00 2001 From: Liam Morland Date: Mon, 17 May 2021 16:42:06 -0400 Subject: [PATCH 06/23] ISTWCMS-4802: Create uw_wcms_tools_create_semvar() --- uw_wcms_tools.gitlab.inc | 53 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/uw_wcms_tools.gitlab.inc b/uw_wcms_tools.gitlab.inc index 17b7b79..1b1ff60 100644 --- a/uw_wcms_tools.gitlab.inc +++ b/uw_wcms_tools.gitlab.inc @@ -576,3 +576,56 @@ function uw_wcms_tools_get_semvar_branch_name(string $branch): ?string { // Invalid branch name. return NULL; } + +/** + * Create semvar branches for each 8.x branch and move default if it is 8.x. + * + * @param object $project + * The project object. + */ +function uw_wcms_tools_create_semvar(stdClass $project): void { + $branches = uw_wcms_tools_get_branch_names($project->id); + + // Create semvar for each 8.x, unless it already exists. + foreach ($branches as $branch_orig) { + $branch_semvar = uw_wcms_tools_get_semvar_branch_name($branch_orig); + if ($branch_semvar && $branch_semvar !== $branch_orig) { + echo $branch_orig . ' -> ' . $branch_semvar . ': '; + if (in_array($branch_semvar, $branches, TRUE)) { + echo uw_wcms_tools_shell_color("Already exists.\n", 'blue'); + } + else { + echo 'Creating... '; + $params = [ + 'branch' => $branch_semvar, + 'ref' => $branch_orig, + ]; + $created_branch = uw_wcms_tools_query_gitlab_api('projects/' . $project->id . '/repository/branches', $params, 'POST'); + if ($created_branch['http_status'] === 201) { + echo uw_wcms_tools_shell_color("Done.\n", 'green'); + } + else { + echo uw_wcms_tools_shell_color("Error.\n", 'red'); + var_dump($created_branch); + } + } + } + } + + // If the default branch is 8.x, set to the corresponding semvar. + $branch_semvar = uw_wcms_tools_get_semvar_branch_name($project->default_branch); + if ($branch_semvar && $branch_semvar !== $project->default_branch) { + echo 'Update default: ' . $project->default_branch . ' -> ' . $branch_semvar . ' '; + $params = [ + 'default_branch' => $branch_semvar, + ]; + $response = uw_wcms_tools_query_gitlab_api('projects/' . $project->id, $params, 'PUT'); + if ($response['http_status'] === 200) { + echo uw_wcms_tools_shell_color("Done.\n", 'green'); + } + else { + echo uw_wcms_tools_shell_color("Error.\n", 'red'); + var_dump($response); + } + } +} -- GitLab From 49012b592100c014416e27e34cf2633c9e1be1c8 Mon Sep 17 00:00:00 2001 From: Liam Morland Date: Mon, 17 May 2021 16:46:09 -0400 Subject: [PATCH 07/23] ISTWCMS-4802: Create gitlab-make-semvar.php --- gitlab-make-semvar.php | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100755 gitlab-make-semvar.php diff --git a/gitlab-make-semvar.php b/gitlab-make-semvar.php new file mode 100755 index 0000000..a803cf4 --- /dev/null +++ b/gitlab-make-semvar.php @@ -0,0 +1,39 @@ +#!/usr/bin/env php +path_with_namespace . "\n"; + uw_wcms_tools_create_semvar($project); +} -- GitLab From b7d3cfbe72e0cd3e3d88e70a3875b5fd39dcc1be Mon Sep 17 00:00:00 2001 From: Liam Morland Date: Tue, 18 May 2021 12:36:14 -0400 Subject: [PATCH 08/23] ISTWCMS-4802: Support semvar in uw_wcms_tools_get_tag_latest() --- uw_wcms_tools.gitlab.inc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/uw_wcms_tools.gitlab.inc b/uw_wcms_tools.gitlab.inc index 1b1ff60..4b0e937 100644 --- a/uw_wcms_tools.gitlab.inc +++ b/uw_wcms_tools.gitlab.inc @@ -254,6 +254,10 @@ function uw_wcms_tools_get_tag_latest($project_id, $branch_filter = NULL, $full_ elseif (preg_match('/^\d+\.x$/', $branch_filter)) { $branch_filter = $branch_filter . '-'; } + // Semvar filter. Whether given as 1.2.3 or 1.2.x, will filter as "1.2.". + elseif (preg_match('/^(\d+\.\d+\.)(x|\d+)$/', $branch_filter, $matches)) { + $branch_filter = $matches[1]; + } // Filter on Drupal major core version only by setting it as integer. elseif (is_int($branch_filter)) { $branch_filter = $branch_filter . '.'; -- GitLab From 53576a6e7f895e9d70b905e67824608245c96c15 Mon Sep 17 00:00:00 2001 From: Liam Morland Date: Tue, 18 May 2021 12:33:26 -0400 Subject: [PATCH 09/23] ISTWCMS-4802: Create uw_wcms_tools_next_semvar() --- uw_wcms_tools.lib.inc | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/uw_wcms_tools.lib.inc b/uw_wcms_tools.lib.inc index a6e0679..e4c283e 100644 --- a/uw_wcms_tools.lib.inc +++ b/uw_wcms_tools.lib.inc @@ -56,6 +56,41 @@ function uw_wcms_tools_next_version($current = NULL) { return $core . '.x-' . $major . '.' . $minor; } +/** + * Return the first or next semantic version number. + * + * @param string $version + * The current version number or branch. + * + * @return string|null + * If $version is a semvar version, return the next patch leve. If it is a + * branch, such as 1.2.x return the first version on that branch. Otherwise, + * return NULL. + */ +function uw_wcms_tools_next_semvar(string $version): ?string { + // Version number provided. + if (preg_match('/^(\d+)\.(\d+)\.(\d+)(-(?:alpha|beta|rc)\d+)?$/', $version, $matches)) { + $major = (int) $matches[1]; + $minor = (int) $matches[2]; + $patch = (int) $matches[3]; + + // Increment minor if version does not end with -alphaN, -betaN, or -rcN. + if (!isset($matches[4])) { + $patch++; + } + } + // Branch provided. + elseif (preg_match('/^(\d+)\.(\d+)\.x$/', $version, $matches)) { + $major = (int) $matches[1]; + $minor = (int) $matches[2]; + $patch = 0; + } + else { + return NULL; + } + return $major . '.' . $minor . '.' . $patch; +} + /** * Parse a site makefile. * -- GitLab From f803e7551760add56aba4259641facbf12d561a7 Mon Sep 17 00:00:00 2001 From: Liam Morland Date: Tue, 18 May 2021 12:37:45 -0400 Subject: [PATCH 10/23] ISTWCMS-4802: Create uw_wcms_tools_version_compare_array() --- uw_wcms_tools.gitlab.inc | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/uw_wcms_tools.gitlab.inc b/uw_wcms_tools.gitlab.inc index 4b0e937..598ae2d 100644 --- a/uw_wcms_tools.gitlab.inc +++ b/uw_wcms_tools.gitlab.inc @@ -297,6 +297,30 @@ function uw_wcms_tools_get_tag_latest($project_id, $branch_filter = NULL, $full_ return $latest; } +/** + * Return the most recent value in an using version_compare(). + * + * @param array $versions + * An array of versions to compare. + * + * @return string|null + * The most recent version or NULL if $versions is empty. + */ +function uw_wcms_tools_version_compare_array(array $versions): ?string { + if (!$versions) { + return NULL; + } + + $latest = (string) array_shift($versions); + foreach ($versions as $version) { + $version = (string) $version; + if (version_compare($version, $latest, '>')) { + $latest = $version; + } + } + return $latest; +} + /** * Return the latest commits for the default branch of a project. * -- GitLab From 9b20ea42ee585774be8b448deb4806906c279d93 Mon Sep 17 00:00:00 2001 From: Liam Morland Date: Tue, 18 May 2021 12:38:30 -0400 Subject: [PATCH 11/23] ISTWCMS-4802: Create uw_wcms_tools_get_branch_latest() --- uw_wcms_tools.gitlab.inc | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/uw_wcms_tools.gitlab.inc b/uw_wcms_tools.gitlab.inc index 598ae2d..4ca1b4d 100644 --- a/uw_wcms_tools.gitlab.inc +++ b/uw_wcms_tools.gitlab.inc @@ -657,3 +657,23 @@ function uw_wcms_tools_create_semvar(stdClass $project): void { } } } + +/** + * Return the most recent semvar branch. + * + * @param int $project_id + * The project ID. + * + * @return string|null + * The branch name or NULL if there are none that match. + */ +function uw_wcms_tools_get_branch_latest(int $project_id): ?string { + $branches = []; + foreach (uw_wcms_tools_get_branches($project_id) as $branch) { + if (preg_match('/^\d+\.\d+\.x$/', $branch->name)) { + $branches[] = $branch->name; + } + } + + return uw_wcms_tools_version_compare_array($branches); +} -- GitLab From e7a923d528ffe3129b06be5088c5f2df72306f12 Mon Sep 17 00:00:00 2001 From: Liam Morland Date: Tue, 18 May 2021 12:39:04 -0400 Subject: [PATCH 12/23] ISTWCMS-4802: Create uw_wcms_tools_get_current_branches() --- uw_wcms_tools.gitlab.inc | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/uw_wcms_tools.gitlab.inc b/uw_wcms_tools.gitlab.inc index 4ca1b4d..0b515e2 100644 --- a/uw_wcms_tools.gitlab.inc +++ b/uw_wcms_tools.gitlab.inc @@ -677,3 +677,41 @@ function uw_wcms_tools_get_branch_latest(int $project_id): ?string { return uw_wcms_tools_version_compare_array($branches); } + +/** + * Return the current development and release branches. + * + * The dev branch is the default branch if it is valid, otherwise, the most + * recent valid branch. The release branch is the corresponding release branch. + * + * @param int $project_id + * The project ID. + * + * @return array|null + * NULL if no valid branches, otherwise an array with keys: + * - dev: The semvar current development branch. + * - rel: The semvar current release branch. + * - tag_latest: The latest tag. + * - tag_next: The next tag. + */ +function uw_wcms_tools_get_current_branches(int $project_id): ?array { + $project = uw_wcms_tools_get_project($project_id); + + // Use the default branch if it is semvar, otherwise, the most recent semvar. + $dev_branch = uw_wcms_tools_get_semvar_branch_name($project->default_branch); + if (!$dev_branch) { + $dev_branch = uw_wcms_tools_get_branch_latest($project_id); + } + // Return early if no semvar branch. + if (!$dev_branch) { + return NULL; + } + + $tag_latest = uw_wcms_tools_get_tag_latest($project_id, $dev_branch); + return [ + 'dev' => $dev_branch, + 'rel' => 'prod/' . $dev_branch, + 'tag_latest' => $tag_latest, + 'tag_next' => uw_wcms_tools_next_semvar($tag_latest->name ?? $dev_branch), + ]; +} -- GitLab From f10b0b65a0bcbf2b6189f09e0e83b84540ce6322 Mon Sep 17 00:00:00 2001 From: Liam Morland Date: Tue, 18 May 2021 12:58:21 -0400 Subject: [PATCH 13/23] ISTWCMS-4802: Create gitlab-tag-release.php --- gitlab-tag-release.php | 85 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100755 gitlab-tag-release.php diff --git a/gitlab-tag-release.php b/gitlab-tag-release.php new file mode 100755 index 0000000..e6df106 --- /dev/null +++ b/gitlab-tag-release.php @@ -0,0 +1,85 @@ +#!/usr/bin/env php +id); + +$branch_names = uw_wcms_tools_get_branch_names($project->id); + +// Update or create release branch. +if (in_array($current_branches['rel'], $branch_names)) { + echo 'Merge ' . $current_branches['dev'] . ' into ' . $current_branches['rel'] . '... '; + // @todo Implement this. + echo uw_wcms_tools_shell_color("Not implemented.\n", 'yellow'); +} +else { + echo 'Create ' . $current_branches['rel'] . ' from ' . $current_branches['dev'] . '... '; + $params = [ + 'branch' => $current_branches['rel'], + 'ref' => $current_branches['dev'], + ]; + $release_branch = uw_wcms_tools_query_gitlab_api('projects/' . $project->id . '/repository/branches', $params, 'POST'); + if ($release_branch['http_status'] === 201) { + echo uw_wcms_tools_shell_color("Done.\n", 'green'); + } + else { + echo uw_wcms_tools_shell_color("Error.\n", 'red'); + var_dump($release_branch); + throw new Exception('Branch creation failed.'); + } +} + +// Create tag. +echo 'Tag ' . $current_branches['rel'] . ' as ' . $current_branches['tag_next'] . '... '; +// Check that there is not already a tag pointing at the branch tip. +$params = [ + 'type' => 'tag', +]; +$release_branch_tip_tags = uw_wcms_tools_query_gitlab_api('projects/' . $project->id . '/repository/commits/' . $release_branch['body']->commit->id . '/refs', $params); +if ($release_branch_tip_tags['http_status'] !== 200) { + echo uw_wcms_tools_shell_color("Error.\n", 'red'); + var_dump($release_branch_tip_tags); + throw new Exception('Reading tags at branch tip failed.'); +} +elseif ($release_branch_tip_tags['body']) { + echo uw_wcms_tools_shell_color("Branch tip already part of a tag. Nothing created.\n", 'yellow'); +} +else { + // Do tag creation. + $params = [ + 'tag_name' => $current_branches['tag_next'], + 'ref' => $release_branch['body']->commit->id, + ]; + $new_tag = uw_wcms_tools_query_gitlab_api('projects/' . $project->id . '/repository/tags', $params, 'POST'); + if ($new_tag['http_status'] === 201) { + echo uw_wcms_tools_shell_color("Done.\n", 'green'); + } + else { + echo uw_wcms_tools_shell_color("Error.\n", 'red'); + var_dump($new_tag); + throw new Exception('Tag creation failed.'); + } +} -- GitLab From 4e0b6f7ba88e87df8a6bbc84636378ed61f40fcb Mon Sep 17 00:00:00 2001 From: Liam Morland Date: Tue, 18 May 2021 16:42:14 -0400 Subject: [PATCH 14/23] ISTWCMS-4802: Allow any prefix branch filter in uw_wcms_tools_get_tag_latest() This means that incorrect filters are more likely to give an error that will be noticed instead of resulting in unfiltered results. --- uw_wcms_tools.gitlab.inc | 3 --- 1 file changed, 3 deletions(-) diff --git a/uw_wcms_tools.gitlab.inc b/uw_wcms_tools.gitlab.inc index 0b515e2..b43501e 100644 --- a/uw_wcms_tools.gitlab.inc +++ b/uw_wcms_tools.gitlab.inc @@ -262,9 +262,6 @@ function uw_wcms_tools_get_tag_latest($project_id, $branch_filter = NULL, $full_ elseif (is_int($branch_filter)) { $branch_filter = $branch_filter . '.'; } - else { - $branch_filter = NULL; - } if ($branch_filter) { foreach ($tags as $key => $value) { if (strpos($value->name, $branch_filter) !== 0) { -- GitLab From 00e31d88fa0f0f70861768fe1b5a213e0efd13a0 Mon Sep 17 00:00:00 2001 From: Liam Morland Date: Wed, 19 May 2021 10:57:07 -0400 Subject: [PATCH 15/23] ISTWCMS-4802: Allow $project_id to be path in uw_wcms_tools_get_tag_latest() --- uw_wcms_tools.gitlab.inc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/uw_wcms_tools.gitlab.inc b/uw_wcms_tools.gitlab.inc index b43501e..2552b9b 100644 --- a/uw_wcms_tools.gitlab.inc +++ b/uw_wcms_tools.gitlab.inc @@ -222,8 +222,8 @@ function uw_wcms_tools_get_group($id): ?object { /** * Return the tag in a project which is highest accounting to version_compare(). * - * @param int $project_id - * The project ID of the project to search. + * @param int|string $project_id + * The project ID or NAMESPACE/PROJECT_PATH of the project to search. * @param string $branch_filter * If set to a Drupal branch name (e.g. "7.x-1.x"), remove tags that don't * match (e.g. not like "7.x-1.1"). @@ -234,10 +234,10 @@ function uw_wcms_tools_get_group($id): ?object { * The tag or NULL if there are no tags. */ function uw_wcms_tools_get_tag_latest($project_id, $branch_filter = NULL, $full_release_only = FALSE) { - $project_id = (int) $project_id; - if ($project_id < 1) { + if (!preg_match('/^(\d+|[a-z0-9_]+\/[a-z0-9_]+)$/', $project_id)) { return; } + $project_id = urlencode($project_id); $tags = uw_wcms_tools_query_gitlab_api('projects/' . $project_id . '/repository/tags', array('per_page' => 100)); $tags = $tags['body']; -- GitLab From 7ba2823f793e3914008648151035f6721b0a8541 Mon Sep 17 00:00:00 2001 From: Liam Morland Date: Tue, 18 May 2021 16:42:42 -0400 Subject: [PATCH 16/23] ISTWCMS-4802: Create composer-update-tags.php --- composer-update-tags.php | 56 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100755 composer-update-tags.php diff --git a/composer-update-tags.php b/composer-update-tags.php new file mode 100755 index 0000000..b5957a4 --- /dev/null +++ b/composer-update-tags.php @@ -0,0 +1,56 @@ +#!/usr/bin/env php +name . $matches[6]; + echo $module . ($line === $new_line ? ' already at ' : ' setting to ') . $latest_tag->name . "\n"; + $line = $new_line; + } + else { + echo uw_wcms_tools_shell_color('Warning: No tag, left on branch: ' . $module . ".\n", 'red'); + } +} +file_put_contents('composer.json', $composer_file); + +echo uw_wcms_tools_shell_color("Done.\n", 'green'); -- GitLab From 61b59e600995f54fe36e5ccd07ec2bc8229a8df4 Mon Sep 17 00:00:00 2001 From: Liam Morland Date: Thu, 20 May 2021 12:22:30 -0400 Subject: [PATCH 17/23] ISTWCMS-4802: Create uw_wcms_tools_gitlab_tag_release() in gitlab-tag-release.php --- gitlab-tag-release.php | 119 +++++++++++++++++++++++------------------ 1 file changed, 66 insertions(+), 53 deletions(-) diff --git a/gitlab-tag-release.php b/gitlab-tag-release.php index e6df106..8c0b9f1 100755 --- a/gitlab-tag-release.php +++ b/gitlab-tag-release.php @@ -16,70 +16,83 @@ min_args($argv, 1); // Separate GITLAB-PATH. $arg = explode('/', $argv[1], 2); -// Load project. -$project = uw_wcms_tools_get_project($arg[0], $arg[1]); -if (!$project) { - throw new Exception('Invalid project.'); -} -echo "Ensuring this project has semvar branches...\n"; -uw_wcms_tools_create_semvar($project); +uw_wcms_tools_gitlab_tag_release($arg[0], $arg[1]); + +/** + * Merge project development to release branch and tag as next patch level. + * + * @param string $namespace + * The GitLab namespace of the project to act on. + * @param string $path + * The GitLab path of the project to act on. + */ +function uw_wcms_tools_gitlab_tag_release(string $namespace, string $path): void { + // Load project. + $project = uw_wcms_tools_get_project($namespace, $path); + if (!$project) { + throw new Exception('Invalid project.'); + } -$current_branches = uw_wcms_tools_get_current_branches($project->id); + echo "Ensuring this project has semvar branches...\n"; + uw_wcms_tools_create_semvar($project); -$branch_names = uw_wcms_tools_get_branch_names($project->id); + $current_branches = uw_wcms_tools_get_current_branches($project->id); -// Update or create release branch. -if (in_array($current_branches['rel'], $branch_names)) { - echo 'Merge ' . $current_branches['dev'] . ' into ' . $current_branches['rel'] . '... '; - // @todo Implement this. - echo uw_wcms_tools_shell_color("Not implemented.\n", 'yellow'); -} -else { - echo 'Create ' . $current_branches['rel'] . ' from ' . $current_branches['dev'] . '... '; - $params = [ - 'branch' => $current_branches['rel'], - 'ref' => $current_branches['dev'], - ]; - $release_branch = uw_wcms_tools_query_gitlab_api('projects/' . $project->id . '/repository/branches', $params, 'POST'); - if ($release_branch['http_status'] === 201) { - echo uw_wcms_tools_shell_color("Done.\n", 'green'); + $branch_names = uw_wcms_tools_get_branch_names($project->id); + + // Update or create release branch. + if (in_array($current_branches['rel'], $branch_names)) { + echo 'Merge ' . $current_branches['dev'] . ' into ' . $current_branches['rel'] . '... '; + // @todo Implement this. + echo uw_wcms_tools_shell_color("Not implemented.\n", 'yellow'); } else { - echo uw_wcms_tools_shell_color("Error.\n", 'red'); - var_dump($release_branch); - throw new Exception('Branch creation failed.'); + echo 'Create ' . $current_branches['rel'] . ' from ' . $current_branches['dev'] . '... '; + $params = [ + 'branch' => $current_branches['rel'], + 'ref' => $current_branches['dev'], + ]; + $release_branch = uw_wcms_tools_query_gitlab_api('projects/' . $project->id . '/repository/branches', $params, 'POST'); + if ($release_branch['http_status'] === 201) { + echo uw_wcms_tools_shell_color("Done.\n", 'green'); + } + else { + echo uw_wcms_tools_shell_color("Error.\n", 'red'); + var_dump($release_branch); + throw new Exception('Branch creation failed.'); + } } -} -// Create tag. -echo 'Tag ' . $current_branches['rel'] . ' as ' . $current_branches['tag_next'] . '... '; -// Check that there is not already a tag pointing at the branch tip. -$params = [ - 'type' => 'tag', -]; -$release_branch_tip_tags = uw_wcms_tools_query_gitlab_api('projects/' . $project->id . '/repository/commits/' . $release_branch['body']->commit->id . '/refs', $params); -if ($release_branch_tip_tags['http_status'] !== 200) { - echo uw_wcms_tools_shell_color("Error.\n", 'red'); - var_dump($release_branch_tip_tags); - throw new Exception('Reading tags at branch tip failed.'); -} -elseif ($release_branch_tip_tags['body']) { - echo uw_wcms_tools_shell_color("Branch tip already part of a tag. Nothing created.\n", 'yellow'); -} -else { - // Do tag creation. + // Create tag. + echo 'Tag ' . $current_branches['rel'] . ' as ' . $current_branches['tag_next'] . '... '; + // Check that there is not already a tag pointing at the branch tip. $params = [ - 'tag_name' => $current_branches['tag_next'], - 'ref' => $release_branch['body']->commit->id, + 'type' => 'tag', ]; - $new_tag = uw_wcms_tools_query_gitlab_api('projects/' . $project->id . '/repository/tags', $params, 'POST'); - if ($new_tag['http_status'] === 201) { - echo uw_wcms_tools_shell_color("Done.\n", 'green'); + $release_branch_tip_tags = uw_wcms_tools_query_gitlab_api('projects/' . $project->id . '/repository/commits/' . $release_branch['body']->commit->id . '/refs', $params); + if ($release_branch_tip_tags['http_status'] !== 200) { + echo uw_wcms_tools_shell_color("Error.\n", 'red'); + var_dump($release_branch_tip_tags); + throw new Exception('Reading tags at branch tip failed.'); + } + elseif ($release_branch_tip_tags['body']) { + echo uw_wcms_tools_shell_color("Branch tip already part of a tag. Nothing created.\n", 'yellow'); } else { - echo uw_wcms_tools_shell_color("Error.\n", 'red'); - var_dump($new_tag); - throw new Exception('Tag creation failed.'); + // Do tag creation. + $params = [ + 'tag_name' => $current_branches['tag_next'], + 'ref' => $release_branch['body']->commit->id, + ]; + $new_tag = uw_wcms_tools_query_gitlab_api('projects/' . $project->id . '/repository/tags', $params, 'POST'); + if ($new_tag['http_status'] === 201) { + echo uw_wcms_tools_shell_color("Done.\n", 'green'); + } + else { + echo uw_wcms_tools_shell_color("Error.\n", 'red'); + var_dump($new_tag); + throw new Exception('Tag creation failed.'); + } } } -- GitLab From d50d7f9ac2b9ef188ef5d5ef64b5df33ae984ca4 Mon Sep 17 00:00:00 2001 From: Liam Morland Date: Thu, 20 May 2021 12:39:36 -0400 Subject: [PATCH 18/23] ISTWCMS-4802: Move uw_wcms_tools_gitlab_tag_release() --- gitlab-tag-release.php | 78 ---------------------------------------- uw_wcms_tools.gitlab.inc | 78 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 78 deletions(-) diff --git a/gitlab-tag-release.php b/gitlab-tag-release.php index 8c0b9f1..3950f1a 100755 --- a/gitlab-tag-release.php +++ b/gitlab-tag-release.php @@ -18,81 +18,3 @@ min_args($argv, 1); $arg = explode('/', $argv[1], 2); uw_wcms_tools_gitlab_tag_release($arg[0], $arg[1]); - -/** - * Merge project development to release branch and tag as next patch level. - * - * @param string $namespace - * The GitLab namespace of the project to act on. - * @param string $path - * The GitLab path of the project to act on. - */ -function uw_wcms_tools_gitlab_tag_release(string $namespace, string $path): void { - // Load project. - $project = uw_wcms_tools_get_project($namespace, $path); - if (!$project) { - throw new Exception('Invalid project.'); - } - - echo "Ensuring this project has semvar branches...\n"; - uw_wcms_tools_create_semvar($project); - - $current_branches = uw_wcms_tools_get_current_branches($project->id); - - $branch_names = uw_wcms_tools_get_branch_names($project->id); - - // Update or create release branch. - if (in_array($current_branches['rel'], $branch_names)) { - echo 'Merge ' . $current_branches['dev'] . ' into ' . $current_branches['rel'] . '... '; - // @todo Implement this. - echo uw_wcms_tools_shell_color("Not implemented.\n", 'yellow'); - } - else { - echo 'Create ' . $current_branches['rel'] . ' from ' . $current_branches['dev'] . '... '; - $params = [ - 'branch' => $current_branches['rel'], - 'ref' => $current_branches['dev'], - ]; - $release_branch = uw_wcms_tools_query_gitlab_api('projects/' . $project->id . '/repository/branches', $params, 'POST'); - if ($release_branch['http_status'] === 201) { - echo uw_wcms_tools_shell_color("Done.\n", 'green'); - } - else { - echo uw_wcms_tools_shell_color("Error.\n", 'red'); - var_dump($release_branch); - throw new Exception('Branch creation failed.'); - } - } - - // Create tag. - echo 'Tag ' . $current_branches['rel'] . ' as ' . $current_branches['tag_next'] . '... '; - // Check that there is not already a tag pointing at the branch tip. - $params = [ - 'type' => 'tag', - ]; - $release_branch_tip_tags = uw_wcms_tools_query_gitlab_api('projects/' . $project->id . '/repository/commits/' . $release_branch['body']->commit->id . '/refs', $params); - if ($release_branch_tip_tags['http_status'] !== 200) { - echo uw_wcms_tools_shell_color("Error.\n", 'red'); - var_dump($release_branch_tip_tags); - throw new Exception('Reading tags at branch tip failed.'); - } - elseif ($release_branch_tip_tags['body']) { - echo uw_wcms_tools_shell_color("Branch tip already part of a tag. Nothing created.\n", 'yellow'); - } - else { - // Do tag creation. - $params = [ - 'tag_name' => $current_branches['tag_next'], - 'ref' => $release_branch['body']->commit->id, - ]; - $new_tag = uw_wcms_tools_query_gitlab_api('projects/' . $project->id . '/repository/tags', $params, 'POST'); - if ($new_tag['http_status'] === 201) { - echo uw_wcms_tools_shell_color("Done.\n", 'green'); - } - else { - echo uw_wcms_tools_shell_color("Error.\n", 'red'); - var_dump($new_tag); - throw new Exception('Tag creation failed.'); - } - } -} diff --git a/uw_wcms_tools.gitlab.inc b/uw_wcms_tools.gitlab.inc index 2552b9b..b6dcebf 100644 --- a/uw_wcms_tools.gitlab.inc +++ b/uw_wcms_tools.gitlab.inc @@ -712,3 +712,81 @@ function uw_wcms_tools_get_current_branches(int $project_id): ?array { 'tag_next' => uw_wcms_tools_next_semvar($tag_latest->name ?? $dev_branch), ]; } + +/** + * Merge project development to release branch and tag as next patch level. + * + * @param string $namespace + * The GitLab namespace of the project to act on. + * @param string $path + * The GitLab path of the project to act on. + */ +function uw_wcms_tools_gitlab_tag_release(string $namespace, string $path): void { + // Load project. + $project = uw_wcms_tools_get_project($namespace, $path); + if (!$project) { + throw new Exception('Invalid project.'); + } + + echo "Ensuring this project has semvar branches...\n"; + uw_wcms_tools_create_semvar($project); + + $current_branches = uw_wcms_tools_get_current_branches($project->id); + + $branch_names = uw_wcms_tools_get_branch_names($project->id); + + // Update or create release branch. + if (in_array($current_branches['rel'], $branch_names)) { + echo 'Merge ' . $current_branches['dev'] . ' into ' . $current_branches['rel'] . '... '; + // @todo Implement this. + echo uw_wcms_tools_shell_color("Not implemented.\n", 'yellow'); + } + else { + echo 'Create ' . $current_branches['rel'] . ' from ' . $current_branches['dev'] . '... '; + $params = [ + 'branch' => $current_branches['rel'], + 'ref' => $current_branches['dev'], + ]; + $release_branch = uw_wcms_tools_query_gitlab_api('projects/' . $project->id . '/repository/branches', $params, 'POST'); + if ($release_branch['http_status'] === 201) { + echo uw_wcms_tools_shell_color("Done.\n", 'green'); + } + else { + echo uw_wcms_tools_shell_color("Error.\n", 'red'); + var_dump($release_branch); + throw new Exception('Branch creation failed.'); + } + } + + // Create tag. + echo 'Tag ' . $current_branches['rel'] . ' as ' . $current_branches['tag_next'] . '... '; + // Check that there is not already a tag pointing at the branch tip. + $params = [ + 'type' => 'tag', + ]; + $release_branch_tip_tags = uw_wcms_tools_query_gitlab_api('projects/' . $project->id . '/repository/commits/' . $release_branch['body']->commit->id . '/refs', $params); + if ($release_branch_tip_tags['http_status'] !== 200) { + echo uw_wcms_tools_shell_color("Error.\n", 'red'); + var_dump($release_branch_tip_tags); + throw new Exception('Reading tags at branch tip failed.'); + } + elseif ($release_branch_tip_tags['body']) { + echo uw_wcms_tools_shell_color("Branch tip already part of a tag. Nothing created.\n", 'yellow'); + } + else { + // Do tag creation. + $params = [ + 'tag_name' => $current_branches['tag_next'], + 'ref' => $release_branch['body']->commit->id, + ]; + $new_tag = uw_wcms_tools_query_gitlab_api('projects/' . $project->id . '/repository/tags', $params, 'POST'); + if ($new_tag['http_status'] === 201) { + echo uw_wcms_tools_shell_color("Done.\n", 'green'); + } + else { + echo uw_wcms_tools_shell_color("Error.\n", 'red'); + var_dump($new_tag); + throw new Exception('Tag creation failed.'); + } + } +} -- GitLab From b9ba52730dec9f916163e03f9d2c01c44cf53a14 Mon Sep 17 00:00:00 2001 From: Liam Morland Date: Thu, 20 May 2021 14:40:50 -0400 Subject: [PATCH 19/23] ISTWCMS-4802: Create uw_wcms_tools_get_branch_default_or_latest() --- uw_wcms_tools.gitlab.inc | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/uw_wcms_tools.gitlab.inc b/uw_wcms_tools.gitlab.inc index b6dcebf..0bc763c 100644 --- a/uw_wcms_tools.gitlab.inc +++ b/uw_wcms_tools.gitlab.inc @@ -675,6 +675,25 @@ function uw_wcms_tools_get_branch_latest(int $project_id): ?string { return uw_wcms_tools_version_compare_array($branches); } +/** + * Return the default branch if semvar otherwise the most recent semvar branch. + * + * @param int $project_id + * The project ID of the project to search. + * + * @return string|null + * The branch name or NULL if there are none that match. + */ +function uw_wcms_tools_get_branch_default_or_latest(int $project_id): ?string { + $project = uw_wcms_tools_get_project($project_id); + + $branch = uw_wcms_tools_get_semvar_branch_name($project->default_branch); + if (!$branch) { + $branch = uw_wcms_tools_get_branch_latest($project->id); + } + return $branch; +} + /** * Return the current development and release branches. * @@ -692,13 +711,8 @@ function uw_wcms_tools_get_branch_latest(int $project_id): ?string { * - tag_next: The next tag. */ function uw_wcms_tools_get_current_branches(int $project_id): ?array { - $project = uw_wcms_tools_get_project($project_id); + $dev_branch = uw_wcms_tools_get_branch_default_or_latest($project_id); - // Use the default branch if it is semvar, otherwise, the most recent semvar. - $dev_branch = uw_wcms_tools_get_semvar_branch_name($project->default_branch); - if (!$dev_branch) { - $dev_branch = uw_wcms_tools_get_branch_latest($project_id); - } // Return early if no semvar branch. if (!$dev_branch) { return NULL; -- GitLab From 50eb83d77949dc4187d6913d2406a191b179317a Mon Sep 17 00:00:00 2001 From: Liam Morland Date: Thu, 20 May 2021 15:23:20 -0400 Subject: [PATCH 20/23] ISTWCMS-4802: Create uw_wcms_tools_gitlab_get_profile_projects() --- uw_wcms_tools.gitlab.inc | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/uw_wcms_tools.gitlab.inc b/uw_wcms_tools.gitlab.inc index 0bc763c..a40c73e 100644 --- a/uw_wcms_tools.gitlab.inc +++ b/uw_wcms_tools.gitlab.inc @@ -804,3 +804,36 @@ function uw_wcms_tools_gitlab_tag_release(string $namespace, string $path): void } } } + +/** + * Return an array of WCMS projects in uw_base_profile composer.json. + * + * @return array[] + * An array of project arrays with keys 'namespace' and 'path'. + */ +function uw_wcms_tools_gitlab_get_profile_projects(): array { + // Get composer.json from development branch in uw_base_profile. + $project = uw_wcms_tools_get_project('wcms', 'uw_base_profile'); + $file_path = 'composer.json'; + $params = [ + 'ref' => uw_wcms_tools_get_branch_default_or_latest($project->id), + ]; + $composer = uw_wcms_tools_query_gitlab_api('projects/' . $project->id . '/repository/files/' . urlencode($file_path) . '/raw', $params); + if ($composer['http_status'] !== 200) { + throw new Exception('Unable to load ' . $file_path . ' from uw_base_profile.'); + } + + // Make an array of all projects in the 'wcms' group. + $profile_projects = []; + foreach (['require', 'require-dev'] as $type) { + if (isset($composer['body']->$type)) { + foreach (array_keys((array) $composer['body']->$type) as $project) { + list($project_arr['namespace'], $project_arr['path']) = explode('/', $project, 2); + if ($project_arr['namespace'] === 'wcms') { + $profile_projects[] = $project_arr; + } + } + } + } + return $profile_projects; +} -- GitLab From 0689cb2a21328f7c9917ee0206ee09bae01b7e4c Mon Sep 17 00:00:00 2001 From: Liam Morland Date: Thu, 20 May 2021 15:46:21 -0400 Subject: [PATCH 21/23] ISTWCMS-4802: Add 'all' option to gitlab-tag-release.php --- gitlab-tag-release.php | 22 +++++++++++++++++----- uw_wcms_tools.gitlab.inc | 2 ++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/gitlab-tag-release.php b/gitlab-tag-release.php index 3950f1a..69ec54a 100755 --- a/gitlab-tag-release.php +++ b/gitlab-tag-release.php @@ -9,12 +9,24 @@ require_once 'devops/uw_devops.inc'; require_once 'uw_wcms_tools.gitlab.inc'; -$_uw_wcms_tools_usage = 'gitlab-tag-release.php GITLAB-PATH +$_uw_wcms_tools_usage = 'gitlab-tag-release.php GITLAB-PATH|all Tag a release of a GitLab project. Provide a GITLAB-PATH, such as -"wcms/uw_base_profile".'; +"wcms/uw_base_profile" or "all" to tag all WCMS projects in the profile.'; min_args($argv, 1); -// Separate GITLAB-PATH. -$arg = explode('/', $argv[1], 2); +if ($argv[1] === 'all') { + $projects = uw_wcms_tools_gitlab_get_profile_projects(); + echo 'Tagging ' . count($projects) . " projects...\n"; +} +else { + // Separate GITLAB-PATH. + $arg = explode('/', $argv[1], 2); -uw_wcms_tools_gitlab_tag_release($arg[0], $arg[1]); + $projects = [ + ['namespace' => $arg[0], 'path' => $arg[1]], + ]; +} + +foreach ($projects as $project) { + uw_wcms_tools_gitlab_tag_release($project['namespace'], $project['path']); +} diff --git a/uw_wcms_tools.gitlab.inc b/uw_wcms_tools.gitlab.inc index a40c73e..ceeca47 100644 --- a/uw_wcms_tools.gitlab.inc +++ b/uw_wcms_tools.gitlab.inc @@ -742,6 +742,8 @@ function uw_wcms_tools_gitlab_tag_release(string $namespace, string $path): void throw new Exception('Invalid project.'); } + echo uw_wcms_tools_shell_color('Project: ' . $project->path_with_namespace . "\n", 'blue'); + echo "Ensuring this project has semvar branches...\n"; uw_wcms_tools_create_semvar($project); -- GitLab From 16cacb0f6bd94210b8b974eb519a841fb53a386c Mon Sep 17 00:00:00 2001 From: Liam Morland Date: Fri, 21 May 2021 11:57:46 -0400 Subject: [PATCH 22/23] ISTWCMS-4802: Check if new tag is needed in uw_wcms_tools_gitlab_tag_release() --- uw_wcms_tools.gitlab.inc | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/uw_wcms_tools.gitlab.inc b/uw_wcms_tools.gitlab.inc index ceeca47..d5fba55 100644 --- a/uw_wcms_tools.gitlab.inc +++ b/uw_wcms_tools.gitlab.inc @@ -754,8 +754,33 @@ function uw_wcms_tools_gitlab_tag_release(string $namespace, string $path): void // Update or create release branch. if (in_array($current_branches['rel'], $branch_names)) { echo 'Merge ' . $current_branches['dev'] . ' into ' . $current_branches['rel'] . '... '; - // @todo Implement this. - echo uw_wcms_tools_shell_color("Not implemented.\n", 'yellow'); + + $release_branch = uw_wcms_tools_query_gitlab_api('projects/' . $project->id . '/repository/branches/' . urlencode($current_branches['rel'])); + if ($release_branch['http_status'] !== 200) { + echo uw_wcms_tools_shell_color("Error.\n", 'red'); + var_dump($release_branch); + throw new Exception('Unable to load release branch.'); + } + + $dev_branch = uw_wcms_tools_query_gitlab_api('projects/' . $project->id . '/repository/branches/' . urlencode($current_branches['dev'])); + if ($dev_branch['http_status'] !== 200) { + echo uw_wcms_tools_shell_color("Error.\n", 'red'); + var_dump($dev_branch); + throw new Exception('Unable to load development branch.'); + } + + // Create array of commit hashes of release branch tip and its parents. + $tip_and_parents_of_release = array_merge([$release_branch['body']->commit->id], $release_branch['body']->commit->parent_ids); + // Test if there is development since the last merge. + if (in_array($dev_branch['body']->commit->id, $tip_and_parents_of_release)) { + echo uw_wcms_tools_shell_color("No development. Nothing to tag.\n", 'green'); + // Nothing to tag, so return now. + return; + } + else { + // @todo Implement this. + echo uw_wcms_tools_shell_color("Not implemented.\n", 'yellow'); + } } else { echo 'Create ' . $current_branches['rel'] . ' from ' . $current_branches['dev'] . '... '; -- GitLab From d8ab741e246972ae8886a9309223807807da3a27 Mon Sep 17 00:00:00 2001 From: Liam Morland Date: Fri, 21 May 2021 13:07:53 -0400 Subject: [PATCH 23/23] ISTWCMS-4802: Implement merging in uw_wcms_tools_gitlab_tag_release() --- uw_wcms_tools.gitlab.inc | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/uw_wcms_tools.gitlab.inc b/uw_wcms_tools.gitlab.inc index d5fba55..271f719 100644 --- a/uw_wcms_tools.gitlab.inc +++ b/uw_wcms_tools.gitlab.inc @@ -778,8 +778,40 @@ function uw_wcms_tools_gitlab_tag_release(string $namespace, string $path): void return; } else { - // @todo Implement this. - echo uw_wcms_tools_shell_color("Not implemented.\n", 'yellow'); + // Create merge request. + $params = [ + 'source_branch' => $current_branches['dev'], + 'target_branch' => $current_branches['rel'], + 'title' => 'Tag ' . $current_branches['tag_next'], + ]; + $merge_request = uw_wcms_tools_query_gitlab_api('projects/' . $project->id . '/merge_requests', $params, 'POST'); + if ($merge_request['http_status'] !== 201) { + echo uw_wcms_tools_shell_color("Error.\n", 'red'); + var_dump($merge_request); + throw new Exception('Unable to create merge request.'); + } + + // Accept (do) merge request. + // Accept will fail if it happens too soon after create. + sleep(1); + $params = [ + 'sha' => $dev_branch['body']->commit->id, + ]; + $merge_request = uw_wcms_tools_query_gitlab_api('projects/' . $project->id . '/merge_requests/' . $merge_request['body']->iid . '/merge', $params, 'PUT'); + if ($merge_request['http_status'] !== 200) { + echo uw_wcms_tools_shell_color("Error.\n", 'red'); + var_dump($merge_request); + throw new Exception('Unable to accept merge request.'); + } + + // Update release branch. + $release_branch = uw_wcms_tools_query_gitlab_api('projects/' . $project->id . '/repository/branches/' . urlencode($current_branches['rel'])); + if ($release_branch['http_status'] !== 200) { + echo uw_wcms_tools_shell_color("Error.\n", 'red'); + var_dump($release_branch); + throw new Exception('Unable to load release branch after merge.'); + } + echo uw_wcms_tools_shell_color("Done.\n", 'green'); } } else { -- GitLab