The integration of CI/CD tools like Bitbucket Pipelines with cloud hosting services such as Platform.sh can significantly streamline the development process. This article will expand upon how to use Bitbucket Pipelines as a VM to run Cypress tests, with an emphasis on the use of activity scripts in Platform.sh and the mechanism of passing the base URL from the activity script to Bitbucket.
The Role of Activity Scripts in Platform.sh
Platform.sh provides a powerful feature called "activity scripts" that allows you to respond to various events within your project's lifecycle. These scripts can be used for a range of tasks, from notifications to triggering external services like Bitbucket Pipelines.
Adding and Using Activity Scripts
- Creation: Write a script in a language supported by your Platform.sh environment (e.g., JavaScript, Python).
- Configuration: Add the script to your project via the
.platform.app.yaml
file or through the Platform.sh user interface. - Execution: The script runs automatically in response to specified events (like a successful push or a completed deployment).
Passing the Base URL from Platform.sh to Bitbucket
The key to linking Platform.sh deployments with Bitbucket Pipelines lies in the handover of the environment's base URL. Here's how it works:
- Retrieving the URL: After a successful deployment on Platform.sh, the activity script extracts the URL of the new environment. This is crucial as Cypress tests need to run against the live version of the application.
- Triggering Bitbucket Pipeline: The script then makes an API call to Bitbucket to trigger a pipeline. This call includes the base URL as a parameter.
- Using the URL in Bitbucket: In the Bitbucket pipeline configuration, the
BASE_URL
environment variable is set, allowing Cypress to run tests against this specific URL.
Detailed Activity Script Process
The activity script in Platform.sh performs several steps:
- Check Deployment Status: It ensures the deployment is successful and the environment is active.
- Extract URL: The script then fetches the URL of the deployed environment.
- Trigger Pipeline: It calls the Bitbucket API, passing the URL and necessary authentication tokens.
Sample Activity Script
const bbUser = 'mybitbucketuserhere';
const bbRepo = 'mybitbucketrepohere';
try {
// be sure it's a real deployment
if (typeof activity.payload.deployment === "undefined") {
console.log(
"Deployment payload (and therefore Variables) is unavailable in this state: " +
activity.state
);
throw new Error("No deployment payload");
}
// get any variables necessary
var bbToken = 'bitbuckettoken';
// verify the run was successful and environment is active
if (
activity.result !== "success" ||
activity.payload.environment.status !== "active" ||
!bbToken
) {
console.log("A fatal error has occurred");
console.log("Activity Result", activity.result);
console.log("Activity Env Status", activity.payload.environment.status);
console.log("Bitbucket token length", bbToken.length);
throw new Error("Fatal Error");
}
// get the URL of the environment (dynamic)
var routes = activity.payload.deployment.routes;
var route = Object.keys(activity.payload.deployment.routes).reduce(function (
accumulator,
key
) {
return routes[key].primary ? key : accumulator;
},
routes[0] || false);
if (!route) {
throw new Error(`No route provided: ${routes}`);
}
trigger_bitbucket_pipeline(route, bbToken);
} catch (exception) {
console.log("An exception has been thrown: " + exception);
}
function trigger_bitbucket_pipeline(baseUrl, bbToken) {
var requestOptions = {
method: "POST",
headers: {
Accept: "application/json",
Authorization: `Bearer ${bbToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"target": {
"ref_type": "branch",
"type": "pipeline_ref_target",
"ref_name": "master"
},
"variables": [
{
"key" : "BASE_URL",
"value" : baseUrl,
"secured": false
}
]
}),
redirect: "follow",
};
var response = fetch(
`https://api.bitbucket.org/2.0/repositories/mybbuser/mybbrepo/pipelines/`,
requestOptions
);
if (!response.ok) {
console.log("Request to Bitbucket Pipeline API Failed", response.body.text());
} else {
console.log("Request to Bitbucket Pipeline API Succeeded");
// this returns a 204 with no content
}
}
/**
* A simple function to parse the environment variables. This reads them exactly as they are created in the PSH UI.
* e.g. if you need env:TOKEN you need to ask for variables()['env:TOKEN'] explicitly.
*/
function variables() {
var vars = {};
activity.payload.deployment.variables.forEach(function (variable) {
vars[variable.name] = variable.value;
});
return vars;
}
Bitbucket Pipeline Configuration
# Use the official cypress docker container.
image: cypress/base:18.16.0
pipelines:
default:
- step:
script:
- echo "$BASE_URL"
- npm install
- ./node_modules/.bin/cypress run --config "baseUrl=$BASE_URL"
after-script:
- apt-get update
- apt-get install curl -y
- ./post.sh # custom bash script to post the results to custom endpoint
artifacts:
- cypress/screenshots/**
In the Bitbucket bitbucket-pipelines.yml
, the BASE_URL
is used by Cypress:
Cypress is configured to run tests against the BASE_URL
, ensuring that the tests are relevant to the latest deployment.
Integration Workflow - Expanded
- Code Push: Developers push code to Bitbucket.
- Automatic Deployment: Bitbucket triggers a pipeline for deployment on Platform.sh.
- Activity Script Execution: Post-deployment, the script on Platform.sh runs, fetching the base URL.
- Triggering Test Pipeline: This script then triggers the Cypress test pipeline in Bitbucket.
- Running Cypress Tests: Bitbucket runs Cypress tests against the base URL of the deployed site.
- Review and Iterate: Developers review test results and iterate as needed.
Conclusion
The integration of Bitbucket Pipelines with Platform.sh using activity scripts offers an automated, efficient pipeline for deploying and testing web applications. By leveraging these tools, teams can ensure that their applications are consistently tested in real-world scenarios, leading to higher quality and more reliable software deliveries. This process not only saves time but also significantly reduces the risk of errors and bugs making it into production environments.
Add new comment