In fact, I believe that many students at the beginning of the github Action for many online tutorials: can read, but can not remember the state. Especially those who come up with a variety of commonly used attributes listed again, and then directly put examples below. If I could just remember the configuration items, I’d go straight to the official documentation.

This series of articles will introduce Github Actions in plain English, perfect for those with no basic knowledge. It will not only tell you about github actions, but also explain the purpose behind them and show you how to accomplish those actions that you want but can’t find online. In short: Easy to understand github actions and give you some initiative instead of just CTRL CV.

This three-part series will take the NodeJS project as an example to introduce the four most commonly used github functions: PR merge validation, Github Page publishing, NPM publishing, and Github Release publishing. While there are plenty of tutorials on these examples online, this article will go deeper and let you use them as a key to understanding, rather than just using them.

This article is an introduction to some of the core concepts of Github Actions and lays a foundation for future articles. Okay, cut the crap. Let’s get started!

A brief introduction to CI/CD

Before we get started, let’s take a look at the github Action’s main purpose: CI/CD.

A long, long time ago, the deployment and distribution of small to medium sized projects was simple, with the backend packaged and thrown into Tomcat and the foreground packaged and thrown into Nginx. If you can run, you can’t run and you can look at the log. This process is relatively simple and usually done by developers, so no one talks about it.

However, with the increasing reliability requirements, deployment platforms are increasingly upgraded. As a result, the process becomes more and more complicated. You first remember to run a single test, and then run a group test, and record yourself if you have any questions. No problem on the platform (on the server), build a good version, gray release….. I have to stop. It’s okay if you let me go through this process, but should I go through this process every time I post?

So what do you do? Write scripts. Programmers are good at handing off mindless tasks to machines. As a result, a variety of automation tools emerged, such as Java Gradle and JS Grunt. Automated building gradually emerged. Automated integration freed programmers from repetitive code building work and completed repetitive work such as running tests and building packages.

Later we gave the build a fancy name: integration.

How can you mindlessly deploy a service after solving one problem and leaving another? Of course, it is still writing scripts. From packaging and copying to server, to containerization, to Docker swarm and K8S, shell scripts have been quietly playing their own light and heat. There are so few family heirlooms that Shell is embarrassed to say it has deployed services.

Later we changed the deployment name to a higher-end one: delivery.

This kind of automation is perfect for taking on the programmer’s workload and putting attention back on the pile of shit. But when you use it, you find… There seems to be a slight problem:

  • Reusability issues: The integration and delivery processes of the same technology stack are virtually identical, with different deployments in different places and with different permissions. But in this automated way, the scripts are stored directly in the code repository and the corresponding server. I have to make a copy of the new project, if there is a problem, there is no way to unified change, do a lot of really a little boring.

  • Consistency problem: For code building, getting code packaged on different machines to behave the same has been a constant headache for millions of people. This kind of automated integration is usually done by executing commands on the local machine, and it is safe to say that the end result is thousands of people. As a result, there are all kinds of new people to ask the elderly why my computer packaging can not run annoying questions. On the other hand, even if you pack and run, how can you rest assured that there are not a few hidden problems that will suddenly give you an elbow when you get online?

  • Security issues: Shell scripts are usually ready for deployment. If you can find the script, the platform deployment key is not far away. It would be fun if someone saved it and gave you a ticking time bomb on your way out. How do you isolate this sensitive information so that people who can deploy can do things at the click of a button and not sneak around with these keys?

  • I am still lazy: although it is made of a key automatic execution, but I still have to execute a local command to build, and then log on the server, and then execute a command deployment, you can not do, I submit the code, what work are dry, developers do not have to care about anything, how beautiful is it?

The more you think about a small problem, the bigger it is, the more you think about it, the more you can’t eat.

  • For reusability, we design these automated processes as “functions” and publish them, if you want to use direct calls.

  • For consistency, we can have a separate machine, and the commands you execute will be sent to the machine to do the build, so that we can keep the machine pure. I don’t believe there will be any flower work.

  • For security, we can set up a layer of “proxy”, this proxy has many buttons, corresponding to different deployment tasks, you want to publish the button is finished, directly to screen sensitive information for you.

  • As for laziness: you said that you want to submit the code and then automatically run the task, so I will link with the code hosting platform.

