background

From the original SVN code version control,FTP manual upload project code ZIP compression package, to the current Git code version control, Jenkins one-click package deployment environment, has initially completed a great leap forward from manual to automatic. Looking back at my own project, I was still in the primitive stage of modifying code from the local repository -> submitting the remote Github repository -> manually pulling the latest branch code from my own server. Can’t endure

OK, let’s start our evolutionary lazy journey, let’s follow my heart and evolve together.

The target

When we modify the remote push warehouse in the local warehouse, the server can automatically pull the latest branch code and complete the project deployment automatically.

Preconditions (nonsense)
  1. There’s a local repository that can connect to a remote repository that can push code
  2. The server repository can pull code from the remote repository
  3. The remote repository has WebHooks

action

It is necessary to understand the principle of a wave of webhooks before you begin.

Webhooks automatic deployment principle
Local repository -> (Push commit code) -> Remote repository (Webhooks) -> (send POST request with key) -> Test/production server (execute deployment script)Copy the code

Now that we know the principle, let’s see what we need to prepare:

  • Remote repositories with Webhooks (Gitlab, Github, Gitee, etc.)
  • Services and test/production servers that can receive POST requests
  • Deployment script (.sh)
Remote repository WebHooks Settings

To set the remote repository to webhooks, you simply need to locate the location:

  1. URL: Sets the address of the POST request (that is, the server service address)

  2. Key: This key can be set or not set. It is recommended to set this key to prevent others from randomly requesting the server interface and automatically pulling the code deployment crazily, which is equivalent to a check

Deployment script auto_build.sh

Auto_build. sh.Linux create directory using mkdir directory name, create file using touch file name.

PROJECTNAME_PATH = '/usr/local/ SRC/project directory '; echo "Starting deployment" cd $PROJECTNAME_PATH git checkout . git pull npm i gulp release pm2 start ecosystem.config.js  echo "Finished"Copy the code

Pay attention to user permissions and global installation of basic commands when executing scripts.

Write the service deploy.js

The next big thing is to build a service that can receive POST requests from remote repositories, which is also simple. You can quickly build such a service with the help of the github-webhook-Handler plugin to create the deploy.js file.

Ps: Secret is the key in the webhooks Settings above

var http = require('http')
var createHandler = require('github-webhook-handler')
var handler = createHandler({ path: '/webhook'.secret: 'myhashsecret' })

http.createServer(function (req, res) {
  handler(req, res, function (err) {
    res.statusCode = 404
    res.end('no such location')
  })
}).listen(7777)

handler.on('error'.function (err) {
  console.error('Error:', err.message)
})

handler.on('push'.function (event) {
  console.log('Received a push event for %s to %s',
    event.payload.repository.name,
    event.payload.ref)
})

handler.on('issues'.function (event) {
  console.log('Received an issue event for %s action=%s: #%d %s',
    event.payload.repository.name,
    event.payload.action,
    event.payload.issue.number,
    event.payload.issue.title)
})
Copy the code

Ps: you can also set up an email to remind yourself of 23333333 when someone raises issues to your warehouse

Error: Cannot find module ‘github-webhook-handler’ Cannot find module ‘github-webhook-handler’ Cannot find module ‘github-webhook-handler’ Confirmation method:

NPM root - g / / view global NPM install path = > / root/NVM/versions/node/v9.10.1 / lib/node_modules CD / root/NVM/versions/node/v9.10.1 / lib/node_modules ll / / view the confirmation depend on whether the installation directoryCopy the code

After the installation is confirmed, you can perform the following steps:

  1. Enter thedeploy.jsdirectory
  2. Execute the following command
npm link github-webhook-handler
Copy the code

Now, all you need to do is combine auto_build.sh with deploy.js.

If you read the code above, you can see that handler is listening for the push event to call the corresponding function, so all you need to do is execute the auto_build.sh command in the function, and you need to add and change the following code in deploy.js

// Add the runCmd function
funciton runCmd(cmd, args, callback) {
    var spawn = require('child_process').spawn;				// node child process
    var child = spawn(cmd, args);
    var response = ' ';
    
    child.stdout.on('data', buffer => response += buffer.toStirng());
    child.stdout.on('end', () => callback(response));
}

// change the push listener event. Auto_build. sh and deploy.js are in the same directory file
handler.on('push'.function(event) {
   runCmd('sh'['./auto_build.sh'].function(text) { console.log(text) }); 
});
Copy the code

Ps: You can use console.log() to output corresponding prompts for troubleshooting

Run the service deploy.js

We want the Deploy service to always be running on the server and to execute the deployment script when the remote repository sends a POST request indicating that we have new code push. We need to start the deploy.js service as a daemon to restart the service if it crashes.

Here are two options for you to choose from, both of which can be installed via NPM:

  1. foreverTo ensure that the application restarts automatically when the process exits.
forever start deploy.js		   				  // Start the service process
forever list								  // List all processes
forever logs id								  // View process output logs
forever stop id								  // Stop the service process
forever restart id							  // Restart the service process
forever -m 5 deploy.js						  // The maximum number of restarts is 5
Copy the code
  1. pm2Powerful, in addition to restart the process, but also real-time log collection and monitoring.
pm2 start deploy.js		   				  // Start the service process
pm2 list								  // List all processes
pm2 logs id								  // View process output logs
pm2 stop id								  // Stop the service process
pm2 restart id							  // Restart the service process
pm2 delete id							  // Delete the server process
Copy the code
Nginx reverse proxy

Because my server is on Tencent cloud, port 7777 is not open, so through a Nginx reverse proxy to the server security group open port.

Be sure to confirm before sending a REMOTE repository POST test request

Security group port of own server has been released!!

Security group port of own server has been released!!

Security group port of own server has been released!!

Important things say three times! Here is my Nginx configuration

server {
	listen 8080;
    server_name	localhost;
    
    location /webhook {
        proxy_passhttp://127.0.0.1:7777; }}Copy the code

Ps: Restart nginx in Linux, go to the sbin directory of nginx, and run the./nginx -s reload command

Bug

Nginx start! Deploy service started! Remote warehouse Webhook setup complete! Click the test button!

Then…

Error!!!!!! The forced smile and smile gradually faded

{
  "error": "No X-Hub-Signature found on request"
}
Copy the code

Read a long time…… I just realized that the remote repository of my project code is the code cloud gitee.com. Since github private private repository needs to be paid before February 2019, I choose the code cloud as the remote repository of my project codes. However, my plug-in is Github-webhook-handler!! ! TAT is a jack-of-all-trades

That’s okay, little problem. How can a man say no at this point?!

Search Github to see if there is a Webhook for Gitee. If there is no webhook, forkGithub-webhook-Handler can change it to a Gitee code cloud. Sure enough, I found Gitee-webhook-middleware and made a change to deploy.js

var createHandler = require('gitee-webhook-middleware');
var handler = createHandler({ path: '/webhook'.token: 'your key' });
Copy the code

Restart the service and click Test!

{
  "ok": true
}
Copy the code

Perfect!

Check the project code on the server. It’s still old. It turns out that Gitee’s POST request event is a Push Hook

// handler.on('push', function() {});
handler.on('Push Hook'.function() {});
Copy the code

At this point, retest, project code update success!

The results of

Lazy success! Laziness is indeed the first productive force of engineers

Now whenever I push code from the local repository to the remote repository, the server pulls the latest version of the code and automatically deploys it.

This is just a simple attempt by me. We can completely extend the automated testing, automatic deployment in one, complete the CI/CD of multi-person collaborative development, greatly reduce the labor cost, reduce the occurrence of human error, and improve the work efficiency of everyone.