debian-mirror-gitlab/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/index.md

405 lines
16 KiB
Markdown
Raw Normal View History

2018-03-27 19:54:05 +05:30
---
2020-06-23 00:09:42 +05:30
stage: Verify
group: Continuous Integration
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
2018-03-27 19:54:05 +05:30
author: Alexandre S Hostert
author_gitlab: Hostert
level: beginner
article_type: tutorial
2019-09-04 21:01:54 +05:30
type: tutorial
2018-03-27 19:54:05 +05:30
date: 2018-02-20
2019-07-07 11:18:12 +05:30
last_updated: 2019-03-06
2018-03-27 19:54:05 +05:30
---
# Testing a Phoenix application with GitLab CI/CD
2020-03-13 15:44:24 +05:30
[Phoenix](https://www.phoenixframework.org/) is a web development framework written in [Elixir](https://elixir-lang.org), which is a
2018-03-27 19:54:05 +05:30
functional language designed for productivity and maintainability that runs on the
2020-04-22 19:07:51 +05:30
[Erlang VM](https://www.erlang.org). Erlang VM is really fast and can handle very large numbers of
2018-03-27 19:54:05 +05:30
simultaneous users.
That's why we're hearing so much about Phoenix today.
2019-09-04 21:01:54 +05:30
In this tutorial, we'll teach you how to set up [GitLab CI/CD](../../README.md) to build and test a Phoenix
2018-03-27 19:54:05 +05:30
application.
2019-09-04 21:01:54 +05:30
The tutorial assumes that you know how to create a Phoenix app, run tests locally, and how to work with Git
and the GitLab UI.
2018-03-27 19:54:05 +05:30
## Introduction
### What is Phoenix?
2020-03-13 15:44:24 +05:30
[Phoenix](https://www.phoenixframework.org/) is a web development framework written in [Elixir](https://elixir-lang.org). It's useful
for building fast, reliable, and high-performance applications, as it uses [Erlang VM](https://www.erlang.org).
2018-03-27 19:54:05 +05:30
Many components and concepts are similar to Ruby on Rails or Python's Django. High developer
productivity and high application performance are only a few advantages on learning how to use it.
2018-10-15 14:42:47 +05:30
Working on the MVC pattern, it's was designed to be modular and flexible. Easy to maintain a growing
2018-03-27 19:54:05 +05:30
app is a plus.
Phoenix can run in any OS where Erlang is supported:
- Ubuntu
- CentOS
- Mac OS X
- Debian
- Windows
- Fedora
2020-06-23 00:09:42 +05:30
- Raspberry Pi OS
2018-03-27 19:54:05 +05:30
2020-06-23 00:09:42 +05:30
Check the [Phoenix learning guide](https://hexdocs.pm/phoenix/overview.html) for more information.
2018-03-27 19:54:05 +05:30
### What is Elixir?
2020-03-13 15:44:24 +05:30
[Elixir](https://elixir-lang.org) is a dynamic, functional language created to use all the maturity of Erlang
2018-10-15 14:42:47 +05:30
(30 years old!) in these days, in an easy way. It has similarities with Ruby, specially on syntax,
2018-03-27 19:54:05 +05:30
so Ruby developers are quite excited with the rapid growing of Elixir. A full-stack Ruby developer
can learn how to use Elixir and Phoenix in just a few weeks!
In Elixir we have a command called `mix`, which is a helper to create projects, testing, run
2020-03-13 15:44:24 +05:30
migrations and [much more](https://elixir-lang.org/getting-started/mix-otp/introduction-to-mix). We'll use it later on in this tutorial.
2018-03-27 19:54:05 +05:30
2020-03-13 15:44:24 +05:30
Check the [Elixir documentation](https://elixir-lang.org/getting-started/introduction) for more information.
2018-03-27 19:54:05 +05:30
## Requirements
To follow this tutorial, you'll need to have installed:
2020-03-13 15:44:24 +05:30
- Elixir [installation instructions](https://elixir-lang.org/install)
- Phoenix Framework [installation instructions](https://hexdocs.pm/phoenix/installation.html)
- PostgreSQL (if you need to use MySQL server, check [Phoenix instructions](https://hexdocs.pm/phoenix/ecto.html#using-mysql))
2018-03-27 19:54:05 +05:30
### Create a new Phoenix project
Open your terminal and go to the directory you wish to create your project.
You don't need to create an empty directory for the project's files, because the `mix` command will
do it for us.
When we call `mix` command, we'll pass two arguments:
- The task we want it to run: `phoenix.new`
- And the parameter `phoenix.new` requires, which is the name of the new project. In this case,
2019-07-07 11:18:12 +05:30
we're calling it `hello_gitlab_ci`, but you're free to set your own name:
2018-03-27 19:54:05 +05:30
2020-03-13 15:44:24 +05:30
```shell
2018-03-27 19:54:05 +05:30
mix phoenix.new hello_gitlab_ci
```
When asked, answer `Y` to fetch and install dependencies.
If everything went fine, you'll get an output like this:
2018-11-20 20:47:30 +05:30
![mix phoenix.new](img/mix-phoenix-new.png)
2018-03-27 19:54:05 +05:30
Now, our project is located inside the directory with the same name we pass to `mix` command, for
example, `~/GitLab/hello_gitlab_ci`.
If we take a look at the directory, we'll see the Phoenix files and the dependencies needed to run.
### Initialize the PostgreSQL database
By default, Phoenix requires a PostgreSQL database to store whatever we need to store in our app. In
this case, we'll only create an empty database.
First, we need to navigate to our recently created project's directory, and then execute again
`mix`. This time, `mix` will receive the parameter `ecto.create`, which is the task to create our
2020-03-13 15:44:24 +05:30
new database. [Ecto](https://hexdocs.pm/ecto/Ecto.html) is the database wrapper for Elixir.
2018-03-27 19:54:05 +05:30
When we do run `mix` the first time after creating our project, it will compile our files to
bytecode, which will be interpreted by Erlang VM. In the next times, it will only compile our
changes.
Run the commands below to create our empty database:
2020-03-13 15:44:24 +05:30
```shell
2018-03-27 19:54:05 +05:30
cd hello_gitlab_ci
mix ecto.create
```
We expect to see this output at the end of the command:
2020-03-13 15:44:24 +05:30
```plaintext
2018-03-27 19:54:05 +05:30
Generated hello_gitlab_ci app
The database for HelloGitlabCi.Repo has been created
```
> **Note:**
Phoenix assumes that our PostgreSQL database will have a `postgres` user account with the correct
permissions and a password of `postgres`. If it's not your case, check
2020-03-13 15:44:24 +05:30
[Ecto's instructions](https://hexdocs.pm/ecto/Ecto.html#module-repositories).
2018-03-27 19:54:05 +05:30
### Start Phoenix server
Now, it's time to see if everything we did until now went well. We'll call `mix` again, this time
with `phoenix.server` parameter, which will start Phoenix's HTTP Server.
2020-03-13 15:44:24 +05:30
```shell
2018-03-27 19:54:05 +05:30
mix phoenix.server
```
This will be the output to this command:
2020-03-13 15:44:24 +05:30
```plaintext
2018-03-27 19:54:05 +05:30
[info] Running HelloGitlabCi.Endpoint with Cowboy using http://localhost:4000
23 May 11:44:35 - info: compiling
23 May 11:44:37 - info: compiled 6 files into 2 files, copied 3 in 9.8 sec
```
Now, we have our app running locally. We can preview it directly on our browser. Let's open
[`localhost:4000`](http://localhost:4000) to see our Phoenix Framework welcome page. If the link do
not work, open [`127.0.0.1:4000`](http://127.0.0.1:4000) instead and later, configure your OS to
point `localhost` to `127.0.0.1`.
2018-11-20 20:47:30 +05:30
![mix phoenix.server](img/mix-phoenix-server.png)
2018-03-27 19:54:05 +05:30
Great, now we have a local Phoenix Server running our app.
2020-06-23 00:09:42 +05:30
Locally, our application is running in an [`iex`](https://elixir-lang.org/getting-started/introduction.html#interactive-mode) session, which stands for Interactive Elixir.
2018-03-27 19:54:05 +05:30
In this interactive mode, we can type any Elixir expression and get its result. To exit `iex`, we
need to press `Ctrl+C` twice. So, when we need to stop the Phoenix server, we have to hit `Ctrl+C`
twice.
## Introducing GitLab CI/CD
With GitLab, we can manage our development workflow, improve our productivity, track issues,
perform code review, and much more from a single platform. With GitLab CI/CD, we can be much more
productive, because every time we, or our co-workers push any code, GitLab CI/CD will build and
2020-06-23 00:09:42 +05:30
test the changes, telling us in real time if anything goes wrong.
2018-03-27 19:54:05 +05:30
Certainly, when our application starts to grow, we'll need more developers working on the same
2018-10-15 14:42:47 +05:30
project and this process of building and testing can easily become a mess without proper management.
2018-03-27 19:54:05 +05:30
That's also why GitLab CI/CD is so important to our application. Every time someone pushes its code to
GitLab, we'll quickly know if their changes broke something or not. We don't need to stop everything
we're doing to test manually and locally every change our team does.
Let's see this in practice.
## Adjusting Phoenix configuration
Now, we need to adjust our Phoenix configuration before configuring GitLab CI/CD.
There is a directory (`config`) in your Phoenix project that contains a configuration file for every
environment it can run. Since we will work with a single environment, we'll edit just the test
configuration file (`test.exs`).
But, why do we need to adjust our configuration? Well, GitLab CI/CD builds and tests our code in one
2019-07-07 11:18:12 +05:30
isolated virtual machine, called [Runner](../../runners/README.md), using Docker technology. In this Runner,
2018-03-27 19:54:05 +05:30
GitLab CI/CD has access to everything our Phoenix application need to run, exactly as we have in our
`localhost`, but we have to tell GitLab CI/CD where to create and find this database using system
variables. This way, GitLab CI/CD will create our test database inside the Runner, just like we do
when running our Phoenix in our `localhost`.
- Open `hello_gitlab_ci/config/test.exs` on your favorite code editor
- Go to **Configure your database** session and edit the block to include `System.get_env`:
2019-10-12 21:52:04 +05:30
```elixir
# Configure your database
config :hello_gitlab_ci, HelloGitlabCi.Repo,
adapter: Ecto.Adapters.Postgres,
username: System.get_env("POSTGRES_USER") || "postgres",
password: System.get_env("POSTGRES_PASSWORD") || "postgres",
database: System.get_env("POSTGRES_DB") || "hello_gitlab_ci_test",
hostname: System.get_env("POSTGRES_HOST") || "localhost",
pool: Ecto.Adapters.SQL.Sandbox
```
We'll need these system variables later on.
2018-03-27 19:54:05 +05:30
- Create an empty file named `.gitkeep` into `hello_gitlab_ci/priv/repo/migrations`
2019-10-12 21:52:04 +05:30
As our project is still fresh, we don't have any data on our database, so, the `migrations`
directory will be empty.
2019-12-21 20:55:43 +05:30
Without `.gitkeep`, Git will not upload this empty directory and we'll got an error when running our
2019-10-12 21:52:04 +05:30
test on GitLab.
2018-03-27 19:54:05 +05:30
2019-10-12 21:52:04 +05:30
> **Note:** If we add a folder via the GitLab UI, GitLab itself will add the `.gitkeep` to that new dir.
2018-03-27 19:54:05 +05:30
Now, let's run a local test and see if everything we did didn't break anything.
## Testing
Earlier, when we created our project, we ran `mix phoenix.new`.
This task created everything a Phoenix application needed, including some unit tests into
`hello_gitlab_ci/test` directory.
Let's run a new task with `mix` to run those tests for us. This time, the parameter expected is
`test`. We can add `--trace` parameter for debugging purposes.
In your terminal, navigate to the directory `hello_gitlab_ci` and run:
2020-03-13 15:44:24 +05:30
```shell
2018-03-27 19:54:05 +05:30
mix test
```
Our expected result is this:
2020-03-13 15:44:24 +05:30
```plaintext
2018-03-27 19:54:05 +05:30
....
Finished in 0.7 seconds
4 tests, 0 failures
Randomized with seed 610000
```
2018-10-15 14:42:47 +05:30
Our test was successful. It's time to push our files to GitLab.
2018-03-27 19:54:05 +05:30
## Configuring CI/CD Pipeline
The first step is to create a new file called `.gitlab-ci.yml` in `hello_gitlab_ci` directory of our
project.
2020-03-13 15:44:24 +05:30
- The easiest way to do this is to click on **Set up CI/CD** on project's main page:
2018-03-27 19:54:05 +05:30
2020-03-13 15:44:24 +05:30
![Set up CI](img/set_up_ci_v12_6.png)
2018-03-27 19:54:05 +05:30
2020-03-13 15:44:24 +05:30
- On the next screen, we can use a template with Elixir tests already included. Click on **Apply a template** and select **Elixir**:
2018-03-27 19:54:05 +05:30
2020-03-13 15:44:24 +05:30
![Select template](img/select_template_v12_6.png)
2018-03-27 19:54:05 +05:30
2019-10-12 21:52:04 +05:30
This template file tells GitLab CI/CD about what we wish to do every time a new commit is made.
2020-03-13 15:44:24 +05:30
However, we have to adapt it slightly to run a Phoenix app.
2018-03-27 19:54:05 +05:30
- The first line tells GitLab what Docker image will be used.
2019-10-12 21:52:04 +05:30
Remember when we learn about Runners, the isolated virtual machine where GitLab CI/CD build and test
our application? This virtual machine must have all dependencies to run our application. This is
where a Docker image is needed. The correct image will provide the entire system for us.
2018-03-27 19:54:05 +05:30
2020-06-23 00:09:42 +05:30
As we are focusing on testing (not deploying), you can use the [elixir:latest](https://hub.docker.com/_/elixir) Docker image, which already has the
2020-03-13 15:44:24 +05:30
dependencies for running Phoenix tests installed, such as Elixir and Erlang:
2018-03-27 19:54:05 +05:30
2020-03-13 15:44:24 +05:30
```yaml
image: elixir:latest
2019-10-12 21:52:04 +05:30
```
2018-03-27 19:54:05 +05:30
2020-03-13 15:44:24 +05:30
- We'll only use `postgres`, so we can delete the `mysql` and `redis` lines from the `services` section:
2018-03-27 19:54:05 +05:30
2020-03-13 15:44:24 +05:30
```yaml
2019-10-12 21:52:04 +05:30
services:
- postgres:latest
```
2018-03-27 19:54:05 +05:30
2020-03-13 15:44:24 +05:30
- Now, we'll create a new section called `variables`, before the `before_script` section:
2018-03-27 19:54:05 +05:30
2020-03-13 15:44:24 +05:30
```yaml
2019-10-12 21:52:04 +05:30
variables:
POSTGRES_DB: hello_gitlab_ci_test
POSTGRES_HOST: postgres
POSTGRES_USER: postgres
POSTGRES_PASSWORD: "postgres"
MIX_ENV: "test"
```
2018-03-27 19:54:05 +05:30
2020-03-13 15:44:24 +05:30
Above, we set up the values for GitLab CI/CD to authenticate into PostgreSQL, like we did in
`config/test.exs` earlier. The `POSTGRES_USER` and `POSTGRES_PASSWORD` values
are used by the `postgres` service to create a user with those credentials.
2018-03-27 19:54:05 +05:30
2020-03-13 15:44:24 +05:30
- In the `before_script` section, we'll add some commands to prepare everything for the test:
2018-03-27 19:54:05 +05:30
2020-03-13 15:44:24 +05:30
```yaml
2019-10-12 21:52:04 +05:30
before_script:
2020-03-13 15:44:24 +05:30
- mix local.rebar --force
2019-10-12 21:52:04 +05:30
- mix local.hex --force
- mix deps.get --only test
- mix ecto.create
- mix ecto.migrate
```
2020-03-13 15:44:24 +05:30
This ensures that [rebar3](https://www.rebar3.org) and [hex](https://hex.pm) are both installed
before attempting to fetch the dependencies that are required to run the tests. Next, the `postgres` db
is created and migrated with `ecto`, to ensure it's up-to-date.
2018-03-27 19:54:05 +05:30
2020-03-13 15:44:24 +05:30
- Finally, we'll leave the `mix` section unchanged.
2018-03-27 19:54:05 +05:30
2020-03-13 15:44:24 +05:30
Let's take a look at the updated file after the changes:
2018-03-27 19:54:05 +05:30
2020-03-13 15:44:24 +05:30
```yaml
image: elixir:latest
2018-03-27 19:54:05 +05:30
services:
- postgres:latest
variables:
2020-03-13 15:44:24 +05:30
POSTGRES_DB: hello_gitlab_ci_test
2018-03-27 19:54:05 +05:30
POSTGRES_HOST: postgres
POSTGRES_USER: postgres
POSTGRES_PASSWORD: "postgres"
MIX_ENV: "test"
before_script:
2020-03-13 15:44:24 +05:30
- mix local.rebar --force
- mix local.hex --force
- mix deps.get --only test
2018-03-27 19:54:05 +05:30
- mix ecto.create
- mix ecto.migrate
mix:
script:
2020-03-13 15:44:24 +05:30
- mix test
2018-03-27 19:54:05 +05:30
```
2018-10-15 14:42:47 +05:30
For safety, we can check if we get any syntax errors before submitting this file to GitLab. Copy the
2020-03-13 15:44:24 +05:30
contents of `.gitlab-ci.yml` and paste it on [GitLab CI/CD Lint tool](https://gitlab.com/ci/lint). Please note that
2018-03-27 19:54:05 +05:30
this link will only work for logged in users.
## Watching the build
I don't know about you, but I love to watch that black screen being filled with compilation output.
With this, I can feel the happiness of something I made working correctly. On `localhost` it's easy
to watch our build, but on GitLab, is it possible? Yes!
Let's go to **Pipelines** and see GitLab doing the job. Just click on **Pipelines** to find the
actual running build job.
![Pipelines](img/pipelines.png)
Click on build's ID to watch the entire process. If everything went as expected, we can wait for the
**Build succeeded** at the end of the process! :)
2020-03-13 15:44:24 +05:30
```shell
2018-03-27 19:54:05 +05:30
$ mix test
....
Finished in 0.3 seconds
4 tests, 0 failures
Randomized with seed 206909
Build succeeded
```
If we take a look at the project's main page on the GitLab UI, we can see the status of the last
build made by GitLab CI/CD.
Time to show the world our green build badge! Navigate to your project's **Settings > CI/CD** and
2020-01-01 13:55:28 +05:30
expand **General pipelines settings**. Scroll down to **Pipeline status** and copy the Markdown code
2018-03-27 19:54:05 +05:30
for your badge. Paste it on the top of your `README.md` file, to let people outside of our project
see if our latest code is running without errors.
When we finish this edition, GitLab will start another build and show a **build running** badge. It
is expected, after all we just configured GitLab CI/CD to do this for every push! But you may think
"Why run build and tests for simple things like editing README.md?" and it is a good question.
2020-05-24 23:13:21 +05:30
For changes that don't affect your application, you can add the keyword [`[ci skip]`](../../yaml/README.md#skip-pipeline)
2018-03-27 19:54:05 +05:30
to commit message and the build related to that commit will be skipped.
In the end, we finally got our pretty green build succeeded badge! By outputting the result on the
README file, it shows to whoever lands on your project's page that your code is up-to-date and
working properly.
## Conclusion
When we have a growing application with many developers working on it, or when we have an open
source project being watched and contributed by the community, it is really important to have our
2018-10-15 14:42:47 +05:30
code permanently working. GitLab CI/CD is a time saving powerful tool to help us maintain our code
2018-03-27 19:54:05 +05:30
organized and working.
2020-04-22 19:07:51 +05:30
As we could see in this post, GitLab CI/CD is really easy to configure and use. We have [many
2020-03-13 15:44:24 +05:30
other reasons](https://about.gitlab.com/blog/2015/02/03/7-reasons-why-you-should-be-using-ci/) to keep
using GitLab CI/CD. The benefits to our teams will be huge!
2018-03-27 19:54:05 +05:30
## References
2020-03-13 15:44:24 +05:30
- [GitLab CI/CD introductory guide](https://about.gitlab.com/blog/2015/12/14/getting-started-with-gitlab-and-gitlab-ci/)
- [GitLab CI/CD full Documentation](../../README.md)
- [GitLab Runners documentation](../../runners/README.md)
- [Using Docker images documentation](../../docker/using_docker_images.md)