As a result, these requirements grow into a single platform that takes care of all the mindless work from the moment the code is written to the moment it is released to the user. Examples include Java-based Jenkins, third-party Travis CI/ CircleCI, GitLab CI integrated into software development platforms, Atlassian CI/CD, and github Action.

Since these operations are completely automated, we simply made the process sustainable, and as soon as the code changes were made, we could run the corresponding results and publish them to the corresponding environment, which was not only easier to manage, but also more user-friendly for things like rollbacks. So we call this repetitive process Continuous Integration, Continuous Delivery, or CI/CD.

Design a simple CI/CD!

Now that we know what CI/CD is, let’s take it one step further. If we were a programmer and wanted to implement a platform to handle CICD, how would we design to meet these requirements?

First of all, if something is going to be done, the main question is, of course, the classic triple W question: Who’s going to do it? When will it be done? What to do? Well, with a stroke of the pen, we have the following flow diagram:

But if you think about it, there seems to be something that can be optimized. For example, to perform tests, we may need to run multiple machines separately to test the performance of different environments. So the above method of specifying only one running machine is not correct. Ok, again, with the stroke of a pen, here’s the new design:

Emmmmm, it seems, can be optimized, here for specific tasks, we do not have to be completely linear execution, if the two tasks have no previous dependency, we can have them execute in parallel.

Well, it seems that not all tasks can be performed in parallel. In this case, we need to add an option to the task to indicate the dependencies between the task and other tasks, such as the build task must be executed after all the test tasks are completed. Ok, the new design is done as soon as I have it in my head:

Now there seems to be no problem with the process, it is not very complicated. Hey, wait a minute. I think we were just trying to solve the reusability problem. I don’t want to think about it, so let’s do it like a function, take some arguments, do some operations in a black box, and return the result. And we can use this function as the smallest logical unit. Each function is a step, several steps can be combined into a larger step, through the combination of layers, finally complete a task, nice!

With the addition of minimum reuse unit “steps”, our GayHub Action V1.0 was designed!

Github Actions

Now that we’ve seen the overall architectural design of Github actions, the smallest unit of action is the “step” shown above. This concept is so important that Github’s CI/CD is called Github Action. Next, let’s take a look at github Actions with the above image.

The whole process of github Action is exactly the same as above. The next thing we need to do is to replace the Chinese name with the corresponding English keyword.

First, let’s take a look at the github Action tutorial:

The event on the left is our “when to do it”, and the job is our “task”. Each job contains multiple steps, and each step corresponds to an action. But it feels like step and action are inclusive, right? In fact, there are some custom properties on each step, such as names, environment variables, parameters passed to the action, and so on.


Ok, now look at the second image from the official tutorial:

It’s easy to understand, right? Jobs are parallel, and each job starts a Runner machine to execute it. So, as long as we have the design diagram above, we won’t be confused by the variety of keywords on Github, let alone remember the rules about asynchronous jobs and synchronous steps. If you think back to the diagram above, the rules can be inferred by themselves.


The process corresponds to, then how to write the specific process? You can’t have a memory stick in your mouth and a picture in your head. I believe many students already know, write yamL file. Almost all CI/CD platforms support yamL for configuring processes, and Github Actions are no exception. So, where does this YAML file go? Answer: in your own code repository. You might be thinking: heck, I have to copy and paste.

Yes and not quite.

Github provides two levels of reuse, the first of which is the action we just mentioned. For reuse within a single project, we can write the corresponding action logic in a separate file and reference the path directly in the process. Or if you want to reference across projects, you can put the action in a separate repository and then reference it in the process with actions/ XXXX. Github will automatically search for the repository and run it.

The second method is more popular. Github has a huge Marketplace of Actions called Github Marketplace · Actions, where most of the Actions you want, both official and private, can be found. We will also introduce several common actions in later articles.

In addition, to solve the problem of copying and pasting a CICD configuration file every time you create a new project. Github also provides reuse at the organizational level. You can create a repository called.github within an organization and develop “template” processes within it so that other repositories in the same organization can use these templates when creating new processes. See Github Docs for details.

Write in the last

That’s about the end of it. This article focuses on the basic design of Github Actions to facilitate your understanding of subsequent articles. The concept of Action is very important. Github uses action to encapsulate and layer the original imperative process configuration, forming an open and flexible tool library. Let everyone can easily reuse, greatly reduce the development cost.

In the next article, we’ll use three examples: PR merge validation, Github Page publishing, and NPM publishing to explain how github Actions can improve programming happiness.