woocommerce/.github/workflows/scripts/post-request-shared.php

285 lines
8.2 KiB
PHP
Raw Normal View History

<?php
/**
* Common code for the post-merge GitHub action scripts.
*
* @package WooCommerce/GithubActions
*/
// phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped, WordPress.WP.AlternativeFunctions
global $repo_owner, $repo_name, $github_token, $graphql_api_url;
/*
* Grab/process input.
*/
$repo_parts = explode( '/', getenv( 'GITHUB_REPOSITORY' ) );
$repo_owner = $repo_parts[0];
$repo_name = $repo_parts[1];
$pr_id = getenv( 'PULL_REQUEST_ID' );
$github_token = getenv( 'GITHUB_TOKEN' );
$github_api_url = getenv( 'GITHUB_API_URL' );
$graphql_api_url = getenv( 'GITHUB_GRAPHQL_URL' );
/**
* Function to get the latest milestone.
*
* @param bool $use_latest_when_null When true, the function returns the latest milestone regardless of release branch status.
* @return string The title of the latest milestone.
*/
function get_latest_milestone_from_api( $use_latest_when_null = false ) {
global $repo_owner, $repo_name;
echo 'Getting the list of milestones...' . PHP_EOL;
$query = "
repository(owner:\"$repo_owner\", name:\"$repo_name\") {
milestones(first: 10, states: [OPEN], orderBy: {field: CREATED_AT, direction: DESC}) {
nodes {
id
title
state
}
}
}
";
$json = do_graphql_api_request( $query );
$milestones = $json['data']['repository']['milestones']['nodes'];
$milestones = array_map(
function( $x ) {
return 1 === preg_match( '/^\d+\.\d+\.\d+$/D', $x['title'] ) ? $x : null;
},
$milestones
);
$milestones = array_filter( $milestones );
usort(
$milestones,
function( $a, $b ) {
return version_compare( $b['title'], $a['title'] );
}
);
echo 'Latest open milestone: ' . $milestones[0]['title'] . PHP_EOL;
$chosen_milestone = null;
foreach ( $milestones as $milestone ) {
$milestone_title_parts = explode( '.', $milestone['title'] );
$milestone_release_branch = 'release/' . $milestone_title_parts[0] . '.' . $milestone_title_parts[1];
$query = "
repository(owner:\"$repo_owner\", name:\"$repo_name\") {
ref(qualifiedName: \"refs/heads/$milestone_release_branch\") {
id
}
}
";
$result = do_graphql_api_request( $query );
if ( is_null( $result['data']['repository']['ref'] ) ) {
$chosen_milestone = $milestone;
} else {
break;
}
}
// If all the milestones have a release branch, just take the newest one.
if ( $use_latest_when_null && is_null( $chosen_milestone ) ) {
echo 'WARNING: No milestone without release branch found, the newest one will be assigned.' . PHP_EOL;
$chosen_milestone = $milestones[0];
}
return $chosen_milestone;
}
/**
* Function to get the last major.minor version with a release from the API.
*
* @return string Returns the latest version with a release formatted as "major.minor".
*/
function get_latest_version_with_release() {
global $repo_owner, $repo_name;
echo 'Getting the list of releases...' . PHP_EOL;
$query = "
repository(owner:\"$repo_owner\", name:\"$repo_name\") {
releases(first: 25, orderBy: { field: CREATED_AT, direction: DESC}) {
nodes {
tagName
}
}
}
";
$json = do_graphql_api_request( $query );
$releases = $json['data']['repository']['releases']['nodes'];
$releases = array_map(
function( $x ) {
return 1 === preg_match( '/^\d+\.\d+\.\d+/D', $x['tagName'] ) ? $x : null;
},
$releases
);
$releases = array_filter( $releases );
usort(
$releases,
function( $a, $b ) {
return version_compare( $b['tagName'], $a['tagName'] );
}
);
$major_minor = preg_replace( '/(^\d+\.\d+).*?$/', '\1', $releases[0]['tagName'] );
echo 'Most recent version with a release: ' . $major_minor . PHP_EOL;
return $major_minor;
}
/**
Fix/37502: Correct spelling errors. (#37887) * change reference of Catpure to Capture Co-Authored-By: Vikram <93216400+vikrampm1@users.noreply.github.com> * change reference of expicitly to explicitly Co-Authored-By: Vikram <93216400+vikrampm1@users.noreply.github.com> * change reference 'cutted' to 'cut' * change reference 'determening' to 'determining' * change reference 'retreive' to 'retrieve' * change reference 'neccessary' to 'necessary' * change reference 'Fitler' to 'Filter' * change reference of "seperate" to "separate" Co-Authored-By: Ankit K Gupta <ankit.himcs@gmail.com> * change reference of "wether" to "whether" Co-Authored-By: Sumit Bagthariya <67687255+qasumitbagthariya@users.noreply.github.com> * change reference of "staus" to "status" * change reference of "retrive" to "retrieve" * change references of "gatways" to "gateways" * change references of "existant" to "existent" * change reference of "requries" to "requires" * change reference of "configuation" to "configuration" * change reference of "processsing" to "processing" * change reference of "represenation" to "representation" * change reference of "dimentions" to "dimensions" * change references of "reigster" to "register" * change reference of "colum" to "column" * change reference of "transtions" to "transitions" * change references of "intially" to "initially" * change references of "orignal" to "original" * change references of "deprected" to "deprecated" * change references of "paramter" to "parameter" * change reference of "intance" to "instance" * change reference of "elemets" to "elements" * change references of "funcitons" to "functions" * change reference of "specificed" to "specified" * change references of "atributes" to "attributes" * change reference of "tast" to "task" * change reference of "chaning" to "changing" * change reference of "retreiving" to "retrieving" * change reference of "caluclation" to "calculation" * change references of "Invaid" to "Invalid" * change references of "paramaters" to "parameters" * change reference of "Additonal" to "Additional" * change reference of "teh" to "the" * change reference of "evalutes" to "evaluates" * change reference of "addedd" to "added" * change reference of "excempt" to "exempt" * change reference of "sequencially" to "sequentially" * change reference of "previos" to "previous" * change reference of "elegible" to "eligible" * change references of "Boostrap" to "Bootstrap" * change references of "compability" to "compatibility" * change reference of "heirarchy" to "hierarchy" * change references of "visibilty" to "visibility" * change reference of "comparsion" to "comparison" * change reference of "capabilties" to "capabilities" * change reference of "datatores" to "datastores" * change reference of "occured" to "occurred" * change reference of "coresponding" to "corresponding" * change references of "thier" to "their" * change reference of "sucessfully" to "successfully" * change reference of "insde" to "inside" * change reference of "nagivation" to "navigation" * change references of "visiblity" to "visibility" * change reference of "documentaiton" to "documentation" * change reference of "anayltics" to "analytics" * change reference of "intalling" to "installing" * change reference of "mininum" to "minimum" * change references of "intial" to "initial" * change reference of "Feld" to "Field" * change reference of "taks" to "task" * change reference of "trasnfer" to "transfer" * change reference of "respone" to "response" * change reference of "Extenstions" to "Extensions" * change reference of "detault" to "default" * change reference of "simultanious" to "simultaneous" * change reference of "overides" to "overrides" * change references of "Indvidual" to "Individual" * change reference of "refering" to "referring" * change reference of "aginst" to "against" * change reference of "execuatable" to "executable" * change reference of "repsonse" to "response" * change reference of "documention" to "documentation" * change reference of "asumed" to "assumed" * change reference of "Minium" to "Minimum" * change reference of "unqiue" to "unique" * change references of "existance" to "existence" * change reference of "compatability" to "compatibility" * change reference of "Taxnomy" to "Taxonomy" * change reference of "quering" to "querying" * change reference of "retrun" to "return" * change reference of "informations" to "information" Co-Authored-By: Viktor Szépe <viktor@szepe.net> * Add changelog * Add changelog * Fix typo --------- Co-authored-by: Vikram <93216400+vikrampm1@users.noreply.github.com> Co-authored-by: Ankit K Gupta <ankit.himcs@gmail.com> Co-authored-by: Sumit Bagthariya <67687255+qasumitbagthariya@users.noreply.github.com> Co-authored-by: Viktor Szépe <viktor@szepe.net> Co-authored-by: Chi-Hsuan Huang <chihsuan.tw@gmail.com>
2023-05-08 07:55:09 +00:00
* Function to retrieve the sha1 reference for a given branch name.
*
* @param string $branch The name of the branch.
* @return string Returns the name of the branch, or a falsey value on error.
*/
function get_ref_from_branch( $branch ) {
global $repo_owner, $repo_name;
$query = "
repository(owner:\"$repo_owner\", name:\"$repo_name\") {
ref(qualifiedName: \"refs/heads/{$branch}\") {
target {
... on Commit {
history(first: 1) {
edges{ node{ oid } }
}
}
}
}
}
";
$result = do_graphql_api_request( $query );
// Warnings suppressed here because traversing this level of arrays with isset / is_array checks would be messy.
return @$result['data']['repository']['ref']['target']['history']['edges'][0]['node']['oid'];
}
/**
* Function to create milestone using the GitHub REST API.
*
* @param string $title The title of the milestone to be created.
* @return bool True on success, False otherwise.
*/
function create_github_milestone( $title ) {
global $repo_owner, $repo_name;
$result = do_github_api_post_request( "/repos/{$repo_owner}/{$repo_name}/milestones", array(
'title' => $title,
) );
return is_array( $result ) && $result['title'] === $title;
}
/**
* Function to create branch using the GitHub REST API.
*
* @param string $branch The branch to be created.
* @param string $sha The sha1 reference for the branch.
* @return bool True on success, False otherwise.
*/
function create_github_branch( $branch, $sha ) {
global $repo_owner, $repo_name;
$ref = "refs/heads/{$branch}";
$result = do_github_api_post_request( "/repos/{$repo_owner}/{$repo_name}/git/refs", array(
'ref' => $ref,
'sha' => $sha,
) );
return is_array( $result ) && $result['ref'] === $ref;
}
/**
* Function to create branch using the GitHub REST API from an existing branch.
*
* @param string $source The branch from which to create.
* @param string $target The branch to be created.
* @return bool True on success, False otherwise.
*/
function create_github_branch_from_branch( $source, $target ) {
$ref = get_ref_from_branch( $source );
if ( ! $ref ) {
return false;
}
return create_github_branch( $target, $ref );
}
/**
* Function to do a GitHub API POST Request.
*
* @param array $request_url
* @param array $body The body of the request to be json encoded.
* @return mixed The json-decoded response if a response is received, 'false' (or whatever file_get_contents returns) otherwise.
*/
function do_github_api_post_request( $request_path, $body ) {
global $github_token, $github_api_url, $github_api_response_code;
$context = stream_context_create(
array(
'http' => array(
'method' => 'POST',
'header' => array(
'Accept: application/vnd.github.v3+json',
'Content-Type: application/json',
'User-Agent: GitHub Actions for creation of milestones',
'Authorization: bearer ' . $github_token,
),
'content' => json_encode( $body ),
),
)
);
$full_request_url = rtrim( $github_api_url, '/' ) . '/' . ltrim( $request_path, '/' );
$result = @file_get_contents( $full_request_url, false, $context );
// Verify that the post request was sucessful.
$status_line = $http_response_header[0];
preg_match( "/^HTTPS?\/\d\.\d\s+(\d{3})\s+/i", $status_line, $matches );
$github_api_response_code = $matches[1];
if ( '2' !== substr( $github_api_response_code, 0, 1 ) ) {
return false;
}
return is_string( $result ) ? json_decode( $result, true ) : $result;
}
/**
* Function to query the GitHub GraphQL API.
*
* @param string $body The GraphQL-formatted request body, without "query" or "mutation" wrapper.
* @param bool $is_mutation True if the request is a mutation, false if it's a query.
* @return mixed The json-decoded response if a response is received, 'false' (or whatever file_get_contents returns) otherwise.
*/
function do_graphql_api_request( $body, $is_mutation = false ) {
global $github_token, $graphql_api_url;
$keyword = $is_mutation ? 'mutation' : 'query';
$data = array( 'query' => "$keyword { $body }" );
$context = stream_context_create(
array(
'http' => array(
'method' => 'POST',
'header' => array(
'Accept: application/json',
'Content-Type: application/json',
'User-Agent: GitHub action to set the milestone for a pull request',
'Authorization: bearer ' . $github_token,
),
'content' => json_encode( $data ),
),
)
);
$result = file_get_contents( $graphql_api_url, false, $context );
return is_string( $result ) ? json_decode( $result, true ) : $result;
}
// phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped, WordPress.WP.AlternativeFunctions