Setting up a Continuous Integration pipeline from A to Z that: runs tests, builds the app and deploys it to Netlify. Let’s do it! 🤓
By now you’ve probably deployed a project to Netlify using their UI by linking a GitHub/GitLab project and setting up the necessary steps to build the app.’
What you may not know is that Netlify has a Node-based CLI tool that lets you deploy from the terminal.
Moreover, GitLab’s CI/CD pipelines provide 2,000 monthly CI pipeline minutes for free that we can use to automate our test & deploy process.
- Create a new project;
- Push it to a GitLab;
- Installing netlify-cli;
- Preparing Netlify for CI — setting up the necessary tokens and config file for Netlify:
- Link your repo to a new Netlify project;
- Generate a personal access token;
- Setup Netlify’s config file;
- Preparing for GitLab CI/CD — setting up environment variables;
- Defining the CI/CD pipeline — defining the .gitlab.yml config file;
- Result: does it blend?;
- Bonus: adding a staging preview — deploying to an extra project;
- Create a project in Netlify;
- Link the staging project to the repo;
- Create Merge Requests into Develop;
- Next steps;
- Repo & Resources;
Create a new project
Or use an existing one. In this case, we’re creating a new one named vue_netlify_ci using
vue create vue_netlify_ci.
Here’s the config I used:
Push it to a GitLab repo
Install netlify-cli globally
npm i netlify-cli -g and make sure it’s properly installed by typing in
netlify -v. It’ll yield something like netlify-cli/2.11.10 darwin-x64 node-v10.15.3.
Command not found?
It’s possible that when you try to run netlify you’ll get a “Command not found” message. That’s most likely due to some issue related to how you installed Node+npm in the first place. To fix it you need to update you $PATH env (for MacOS/Linux the process should be roughly equal. For Windows users, Google I guess?)
1. Look up the result of installing netlify-cli, it should look something like:
/usr/local/Cellar/node/8.7.0/bin/ntl -> /usr/local/Cellar/node/8.7.0/lib/node_modules/netlify-cli/bin/run
/usr/local/Cellar/node/8.7.0/bin/netlify -> /usr/local/Cellar/node/8.7.0/lib/node_modules/netlify-cli/bin/run
updated 1 package in 5.123s
In my case, netlify can be found within /usr/local/Cellar/node/8.7.0/bin/
and that’s the line we need to add to our .bash_profile. To do so, vim in to it using
vim ~/.bash_profileand add the line
export PATH=/usr/local/Cellar/node/8.7.0/bin/:$PATH(note that you need to change this depending on your output).
Save it and run
source ~/.bash_profileand netlify should now be accessible in your terminal.
Preparing Netlify for CI
Link your repo to a new Netlify project
netlify init --manual and follow these wizard steps:
- Select: Create & configure new site
- Give it a name (optional) (we’ll call it vue-netlify-ci)
- Pick your team, if any and press Enter to finish.
Note: if it’s your first time using netlify CLI, you’ll be prompted to authorize the connection to your account (it’ll open a browser window with the authorization UI).
After these, you’ll have your project created within Netlify but it won’t be deployed (because we haven’t told it how to do so yet).
We now have a Site ID which we’ll need for our GitLab YAML instructions.
Generate a personal access token
If you’re logged in Netlify, click here to go straight to the right section. For reference, it’s located under User Settings > Applications.
Add a description to the token such as CI and keep it somewhere safe! Once you exit that page with the generated token you won’t be able to retrieve it anymore. If you lose it, you’ll need to generate a new one.
Setup Netlify’s config file
We can describe how Netlify will build and deploy your site using TOML markup language. In our case, simply create a file named netlify.toml under the project’s root directory with the following:
What’s happening here? We’re simply telling Netlify which directory contains the deploy-ready assets generated by the build.
(Note: In our case we are building the app using GitLab’s runners and deploying the bundle all together, whereas you’d normally have
command = "npm run build" to tell Netlify to build the app first).
We now have an access token, the site’s ID and we’ve told Netlify how to handle the deploy process. Onto GitLab.
Preparing for GitLab CI/CD
GitLab’s CI/CD is pretty straight forward. If you push to a repo and it detects a .gitlab-ci.yml file within your project, it’ll use shared runners to run the scripts inside it according to the provided instructions.
Before setting up the file, we need to setup environment variables so our .yml doesn’t expose any sensible data, namely the access token and site ID.
To do so, navigate to Settings > CI /CD and expand the Variables section.
Add in NETLIFY_AUTH_TOKEN and NETLIFY_SITE_ID, each with their respective values. (Tip: if you don’t recall your side ID, you can see it in your project root directory under .netlify/state.json).
Save them, and we are now ready finally ready to add .gitlab-ci.yml
Defining the CI/CD pipeline
GitLab CI/CD pipelines are configured using a YAML file called .gitlab-ci.yml within each project.
In the project’s root directory, create a file called .gitlab-ci.yml and add the following:
This sets up a 4-stage pipeline that will 1) setup the project’s dependencies; 2) run our tests; 3) build the app; 4) deploy it to Netlify.
Some details about what is being used:
image: indicates which Docker to use for the jobs.
artifacts: specifies files/directories we want to make available to following jobs.
dependencies: to be used in conjunction with artifacts. Allows us to use the result of the build stage (the dist folder) into the deploy stage.
npm ci: “npm ci bypasses a package’s package.json to install modules from a package’s lockfile [..] offering massive improvements to both the performance and reliability of builds for continuous integration / continuous deployment processes”.
netlify deploy: deploys our site to Netlify, specifically: --site $NETLIFY_SITE_ID and --auth $NETLIFY_AUTH_TOKEN indicate the site we want to deploy to and authenticate us to deploy (using the CI/CD env variables we set up earlier). --prod indicates we want to deploy to production.
Result: does it blend?
Finally, add and commit the files and
git push (we’ve been working on the master branch. Ideally you would push to a separate branch and then PR+Merge into master. Only changes to master affect the CI pipeline).
As soon as you push/merge to master, GitLab will trigger its runners and execute the pipeline.
Within your GitLab project, Navigate to CI/CD > Pipelines or CI/CD > Jobs to view in detail the status of each stage. If you get an error, be sure to click that job and look at the logs to understand what’s the issue.
Bonus: adding a staging preview
You know what’d be cool? Having the ability to preview new features on a separate deploy. Netlify has the option to deploy previews for each PR/MR when you link your repo as you would normally using the UI.
Unfortunately for us, it seems that it is not possible as of now to automate our deployment solely using our CI pipeline and/or Netlify’s CLI, so we’ll do differently.
At the end of this, we’ll have a flow looking like this:
Create a project in Netlify
Create a new project in Netlify which will host the staging as well as merge requests’ previews. We’ll name it by prepending staging-- to the production’s name, so it looks like staging-vue-netlify-ci.netlify.com. This is just to help distinguish both projects, you can use any naming you want.
Link the staging project to the repo
After selecting the project, select the develop branch which will be responsible for representing our staging preview.
Define the build command as
npm run build and set the publish directory to dist.
Once you save it, Netlify will watch the develop branch and automatically build MR previews and production builds(which in this case production is treated as our staging. Real production is handled by our own pipeline remember?).
Create Merge Request into Develop
Remembering the flow above, you can generate as many deploys you want:
- one for per each branch that has a merge request into develop (ideal to quickly test features, hypothesis, quick showcase);
- one for the develop branch which acts as our staging environment;
And we get to keep using our own CI pipeline to the apply tests when merging into master. Of course you could change this whole flow to accommodate your needs.
An extra advantage of setting it up this way is that the build from our MR previews and develop deploys are all handled by Netlify, meaning we don’t get to waste CI minutes provided by GitLab. 👌
As you can see, it’s pretty easy to setup a continuous integration & delivery pipeline to host a Vue.js app on Netlify using GitLab.
Optimizing pipeline time
Keep in mind that as the app gets new features and as you add more testing, the stages of the CI/CD pipeline will take longer and longer to be completed. It’s important to keep it fast not only for agile flows but also for cost reasons, as GitLab only provides 2k free minutes for CI/CD per month⏱️.
I’m by far no expert in using .gitlab-ci.yml configs and I’m sure the times above can be considerably reduced. This article by Wes Cossick details some ways to speed up the pipeline’s execution time. I’ll review this article with benchmarks and improvements as I improve my projects’ pipelines.
Repo & Resources
These provided config files here should be enough, but if you want to have a look at the repository (featuring Netlify’s deploy status badge) you can grab it here (https://gitlab.com/mstrlaw/vue_netlify_ci).
Resources / Reading material:
Chime in and leave your thoughts and suggestions in the comments below.
- Added the “Bonus” section explaining how to have an extra staging project linked to Netlify;
- Grammar & typos;