After the build is complete, Pipelines creates a “build artifact” consisting of the contents of the SOURCE_DIR and commits the artifact to your Cloud Platform repository in a build branch named pipelines-build-[BRANCHNAME]
by default.
Pipelines commits build artifacts automatically and does not log the results of the commit. However, the pipelines start command does display the path of the build branch in the repository.
Why is the build artifact created in the repository?
Storing the build artifact in your Cloud Platform repository provides the following advantages over alternatives such as creating a tarball:
- You can easily deploy the build artifact to your Cloud Platform environments, using the Cloud Platform interface or the Cloud API.
- You can easily view the build artifact using Git.
- You can more easily debug your build process, comparing the build artifact against what you may have expected, and compare build artifacts over time, using a tool like
git diff
. - You can control how long your build artifacts are retained, since you control the contents of your own repository. You may, for example, have compliance requirements that mandate keeping them for a specified time, or security concerns that require you to be able to delete them promptly.
- You can easily copy a build artifact to other systems for such purposes as static code analysis or license compliance.
Deploying the build artifact
After you complete a build, you can deploy the resulting build artifact in any Cloud Platform environment. You can do this by selecting the build branch for deployment by using the Cloud Platform user interface or Cloud API.
After you set the deployed branch of an environment to a build branch, each build artifact committed to that branch is deployed immediately, without requiring any intervention. For example, if you build the master branch, and your Cloud Platform development environment is set to the pipelines-build-master
branch, the build artifact is deployed immediately to that development environment when the pipeline job completes successfully.
Note
- You cannot control the branch name or tag name committed by Pipelines. These values are always based on your source branch or tag. For example,
pipelines-build-[branch_name]
orpipelines-build-[tag_name]
. - Automatic deployment does not work with Node.js environments. To create your own shell script file for deploying artifacts, see Creating a shell script for deploying artifacts.
Creating a shell script for deploying artifacts
To write a shell script for deploying artifacts, create a file named deploy-artifact.sh
, and place it in the root directory of the repository. Ensure that the file contains the following:
#!/bin/bash
set -e
# This is a script to deploy NodeJs artifact
# Note: This script doesn't handle the token expiry or any API exceptions/errors.
# A function to end script unsuccessfuly
err() {
echo "Failed to deploy the artifact, check task log for more details at $PIPELINE_JOB_URL"
exit 1
}
if [[ -z "${TARGET_ENV_NAME}" ]]
then
echo "Target environment name is not defined, make sure that TARGET_ENV_NAME environment variable is set"
err
fi
if [[ -z "${PIPELINE_ARTIFACT_START_LOG}" ]]
then
echo "Pipeline artifact start log is not defined, make sure that PIPELINE_ARTIFACT_START_LOG environment variable is set"
err
fi
# Get Cloud Authentication token. For more details: https://docs.acquia.com/acquia-cloud/develop/api/auth/
max_retries=3
attempt=1
delay=5
TOKEN=""
while [ $attempt -le $max_retries ]; do
echo "Attempt $attempt: Contacting endpoint for token generation:"
response=$(curl -sS -w "\n%{http_code}" -X POST -u "${CLOUD_API_KEY}:${CLOUD_API_SECRET}" -d "grant_type=client_credentials" https://accounts.acquia.com/api/auth/oauth/token)
http_code=$(echo "$response" | tail -n1)
echo "HTTP code: $http_code"
response_body=$(echo "$response" | sed '$d')
if [[ $http_code -ge 200 && $http_code -lt 300 ]]; then
echo "Retrieving token:"
TOKEN=$(echo "$response_body" | python3 -c "import sys, json; print(json.load(sys.stdin)['access_token'])")
echo "Token retrieved from response"
break
else
echo "Request failed with HTTP $http_code. Response body: $response_body"
echo "Retrying in $delay seconds..."
sleep $delay
((attempt++))
fi
done
if [[ -z "$TOKEN" ]]; then
echo "Failed to obtain token after $attempt attempts."
exit 1
fi
# Get target environment Id.
attempt=1
TARGET_ENV_ID=""
while [ $attempt -le $max_retries ]; do
echo "Attempt $attempt: Contacting endpoint for TARGET_ENV_ID:"
response=$(curl -sS -w "\n%{http_code}" -X GET "https://cloud.acquia.com/api/applications/$PIPELINE_APPLICATION_ID/environments" -H "Content-Type: application/json" -H "Authorization: Bearer ${TOKEN}")
http_code=$(echo "$response" | tail -n1)
echo "HTTP code: $http_code"
response_body=$(echo "$response" | sed '$d')
if [[ $http_code -ge 200 && $http_code -lt 300 ]]; then
echo "Retrieving TARGET_ENV_ID:"
TARGET_ENV_ID=$(echo "$response_body" | python3 -c "import sys, json; envs=json.load(sys.stdin)['_embedded']['items']; print([x for x in envs if x['name'] == '$TARGET_ENV_NAME'][0]['id'])")
echo "TARGET_ENV_ID is $TARGET_ENV_ID"
break
else
echo "Request failed with HTTP $http_code. Response body: $response_body"
echo "Retrying in $delay seconds..."
sleep $delay
((attempt++))
fi
done
if [[ -z "$TARGET_ENV_ID" ]]; then
echo "Failed to obtain TARGET_ENV_ID after $attempt attempts."
exit 1
fi
# Get artifact id from pipeline-artifact start log.
ARTIFACT_ID=$(grep artifactId $PIPELINE_ARTIFACT_START_LOG | cut -d ' ' -f3)
echo ARTIFACT_ID is $ARTIFACT_ID
# Put artifact id into pipeline metadata, so you can get it later if necessary.
pipelines_metadata artifact_id $ARTIFACT_ID
# Deploy artifact to target envronment. Use the notification url returned to get the tasks's status.
# For more details: http://cloudapi-docs.acquia.com/#/Environments/postDeployArtifact
attempt=1
NOTIFICATION_LINK=""
while [ $attempt -le $max_retries ]; do
echo "Attempt $attempt: Contacting endpoint for NOTIFICATION_LINK:"
response=$(curl -sS -w "\n%{http_code}" -X POST -d "{\"artifact_id\":\"$ARTIFACT_ID\"}" "https://cloud.acquia.com/api/environments/$TARGET_ENV_ID/artifacts/actions/switch" -H "Content-Type: application/json" -H "Authorization: Bearer ${TOKEN}")
http_code=$(echo "$response" | tail -n1)
echo "HTTP code: $http_code"
response_body=$(echo "$response" | sed '$d')
if [[ $http_code -ge 200 && $http_code -lt 300 ]]; then
echo "Retrieving NOTIFICATION_LINK:"
NOTIFICATION_LINK=$(echo "$response_body" | python3 -c "import sys, json; print(json.load(sys.stdin)['_links']['notification']['href'])")
echo "NOTIFICATION_LINK is $NOTIFICATION_LINK"
break
else
echo "Request failed with HTTP $http_code. Response body: $response_body"
echo "Retrying in $delay seconds..."
sleep $delay
((attempt++))
fi
done
if [[ -z "$NOTIFICATION_LINK" ]]; then
echo "Failed to obtain NOTIFICATION_LINK after $max_retries attempts."
exit 1
fi
# Poll NOTIFICATION_LINK to know the task status, the status will be 'in-progress' until the task is finished. For more details: https://cloudapi-docs.acquia.com/#/Notifications/getNotificationByUuid
#DEPLOY_STATUS='in-progress'
attempt=1
DEPLOY_STATUS=""
while [ $attempt -le $max_retries ]; do
echo "Attempt $attempt: Checking deployment status from NOTIFICATION_LINK:"
response=$(curl -sS -w "\n%{http_code}" -X GET "$NOTIFICATION_LINK" -H "Content-Type: application/json" -H "Authorization: Bearer ${TOKEN}")
http_code=$(echo "$response" | tail -n1)
response_body=$(echo "$response" | sed '$d')
if [[ $http_code -ge 200 && $http_code -lt 300 ]]; then
DEPLOY_STATUS=$(echo "$response_body" | python3 -c "import sys, json; print(json.load(sys.stdin)['status'])")
echo "Current deployment status: $DEPLOY_STATUS"
# Exit the loop if the deployment status is fetched successfully
break
else
echo "Request failed with HTTP $http_code. Response body: $response_body"
echo "Retrying in $delay seconds..."
sleep $delay
((attempt++))
fi
done
if [[ -z "$DEPLOY_STATUS" ]]; then
echo "Failed to retrieve DEPLOY_STATUS after $max_retries attempts."
exit 1
fi
echo "Waiting for the deployment to be finished, current status: $DEPLOY_STATUS."
# Tracking deployment status
while [ "$DEPLOY_STATUS" = 'in-progress' ]; do
sleep 60
echo "Tracking DEPLOY_STATUS ..."
attempt=1
TOKEN=""
while [ $attempt -le $max_retries ]; do
echo "Attempt $attempt: Contacting endpoint for token re-generation:"
response=$(curl -sS -w "\n%{http_code}" -X POST -u "${CLOUD_API_KEY}:${CLOUD_API_SECRET}" -d "grant_type=client_credentials" https://accounts.acquia.com/api/auth/oauth/token)
http_code=$(echo "$response" | tail -n1)
echo "HTTP code: $http_code"
response_body=$(echo "$response" | sed '$d')
if [[ $http_code -ge 200 && $http_code -lt 300 ]]; then
echo "Retrieving token:"
TOKEN=$(echo "$response_body" | python3 -c "import sys, json; print(json.load(sys.stdin)['access_token'])")
echo "Token retrieved from response"
echo "New TOKEN generated";
break
else
echo "Request failed with HTTP $http_code. Response body: $response_body"
echo "Retrying in $delay seconds..."
sleep $delay
((attempt++))
fi
done
if [[ -z "$TOKEN" ]]; then
echo "Failed to obtain token after $attempt attempts."
exit 1
fi
# Poll NOTIFICATION_LINK to know the task status
attempt=1
DEPLOY_STATUS=""
while [ $attempt -le $max_retries ]; do
echo "Attempt $attempt: Checking deployment status from NOTIFICATION_LINK:"
response=$(curl -sS -w "\n%{http_code}" -X GET "$NOTIFICATION_LINK" -H "Content-Type: application/json" -H "Authorization: Bearer ${TOKEN}")
http_code=$(echo "$response" | tail -n1)
response_body=$(echo "$response" | sed '$d')
if [[ $http_code -ge 200 && $http_code -lt 300 ]]; then
DEPLOY_STATUS=$(echo "$response_body" | python3 -c "import sys, json; print(json.load(sys.stdin)['status'])")
echo "Current deployment status: $DEPLOY_STATUS"
# Exit the loop if the deployment status is fetched successfully
break
else
echo "Request failed with HTTP $http_code. Response body: $response_body"
echo "Retrying in $delay seconds..."
sleep $delay
((attempt++))
fi
done
if [[ -z "$DEPLOY_STATUS" ]]; then
echo "Failed to retrieve DEPLOY_STATUS after $max_retries attempts."
exit 1
fi
echo "Waiting for the deployment to be finished, current status: $DEPLOY_STATUS."
done
echo $DEPLOY_STATUS
# Exit with 1 if the final status is 'failed'. Do nothing if the final status is 'completed' which mean the deployment is successful.
if [ "$DEPLOY_STATUS" = 'failed' ]
then
err
fi
Node.js build artifacts
Node.js application support in Cloud Platform uses the Cloud Platform pipelines functionality to build an artifact that you can then deploy to your environment.
Each artifact has a name, which enables you to select a specific artifact by that name in the deployment phase. When you deploy, the most recently built artifact will be at the top of the list. The default naming convention for node artifacts is as follows:
[git branch]@[commit hash]
This can cause issues, as commits can be amended. This can result in two artifacts with the same name but with different comments.
It is possible to set a default name for your artifact by adding configurations to your yaml
file using the pipelines-artifact command and pipelines variables. To do this, complete the following steps:
- Edit your build definition file. For examples, see Example Pipelines build definition files.
Find the following line in the file:
- pipelines-artifact start
Edit the line by adding the
PIPELINE_VCS_PATH
andPIPELINE_GIT_HEAD_REF
options to your start command, similar to the following:- PIPELINE_VCS_PATH=artifact PIPELINE_GIT_HEAD_REF=example pipelines-artifact start
- Save the build definition file.
Using this example, your artifact name will become artifact@example
rather than branch@commit
.