2020-04-23 19:48:55 +00:00
#!/bin/bash
2020-04-25 20:50:08 +00:00
# Executed when the master branch of PokeAPI/pokeapi gets updated
# Runs in CircleCI
# Generates new data using the latest changes of PokeAPI/pokeapi in order to open a Pull Request towards PokeAPI/api-data
2020-04-23 19:48:55 +00:00
set -o pipefail
org = 'PokeAPI'
data_repo = 'api-data'
2020-04-25 19:15:41 +00:00
engine_repo = 'pokeapi'
2020-05-02 17:59:09 +00:00
branch_name = 'staging'
2020-04-25 19:15:41 +00:00
username = 'pokeapi-machine-user'
email = 'pokeapi.co@gmail.com'
2020-06-01 20:01:56 +00:00
staging_environment_url = 'https://staging.pokeapi.co/api/v2/'
2020-05-13 14:14:42 +00:00
production_environment_url = 'https://pokeapi.co/api/v2/'
data_repo_url = 'https://github.com/PokeAPI/api-data'
engine_circleci_status_url = 'https://app.circleci.com/pipelines/github/PokeAPI/pokeapi'
deploy_circleci_status_url = 'https://app.circleci.com/pipelines/github/PokeAPI/deploy'
2020-07-23 17:22:12 +00:00
auth_header = " Authorization: token $MACHINE_USER_GITHUB_API_TOKEN "
2020-04-25 19:15:41 +00:00
2020-04-30 21:53:46 +00:00
# Exit the script notifying the user about its success
cleanexit( ) {
2020-04-25 19:15:41 +00:00
echo "Exiting"
echo " $2 "
2020-06-02 16:20:54 +00:00
if [ " $1 " = "success" ] ; then
2020-04-30 12:51:52 +00:00
notify_engine_pr "end_success"
2020-06-02 16:20:54 +00:00
exit 0
elif [ " $1 " = "no-deploy" ] ; then
notify_engine_pr "end_no_deploy"
exit 0
2020-07-11 14:09:28 +00:00
elif [ " $1 " = "no-new-data" ] ; then
notify_engine_pr "end_no_new_data"
exit 0
2020-06-02 16:20:54 +00:00
else
notify_engine_pr "end_failed"
exit 1
fi
}
# Checks if the PR carries a special `no-deploy` label
# If so it aborts the deployment
assert_no_deploy_label( ) {
engine_repo_pr_number = $( get_invokator_pr_number)
if [ " $engine_repo_pr_number " != "null" ] ; then
2020-07-23 17:22:12 +00:00
no_deploy_label = $( curl -f -H " $auth_header " -X GET " https://api.github.com/repos/ $org / $engine_repo /pulls/ $engine_repo_pr_number " | jq --raw-output '.labels | .[] | select(.name == "no-deploy") | .name' )
2020-06-02 16:20:54 +00:00
if [ " $no_deploy_label " = = 'no-deploy' ] ; then
cleanexit 'no-deploy' 'No-deploy label is present thus no need to deploy the project'
fi
2020-04-30 12:51:52 +00:00
fi
2020-04-25 19:15:41 +00:00
}
2020-04-23 19:48:55 +00:00
2020-04-25 20:40:21 +00:00
# Create and use a personal folder
2020-04-23 19:48:55 +00:00
prepare( ) {
2020-04-24 20:49:53 +00:00
mkdir -p ./repositories
2020-06-02 16:20:54 +00:00
cd repositories || cleanexit 'fail' "Failed to cd"
2020-04-25 19:15:41 +00:00
}
2020-05-31 21:25:59 +00:00
# GraphQL query to retrieve a PR's number based on a commit hash
2020-05-31 21:28:32 +00:00
pr_associated_with_sha_graphql_query_content( ) {
2020-05-31 21:25:59 +00:00
cat <<EOF
query associatedPRs {
repository( name: \" pokeapi\" , owner: \" PokeAPI\" ) {
commit: object( expression: \" $1 \" ) {
... on Commit {
associatedPullRequests( first: 1) {
edges {
node {
number
}
}
}
}
}
}
}
EOF
}
# Get the PR's numer associated with the last commit
get_invokator_pr_number_from_graphql( ) {
last_commit_sha = " $( git rev-parse HEAD) "
2020-05-31 21:28:32 +00:00
query = " $( pr_associated_with_sha_graphql_query_content " $last_commit_sha " ) "
2020-05-31 21:25:59 +00:00
query = $( echo $query ) # echo strips all IFS characters (newline, space)
2020-07-23 17:22:12 +00:00
pr_number = $( curl -s -H "Content-Type: application/json" -H " $auth_header " -X POST --data " {\"query\": \" $query \"} " "https://api.github.com/graphql" | jq ".data.repository.commit.associatedPullRequests.edges[0].node.number" )
2020-05-31 21:25:59 +00:00
echo " $pr_number "
}
2020-04-25 20:40:21 +00:00
# Check and return the number of the Pull Request that started this job
2020-04-25 19:15:41 +00:00
get_invokator_pr_number( ) {
2020-05-26 15:28:16 +00:00
commit_msg_regex = "Merge pull request #([0-9]+) from PokeAPI/(.*)"
2020-05-31 21:25:59 +00:00
last_commit_message = $( git log --oneline --format= %B -n 1 HEAD | head -n 1)
invokator_pr_number_from_graphql = " $( get_invokator_pr_number_from_graphql) "
2020-05-02 17:59:09 +00:00
if ! [ -z " $CIRCLE_PULL_REQUEST " ] ; then
2020-04-25 19:15:41 +00:00
echo " ${ CIRCLE_PULL_REQUEST ##*/ } "
2020-05-31 21:25:59 +00:00
elif [ " $invokator_pr_number_from_graphql " != 'null' ] ; then
echo " $invokator_pr_number_from_graphql "
elif [ [ $last_commit_message = ~ $commit_msg_regex ] ] ; then
2020-05-26 15:28:16 +00:00
echo " ${ BASH_REMATCH [1] } "
2020-05-02 17:59:09 +00:00
else
echo 'null'
2020-04-25 19:15:41 +00:00
fi
2020-04-23 19:48:55 +00:00
}
2020-04-25 20:40:21 +00:00
# Clone the repository containing the static JSON files
2020-04-23 19:48:55 +00:00
clone( ) {
2020-04-25 19:15:41 +00:00
git clone " https://github.com/ ${ org } / ${ data_repo } .git " " $data_repo "
2020-04-23 19:48:55 +00:00
}
2020-04-25 20:40:21 +00:00
# Configure git to use the supplied user when committing
2020-04-23 19:48:55 +00:00
configure_git( ) {
2020-04-25 19:15:41 +00:00
git config --global user.name " $username "
git config --global user.email " $email "
}
2020-04-30 12:51:52 +00:00
pr_input_updater_start( ) {
2020-04-25 19:15:41 +00:00
cat <<EOF
{
2020-06-02 16:20:54 +00:00
"body" : " A [PokeAPI/api-data]( ${ data_repo_url } ) refresh has started. In 45 minutes the staging branch of [PokeAPI/api-data]( ${ data_repo_url } /tree/staging) will be pushed with the new generated data. <br><br> The staging branch will be deployed in our [staging environment]( $staging_environment_url ) and you will be able to review the entire API. <br><br> A Pull Request ([master]( ${ data_repo_url } /tree/master)<-[staging]( ${ data_repo_url } /tree/staging)) will be also created at [PokeAPI/api-data]( ${ data_repo_url } /pulls) and assigned to the PokeAPI Core team to be reviewed. If approved and merged new data will soon be available worldwide at [pokeapi.co]( $production_environment_url ). "
2020-04-25 19:15:41 +00:00
}
EOF
}
2020-04-30 12:51:52 +00:00
pr_input_updater_end_success( ) {
cat <<EOF
{
2020-06-02 16:20:54 +00:00
"body" : " The updater script has finished its job and has now opened a Pull Request towards [PokeAPI/api-data]( ${ data_repo_url } /pulls) with the updated data. <br><br> You can see the Pull Request deployed at our [staging environment]( $staging_environment_url ) when [CircleCI deploy]( $deploy_circleci_status_url ) will be finished (_check the started time of the last build_). "
}
EOF
}
pr_input_updater_end_no_deploy( ) {
cat <<EOF
{
"body" : "This Pull Request won't be deployed since the label \`no-deploy\` was found in its meta-data."
2020-04-30 12:51:52 +00:00
}
EOF
}
pr_input_updater_end_failed( ) {
cat <<EOF
{
2020-07-23 17:22:12 +00:00
"body" : " The updater script could not finish its job. Please check [CircleCI's builds]( $engine_circleci_status_url ) and [logs]( ${ CIRCLE_BUILD_URL } ). "
2020-04-30 12:51:52 +00:00
}
EOF
}
2020-07-11 14:09:28 +00:00
pr_input_updater_end_no_new_data( ) {
cat <<EOF
{
"body" : " The updater script finished its job and the generated data didn't change. The deploy was thus skipped. For further information check [CircleCI's builds]( $engine_circleci_status_url ) and [logs]( ${ CIRCLE_BUILD_URL } ). "
}
EOF
}
2020-11-16 18:16:18 +00:00
# If the job was started by a Pull Request and not by a cron job, add a comment to notify the users
2020-04-30 12:51:52 +00:00
notify_engine_pr( ) {
2021-05-19 15:10:05 +00:00
local -r allowed_events = 'start end_failed end_success end_no_deploy end_no_new_data'
if [ [ " $allowed_events " = = *" $1 " * ] ] && [ [ " $CIRCLE_BRANCH " = = 'master' ] ] ; then
2020-05-13 15:38:08 +00:00
engine_repo_pr_number = $( get_invokator_pr_number)
2020-11-16 18:16:18 +00:00
if [ " $engine_repo_pr_number " != "null" ] && [ -n " $CIRCLE_USERNAME " ] ; then
2020-07-23 17:22:12 +00:00
curl -f -H " $auth_header " -X POST --data " $( pr_input_updater_$1 ) " " https://api.github.com/repos/ $org / $engine_repo /issues/ $engine_repo_pr_number /comments "
2020-04-30 12:51:52 +00:00
fi
2020-04-25 19:15:41 +00:00
fi
2020-04-23 19:48:55 +00:00
}
2020-04-25 20:40:21 +00:00
# Run the updater script (https://github.com/PokeAPI/api-data/blob/master/updater/cmd.bash) which will generate the new pokeapi data and push it to the api-data repository under a new branch
2020-04-24 20:49:53 +00:00
run_updater( ) {
2020-06-02 16:20:54 +00:00
cd " $data_repo /updater " || cleanexit 'fail' "Failed to cd"
2020-05-13 14:01:54 +00:00
# Wait to be sure PokeAPI/pokeapi's master branch has been updated on Github with the lastest merged PR content
2020-04-25 19:15:41 +00:00
sleep 10
# Build the updater image
2020-04-24 20:49:53 +00:00
docker build -t pokeapi-updater .
2020-04-25 19:15:41 +00:00
if [ $? -ne 0 ] ; then
2020-06-02 16:20:54 +00:00
cleanexit 'fail' "Failed to build the pokeapi-updater image"
2020-04-25 19:15:41 +00:00
fi
# Run the updater
2021-05-17 20:33:33 +00:00
docker run --privileged -e REPO_POKEAPI_CHECKOUT_OBJECT = " $CIRCLE_SHA1 " -e COMMIT_EMAIL = " $email " -e COMMIT_NAME = " $username " -e BRANCH_NAME = " $branch_name " -e REPO_POKEAPI = " https://github.com/ $org / $engine_repo .git " -e REPO_DATA = " https:// $MACHINE_USER_GITHUB_API_TOKEN @github.com/ $org / $data_repo .git " -e RUN_AS = 'root' pokeapi-updater
2020-07-11 14:09:28 +00:00
return_code = $?
if [ " $return_code " -eq 2 ] ; then
cleanexit 'no-new-data' "Generated data is the same as old data, skipping deploy"
elif [ " $return_code " -ne 0 ] ; then
2020-06-02 16:20:54 +00:00
cleanexit 'fail' "Failed to run the pokeapi-updater container"
2020-04-25 19:15:41 +00:00
fi
2020-06-03 16:19:19 +00:00
cd ../.. || cleanexit 'fail' "Failed to cd"
2020-04-23 19:48:55 +00:00
}
2020-04-25 20:40:21 +00:00
# Check if the updater script has pushed the data to a new branch
2020-04-25 19:15:41 +00:00
check_remote_branch( ) {
2020-04-25 20:40:21 +00:00
# Wait for Github to update origin/${branch_name}
sleep 10
2020-07-23 17:22:12 +00:00
curl -f -H " $auth_header " -X GET " https://api.github.com/repos/ $org / $data_repo /branches/ $1 "
2020-04-25 19:15:41 +00:00
if [ $? -ne 0 ] ; then
2020-06-02 16:20:54 +00:00
cleanexit 'fail' "The updater script failed to push the new data"
2020-04-25 19:15:41 +00:00
fi
}
2020-04-24 20:49:53 +00:00
2020-06-04 15:46:42 +00:00
pr_input_alredy_open( ) {
cat <<EOF
{
"base" : " $branch_name "
}
EOF
}
check_pr_already_open( ) {
2020-07-23 17:22:12 +00:00
data_repo_pr_number = $( curl -H " $auth_header " -X GET --data " $( pr_input_alredy_open) " " https://api.github.com/repos/ $org / $data_repo /pulls " | jq '.[0].number' )
2020-06-04 15:46:42 +00:00
echo " $data_repo_pr_number "
}
2020-05-26 15:28:16 +00:00
# Generate the input content that will be sent to Github's API to open a refresh-data PR towards PokeAPI/api-data
pr_input_content_with_pr_number( ) {
2020-04-23 19:48:55 +00:00
cat <<EOF
{
2020-05-02 17:59:09 +00:00
"title" : " API data update from \` ${ org } / ${ engine_repo } # ${ 1 } \` " ,
2020-05-13 14:14:42 +00:00
"body" : " Incoming data generated by [ ${ org } / ${ engine_repo } ](https://github.com/ ${ org } / ${ engine_repo } )'s CircleCI worker since Pull Request [# ${ 1 } ](https://github.com/ ${ org } / ${ engine_repo } /pull/ ${ 1 } ) was merged into the \`master\` branch. <br><br> The new data was generated using a copy of [ ${ org } / ${ engine_repo } ](https://github.com/ ${ org } / ${ engine_repo } /commits/master) repository when the \`HEAD\` was pointing to \` ${ CIRCLE_SHA1 } \`. <br><br> This Pull Request should have been deployed in our [staging environment]( $staging_environment_url ), check [here]( $deploy_circleci_status_url ) for the lastest build timestamp and status code. " ,
2020-04-23 19:48:55 +00:00
"head" : " $branch_name " ,
"base" : "master" ,
"assignees" : [
"Naramsim"
] ,
"labels" : [
"api-data-update"
]
}
EOF
}
2020-05-26 15:28:16 +00:00
# Copy of pr_input_content_with_pr_number
# run when the script cannot detect the merged PR number that started the CircleCI job
pr_input_content_without_pr_number( ) {
cat <<EOF
{
"title" : " API data update from \` ${ org } / ${ engine_repo } \` " ,
"body" : " Incoming data generated by [ ${ org } / ${ engine_repo } ](https://github.com/ ${ org } / ${ engine_repo } )'s CircleCI worker. <br><br> The new data was generated using a copy of [ ${ org } / ${ engine_repo } ](https://github.com/ ${ org } / ${ engine_repo } /commits/master) repository when the \`HEAD\` was pointing to \` ${ CIRCLE_SHA1 } \`. <br><br> This Pull Request should have been deployed in our [staging environment]( $staging_environment_url ), check [here]( $deploy_circleci_status_url ) for the lastest build timestamp and status code. " ,
"head" : " $branch_name " ,
"base" : "master" ,
"assignees" : [
"Naramsim"
] ,
"labels" : [
"api-data-update"
]
}
EOF
}
2020-06-04 15:46:42 +00:00
# Create/update a Pull Request to merge the branch recently pushed by the updater with the master branch
2020-04-25 20:40:21 +00:00
create_pr( ) {
2020-05-02 17:59:09 +00:00
engine_repo_pr_number = $( get_invokator_pr_number)
2020-06-04 15:46:42 +00:00
data_repo_pr_already_open_number = $( check_pr_already_open)
if [ " $data_repo_pr_already_open_number " != "null" ] ; then
data_repo_pr_number = " $data_repo_pr_already_open_number "
if [ " $engine_repo_pr_number " != "null" ] ; then
2020-07-23 17:22:12 +00:00
data_repo_pr_number = $( curl -H " $auth_header " -X PATCH --data " $( pr_input_content_with_pr_number " $engine_repo_pr_number " ) " " https://api.github.com/repos/ $org / $data_repo /pulls/ $data_repo_pr_already_open_number " | jq '.number' )
2020-06-04 15:46:42 +00:00
else
2020-07-23 17:22:12 +00:00
data_repo_pr_number = $( curl -H " $auth_header " -X PATCH --data " $( pr_input_content_without_pr_number) " " https://api.github.com/repos/ $org / $data_repo /pulls/ $data_repo_pr_already_open_number " | jq '.number' )
2020-06-04 15:46:42 +00:00
fi
2020-05-26 15:28:16 +00:00
else
2020-06-04 15:46:42 +00:00
if [ " $engine_repo_pr_number " != "null" ] ; then
2020-07-23 17:22:12 +00:00
data_repo_pr_number = $( curl -H " $auth_header " -X POST --data " $( pr_input_content_with_pr_number " $engine_repo_pr_number " ) " " https://api.github.com/repos/ $org / $data_repo /pulls " | jq '.number' )
2020-06-04 15:46:42 +00:00
else
2020-07-23 17:22:12 +00:00
data_repo_pr_number = $( curl -H " $auth_header " -X POST --data " $( pr_input_content_without_pr_number) " " https://api.github.com/repos/ $org / $data_repo /pulls " | jq '.number' )
2020-06-04 15:46:42 +00:00
fi
2020-05-26 15:28:16 +00:00
fi
2020-04-30 12:51:52 +00:00
if [ [ " $data_repo_pr_number " = "null" ] ] ; then
2020-07-23 17:22:12 +00:00
cleanexit 'fail' "Could not create the Pull Request"
2020-04-25 20:40:21 +00:00
fi
2020-04-30 12:51:52 +00:00
echo " $data_repo_pr_number "
2020-04-25 20:40:21 +00:00
}
pr_input_assignees_and_labels( ) {
2020-04-23 20:31:08 +00:00
cat <<EOF
{
"assignees" : [
"Naramsim"
] ,
"labels" : [
"api-data-update"
]
}
EOF
}
2020-04-25 20:40:21 +00:00
# Assign the PR to Naramsim and add a label
customize_pr( ) {
# Wait for Github to open the PR
sleep 10
2020-04-30 12:51:52 +00:00
data_repo_pr_number = $1
2020-07-23 17:22:12 +00:00
curl -H " $auth_header " -X PATCH --data " $( pr_input_assignees_and_labels) " " https://api.github.com/repos/ $org / $data_repo /issues/ $data_repo_pr_number "
2020-04-25 20:40:21 +00:00
if [ $? -ne 0 ] ; then
2020-07-23 17:22:12 +00:00
echo "Could not add Assignees and Labes to the Pull Request"
2020-04-25 20:40:21 +00:00
fi
}
2020-04-25 20:50:08 +00:00
pr_input_reviewers( ) {
2020-04-23 19:48:55 +00:00
cat <<EOF
{
"reviewers" : [
"Naramsim"
2020-04-25 20:50:08 +00:00
] ,
"team_reviewers" : [
"core-team"
2020-04-23 19:48:55 +00:00
]
}
EOF
}
2020-04-25 20:40:21 +00:00
# Request the Core team to review the Pull Request
add_reviewers_to_pr( ) {
2020-04-30 12:51:52 +00:00
data_repo_pr_number = $1
2020-07-23 17:22:12 +00:00
curl -H " $auth_header " -X POST --data " $( pr_input_reviewers) " " https://api.github.com/repos/ $org / $data_repo /pulls/ $data_repo_pr_number /requested_reviewers "
2020-04-24 19:18:26 +00:00
if [ $? -ne 0 ] ; then
2020-07-23 17:22:12 +00:00
echo "Could not add Reviewers to the Pull Request"
2020-04-24 19:18:26 +00:00
fi
2020-04-23 19:48:55 +00:00
}
2020-06-02 16:20:54 +00:00
assert_no_deploy_label
2020-04-23 19:48:55 +00:00
prepare
configure_git
2020-04-30 21:53:46 +00:00
clone
2020-04-30 12:51:52 +00:00
notify_engine_pr "start"
2020-04-24 20:49:53 +00:00
run_updater
2020-04-25 19:15:41 +00:00
check_remote_branch " $branch_name "
2020-05-03 15:16:02 +00:00
if [ " $CIRCLE_BRANCH " = 'master' ] ; then
sleep 300 # 5 minutes, the time it takes for CircleCI's api-data script to generate the data and for CircleCI's deploy script to deploy it to the staging environment
check_remote_branch " $branch_name "
data_repo_pr_number = $( create_pr)
customize_pr " $data_repo_pr_number "
add_reviewers_to_pr " $data_repo_pr_number "
fi
2020-06-02 16:20:54 +00:00
cleanexit 'success' 'Done'