debian-mirror-gitlab/doc/ci/examples/deployment/composer-npm-deploy.md

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

163 lines
6.3 KiB
Markdown
Raw Normal View History

2019-09-04 21:01:54 +05:30
---
2020-06-23 00:09:42 +05:30
stage: Release
2021-02-22 17:27:13 +05:30
group: Release
2022-11-25 23:54:43 +05:30
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
2019-09-04 21:01:54 +05:30
type: tutorial
---
2021-10-27 15:23:28 +05:30
# Running Composer and npm scripts with deployment via SCP in GitLab CI/CD **(FREE)**
2017-08-17 22:00:37 +05:30
2021-11-18 22:05:49 +05:30
This guide covers the building of dependencies of a PHP project while compiling assets via an npm script using [GitLab CI/CD](../../index.md).
2017-08-17 22:00:37 +05:30
2021-03-08 18:12:59 +05:30
While it is possible to create your own image with custom PHP and Node.js versions, for brevity we use an existing [Docker image](https://hub.docker.com/r/tetraweb/php/) that contains both PHP and Node.js installed.
2017-08-17 22:00:37 +05:30
```yaml
image: tetraweb/php
```
2021-03-08 18:12:59 +05:30
The next step is to install zip/unzip packages and make composer available. We place these in the `before_script` section:
2017-08-17 22:00:37 +05:30
```yaml
before_script:
- apt-get update
- apt-get install zip unzip
- php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
- php composer-setup.php
- php -r "unlink('composer-setup.php');"
```
2021-03-08 18:12:59 +05:30
This makes sure we have all requirements ready. Next, run `composer install` to fetch all PHP dependencies and `npm install` to load Node.js packages. Then run the `npm` script. We need to append them into `before_script` section:
2017-08-17 22:00:37 +05:30
```yaml
before_script:
# ...
2017-09-10 17:25:29 +05:30
- php composer.phar install
2017-08-17 22:00:37 +05:30
- npm install
- npm run deploy
```
In this particular case, the `npm deploy` script is a Gulp script that does the following:
1. Compile CSS & JS
2019-02-15 15:39:39 +05:30
1. Create sprites
1. Copy various assets (images, fonts) around
1. Replace some strings
2017-08-17 22:00:37 +05:30
2021-03-08 18:12:59 +05:30
All these operations put all files into a `build` folder, which is ready to be deployed to a live server.
2017-08-17 22:00:37 +05:30
2018-03-17 18:26:18 +05:30
## How to transfer files to a live server
2017-08-17 22:00:37 +05:30
2021-03-08 18:12:59 +05:30
You have multiple options: rsync, SCP, SFTP, and so on. For now, use SCP.
2017-08-17 22:00:37 +05:30
2021-03-08 18:12:59 +05:30
To make this work, you must add a GitLab CI/CD Variable (accessible on `gitlab.example/your-project-name/variables`). Name this variable `STAGING_PRIVATE_KEY` and set it to the **private** SSH key of your server.
2017-08-17 22:00:37 +05:30
2018-03-17 18:26:18 +05:30
### Security tip
2017-08-17 22:00:37 +05:30
2019-09-04 21:01:54 +05:30
Create a user that has access **only** to the folder that needs to be updated.
2017-08-17 22:00:37 +05:30
2021-03-08 18:12:59 +05:30
After you create that variable, make sure that key is added to the Docker container on run:
2017-08-17 22:00:37 +05:30
```yaml
before_script:
# - ....
- 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
- mkdir -p ~/.ssh
- eval $(ssh-agent -s)
- '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
```
In order, this means that:
2019-02-15 15:39:39 +05:30
1. We check if the `ssh-agent` is available and we install it if it's not.
1. We create the `~/.ssh` folder.
1. We make sure we're running bash.
2021-03-08 18:12:59 +05:30
1. We disable host checking (we don't ask for user accept when we first connect to a server, and since every job equals a first connect, we need this).
2017-08-17 22:00:37 +05:30
And this is basically all you need in the `before_script` section.
2019-09-04 21:01:54 +05:30
## How to deploy
2017-08-17 22:00:37 +05:30
2020-06-23 00:09:42 +05:30
As we stated above, we need to deploy the `build` folder from the Docker image to our server. To do so, we create a new job:
2017-08-17 22:00:37 +05:30
```yaml
stage_deploy:
artifacts:
paths:
- build/
only:
- dev
script:
- ssh-add <(echo "$STAGING_PRIVATE_KEY")
- ssh -p22 server_user@server_host "mkdir htdocs/wp-content/themes/_tmp"
- scp -P22 -r build/* server_user@server_host:htdocs/wp-content/themes/_tmp
- ssh -p22 server_user@server_host "mv htdocs/wp-content/themes/live htdocs/wp-content/themes/_old && mv htdocs/wp-content/themes/_tmp htdocs/wp-content/themes/live"
- ssh -p22 server_user@server_host "rm -rf htdocs/wp-content/themes/_old"
```
2018-03-17 18:26:18 +05:30
Here's the breakdown:
2017-08-17 22:00:37 +05:30
2021-03-08 18:12:59 +05:30
1. `only:dev` means that this build runs only when something is pushed to the `dev` branch. You can remove this block completely and have everything run on every push (but probably this is something you don't want).
1. `ssh-add ...` we add that private key you added on the web UI to the Docker container.
1. We connect via `ssh` and create a new `_tmp` folder.
1. We connect via `scp` and upload the `build` folder (which was generated by a `npm` script) to our previously created `_tmp` folder.
1. We connect again via `ssh` and move the `live` folder to an `_old` folder, then move `_tmp` to `live`.
1. We connect to SSH and remove the `_old` folder.
2017-08-17 22:00:37 +05:30
2021-03-08 18:12:59 +05:30
What's the deal with the artifacts? We tell GitLab CI/CD to keep the `build` directory (later on, you can download that as needed).
2017-08-17 22:00:37 +05:30
2018-03-17 18:26:18 +05:30
### Why we do it this way
2017-08-17 22:00:37 +05:30
If you're using this only for stage server, you could do this in two steps:
```yaml
- ssh -p22 server_user@server_host "rm -rf htdocs/wp-content/themes/live/*"
- scp -P22 -r build/* server_user@server_host:htdocs/wp-content/themes/live
```
2021-03-08 18:12:59 +05:30
The problem is that there's a small period of time when you don't have the app on your server.
2017-08-17 22:00:37 +05:30
2019-09-04 21:01:54 +05:30
Therefore, for a production environment we use additional steps to ensure that at any given time, a functional app is in place.
2017-08-17 22:00:37 +05:30
2018-03-17 18:26:18 +05:30
## Where to go next
2017-08-17 22:00:37 +05:30
2019-09-04 21:01:54 +05:30
Since this was a WordPress project, I gave real life code snippets. Some further ideas you can pursue:
2017-08-17 22:00:37 +05:30
2021-04-17 20:07:23 +05:30
- Having a slightly different script for the default branch allows you to deploy to a production server from that branch and to a stage server from any other branches.
2021-10-27 15:23:28 +05:30
- Instead of pushing it live, you can push it to WordPress official repository.
2017-08-17 22:00:37 +05:30
- You could generate i18n text domains on the fly.
---
2021-03-08 18:12:59 +05:30
Our final `.gitlab-ci.yml` looks like this:
2017-08-17 22:00:37 +05:30
```yaml
image: tetraweb/php
before_script:
- apt-get update
- apt-get install zip unzip
- php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
- php composer-setup.php
- php -r "unlink('composer-setup.php');"
2017-09-10 17:25:29 +05:30
- php composer.phar install
2017-08-17 22:00:37 +05:30
- npm install
- npm run deploy
- 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
- mkdir -p ~/.ssh
- eval $(ssh-agent -s)
- '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
stage_deploy:
artifacts:
paths:
2020-07-28 23:09:34 +05:30
- build/
2017-08-17 22:00:37 +05:30
only:
- dev
script:
- ssh-add <(echo "$STAGING_PRIVATE_KEY")
- ssh -p22 server_user@server_host "mkdir htdocs/wp-content/themes/_tmp"
- scp -P22 -r build/* server_user@server_host:htdocs/wp-content/themes/_tmp
- ssh -p22 server_user@server_host "mv htdocs/wp-content/themes/live htdocs/wp-content/themes/_old && mv htdocs/wp-content/themes/_tmp htdocs/wp-content/themes/live"
- ssh -p22 server_user@server_host "rm -rf htdocs/wp-content/themes/_old"
```