Automate Git Workflow Based on Node.js and PM2

Background

Due to the repository migration and pipeline permission issues, the repository used by the pipeline could not be directly used to submit PRs on the page. Therefore, when the cooperating party's counterparts modified the SaaS backend code and needed to release, they had to manually merge and push the code locally each time, which was very cumbersome and inefficient. Since the pulled repository and branch are fixed each time, a Node script was written to automatically fetch the code by calling an API.

Technology Stack Selection

Given that the current requirements are very simple, just for synchronization, essentially the following commands need to be executed:

  • git checkout dev

  • git pull --no-rebase

  • git pull bkop dev_databus --no-rebase

  • git push

Based on this, the following key technologies are primarily adopted:

  • Node.js: A JavaScript runtime environment that runs on the server.

  • Express: A fast, unopinionated, modular web framework for Node.js, providing support for our API services.

  • Child Process: Used to execute shell commands.

  • PM2: A process manager for Node applications with built-in load balancing capabilities.

Solution Overview

Directory Structure and Dependency Installation

First, create a project directory and initialize a new npm project. Then, install the required dependencies.

mkdir git-auto-pilot && cd $_
npm init -y
npm install express child-process-promise

Here, the child-process-promise library is used instead of the native exec function to enhance error handling with better elegance and support for Promise syntax.

Create Automated Script

The core part of the automation logic is implemented by writing a simple Express application and triggering a series of Git operations through an HTTP interface.

Main Functional Modules

Set up Express Application

Start by importing the required modules and setting up a basic Express application.

// File path: index.js
const express = require('express');
const cp = require('child-process-promise');
const path = require('path');

const app = express();
const directory = 'xxx'; // Directory path
GET Route for Update Operations

Define a /update route to execute all the Git operations.

app.get('/update', async (req, res) => {
  try {
    await executeGitCommand('checkout dev');
    await executeGitCommand('pull --no-rebase');
    await executeGitCommand('pull bkop dev_databus --no-rebase');
    await executeGitCommand('push');

    const recentCommits = await executeGitCommand('log -n 5 --pretty=format:"%h %s"');

    res.send(`
      <h1>Update and Push Successful!</h1>
      <h2>Most Recent Commits:</h2>
      <pre>${recentCommits.stdout}</pre>
    `);
  } catch (error) {
    console.error(`Failed to perform update operations: ${error}`);
    res.status(500).send(`<pre>Error: ${error.stderr || error.stack}</pre>`);
  }

});

function executeGitCommand(command) {
  const fullCommand = `git ${command}`;
  console.log(`Executing command: ${fullCommand} in ${directory}`);

  return cp.exec(fullCommand, { cwd: directory });
}

In this route, all git operations are executed in sequence, with exception handling included to ensure the robustness of the program.

Start Express Service

The final step is to start the application to listen on a port.

const PORT = process.env.PORT || 30035;

app.listen(PORT, () => 
  console.log(`Server is running at http://localhost:${PORT}/`)
);

Use PM2 for Daemon Management

To ensure that the application runs stably in the background, use PM2 for management. This way, the service can be automatically restarted even if the terminal is closed or the machine is restarted.

pm2 start index.js --name "git-auto-pilot"

Now, even if the terminal is closed or the machine is restarted, the service will be automatically revived by PM2.

Summary

Using Node and PM2, you can write many simple and practical automation scripts. Currently, this script cannot handle conflicts but is sufficient to solve most of my problems, saving a lot of time manually merging code.

On this basis, by general modification of the git commands in the code, you can meet different automation needs based on actual requirements. Furthermore, if needed, you can continue to enhance the front-end page to automate processes such as conflict handling, turning it into a simple online Git processing tool that can perform different Git operations based on user interaction.