takeaway

Hard to learn after writing # Shell? That’s because after you didn’t find scene one, it went down well. In addition, the author further improved the function of Git-Workflow to break away from nodeJS and officially become a common scripting tool for all languages.

Two of the most critical functions are automatic version upgrade and automatic CHANGELOG generation. In the process of completing these two functions, the author also extracted some scenes as the carrier of shell learning. In addition, some of the less commonly used but fun Git commands will also be introduced.

The body of the

Automatic Version Upgrade

The git-Workflow version is implemented with a tag. Therefore, we need to at least implement the function of obtaining, updating and verifying the version number. Details are as follows:

Get the latest remote version tag

_tagVersion=$(git ls-remote --tags origin | awk "{print \$2}" | sort -t "."- k1, 1 n - k2, 2 n - k3, 3 n | awk"END{print}" | sed "s/.*\/\([0-9\.]*\).*/\1/g")
Copy the code

The command is very long and we parse it sentence by sentence. Git ls-remote –tags origin git ls-remote –tags origin

3351 d8e78b9d1cbacc9ec2cff468bb46c6c58c2e refs/tags / 1.1.0 cfa7224d274c4f0ace474267b2f16cb7bacbd9e5 refs/tags / 1.1.1 76 e49432ad7cbcac7e6bf920c5458ffca46d163b refs/tags / 1.1.1 ^ {} 526 a151cd2e558df416d9a65141812aad987ac36 refs/tags / 1.2.0 6 aeff0887811c998b77ff0308864ee312102c8ba refs/tags / 1.2.1 b3599b5c2f7d23ba70944db9b128b8a9bdc0daab refs/tags / 1.2.2Copy the code

Next, awK “{print \$2}” gets the second column, the one with the version number.

Then sort by sort -t “.” -k1, 1n-k2, 2n-k3,3n, 1.12.0 (1.2.0);

Then use awK “END{print}” to get the last line of data, refs/tags/1.2.2.

Finally using sed “s /. * / / / ([0-9. \] * \). * / / 1 / g” using regular match, to obtain the final version, namely 1.2.2.

So, let’s summarize briefly.

  • awkThe command is mainly used to process multi-column text and obtain the last line of data.
  • sortThe command is used to sort;
  • sedThe command is used to extract the regex, but its regex capability is limitedgrepThe re ability to do more.

We just need to know roughly what the command can achieve, and how to use it, we can look it up on the spot.

Version Automatic upgrade

Once you get the version, it’s time to update the version according to Semver’s specifications. The code is as follows:

# SIDE EFFECTS
# Usage:
# _updateVersion 1.2.3 patch
# echo $_tagVersion # 1.2.4
_updateVersion() {
  ver=The $1

  IFS=. read -r major minor patch <<EOF
$ver
EOF

  case "$2" in
  patch) tag="$major.$minor.$((patch + 1))" ;;
  major) tag="$((major + 1)). 0.0" ;;
  *) tag="$major.$((minor + 1)). 0" ;;
  esac

  _tagVersion=$tag
}
Copy the code

As shown in the comments, this function takes two inputs, the first being the base version number and the second being the upgrade mode (major, Minor, patch).

This function is referenced by the answer in the q&A. Where IFS stands for delimiter. The general function of this line of code is to assign the result of segmentation to major, minor and patch variables with. As delimiter. The logic of case is not much more.

It is also worth noting that the return value of shell functions can only be numbers. Therefore, to change version, you have to introduce the side effect of modifying global variables inside the function, which is really a last resort. Therefore, the author also put _ in front of variables and methods as a special identifier.

Version number verification is covered later.

CHANGELOG is automatically generated

Version issues are resolved, followed by the more complex CHANGELOG. In this case, the Xconventional Changelog is used for reference. The changelog is generated by extracting information from the commit message submitted in accordance with the contract form. The details will not be expanded, but can be simply understood as to implement the following transformation:

Commit b3599b5c2f7d23ba70944db9b128b8a9bdc0daab (HEAD - > develop, tag: 1.2.2, origin/develop) an Author: zhaolandelong <[email protected]> Date: Tue Feb 8 12:42:33 2022 +0800 feat: add fileheader to ensure version commit 6aeff0887811c998b77ff0308864ee312102c8ba Author: zhaolandelong <[email protected]> Date: Tue Feb 8 10:49:06 2022 +0800 fix: fix deploy tag commit 1e868519053913704c5fe96f0c0582143ba9cda7 Author: zhaolandelong <[email protected]> Date: Tue Feb 8 10:45:32 2022 +0800 feat: update READMECopy the code

convert

# # [1.2.2] (https://github.com/zhaolandelong/git-workflow/compare/1.2.0... 1.2.2) (2022-02-08)


### Bug Fixes

* fix deploy tag ([6aeff08] (https://github.com/zhaolandelong/git-workflow/commits/6aeff0887811c998b77ff0308864ee312102c8ba))

### Features

* add fileheader to ensure version ([b3599b5] (https://github.com/zhaolandelong/git-workflow/commits/b3599b5c2f7d23ba70944db9b128b8a9bdc0daab))
* update README ([1e86851] (https://github.com/zhaolandelong/git-workflow/commits/1e868519053913704c5fe96f0c0582143ba9cda7))

Copy the code

This readable MD text.

Get the log between the two versions and format it

Let’s start with a simple one: get the url prefix for the repository.

Git /config file for "url = XXX "and get the third column.
gitOriginUrl=$(grep -E "^\s+url = .+\.git$" .git/config | awk "{print \$3}")
# results: https://github.com/zhaolandelong/git-workflow.git

# truncate the last 4 characters
gitUrl=${gitOriginUrl:0:-4}
# results: https://github.com/zhaolandelong/git-workflow
Copy the code

Git git git git git git git git git git git

logs=$(git log --pretty=format:"%s ([%h]($gitUrl/commits/%H))" $preCommit.$curCommit)
Copy the code

git log $preCommit… $curCommit This command gets the log between two COMMITS. Notice, those three dots… It’s not any omission, it’s fixed grammar, that’s how it’s written. These two variables are flexible and can be commit, branch, or tag. So you can deal with different scenarios. For example, when the official release, will use tag; HEAD and tag will be used when testing; You can even use HEAD and branch every time you mention PR. I won’t expand it here, but if you’re interested, you can try it out for yourself.

Git log –pretty=format:” XXXX “can be used to process the log into the format you want, %x for placeholders, such as %s for content, %h for short hash, %h for long hash, etc.

The $logs generated from the above command look like this:

feat: add fileheader to ensure version ([b3599b5] (https://github.com/zhaolandelong/git-workflow/commits/b3599b5c2f7d23ba70944db9b128b8a9bdc0daab))
fix: fix deploy tag ([6aeff08] (https://github.com/zhaolandelong/git-workflow/commits/6aeff0887811c998b77ff0308864ee312102c8ba))
feat: update README ([1e86851] (https://github.com/zhaolandelong/git-workflow/commits/1e868519053913704c5fe96f0c0582143ba9cda7))
Copy the code

Now that it looks like what you want, it’s time to sort by Fetures and Bug Fixes. If other high-level languages are still very easy, using the shell is a little bit more troublesome, mainly test the level of regularity.

if[$(echo "$logs" | grep -Ec "^fix(\(.+\))?: ") -gt 0 ]; then
  echo -e "\n### Bug fixes\n" >>CHANGELOG.md
  echo "$logs" | grep -E "^fix: " | sed "s/fix:/*/" >>CHANGELOG.md
  echo "$logs" | grep -E "^fix\(.+\): " | sort | sed "s/fix(\(.*\)):/* **\1:**/" >>CHANGELOG.md
fi
Copy the code

First, grep -ec is used to determine if there is anything starting with fix (note that scope is also handled) and to count the number.

Then, if the number is greater than zero, write the Bug Fixes subtitle in the Changelog.md file.

Finally, grep + sed was used to process the records without scope and with scope respectively. Note that the records with scope are sorted. After processing is the final desired effect. Feat, Perf, and Revert all you need to do is replace Fix.

Get a commit date and format it

This requirement may at first seem easy. There are actually a few holes, mainly in git.

Git show 1.2.2 -s --pretty=format:"%ad" --date=format:"%Y-%m-%d" | awk "END{print}"
# 2022-02-08
Copy the code

Git show XXX lists the details of a commit. The parameters can be commit, tag, or branch. There is a catch here, which is that different parameters are used, the print result is not the same, so you need to use AWK to get the last line of content, to ensure the output effect. As for what will be different, here to sell a secret, we start to try the impression will be more profound.

Then, -s can filter to diff information, which we don’t need. It took me a lot of time just trying to get rid of these massive diff messages, mainly because I had some habitual thinking and wanted to use shell to solve, but git came with such commands. So choice is more important than effort…

Finally, –pretty=format already mentioned, % CD represents the submission date. –date=format:” XXX”

Check for branch and tag compliance

As git-Workflow says, you need to branch and tag your script to run properly. Icing on the cake, let’s implement the verification function again.

Checks for remote branches and red alert

  # branch check
  if [ $(git branch -r | grep -v "HEAD" | grep -Ewc " origin/($deployBR|$releaseBR|$developBR)") -ne 3 ]; then
    echo -e "\n\033[0;31mPlease create [$deployBR.$releaseBR.$developBR] branches and push them to origin first.\033[0m\n"
    exit
  fi
Copy the code

First, the remote branches are listed, the HEAD records are filtered out, and the re is used to find out if the correct number of data exactly matches the branch name. Note that grep -w is a perfect match for the entire word, so we can save the re by adding ^$.

Then, if the data is found to be incorrect, it prints red and exits. Echo -e “\033[0;31m—–\033[0m” echo -e “\033[0;31m—–\033[0m” How to change the output color of echo in Linux.

Detect the presence of a remote tag that matches semver

  # tag check
  if [ $(git ls-remote --tags origin | awk '{print $2}' | grep -Ec "^refs/tags/[0-9]+\.[0-9]+\.[0-9]+(\^\{\})? $") -eq 0 ]; then
    echo -e "\n\033[0;31mPlease create a SEMVER tag and push it to origin first.\neg: 1.0.0, 0.0.0\033[0m\n"
    exit
  fi
Copy the code

With the introduction above, this command is easy to understand. It is worth noting that remote tags may end with ^{}, so there will be some compatible expressions in the re. Here you can see that grep has sufficient support for regex.

conclusion

With a full-language version of the pure shell available, the project finally came to a close. The whole process lasted about two weeks, in fact, it was about one week, mainly because there was a Spring Festival holiday. After the whole project, I really feel that my shell and Git skills have been improved to some extent. At least I am glad that I have more confidence and judgment in my mind when I have similar needs again.

The next step is to implement the script within the department. If it can be successfully promoted to the whole department, then the project will have more value. After all, as engineers, it’s our job to hit the ground running and solve real problems. Recently found a summary of Zhang Yiming’s blog article, and finally there are new content at the end of the article, with everyone.

Feeling: The gap in life is in the self feel good in the open. — Zhang Yiming on Weibo