65.9K
CodeProject 正在变化。 阅读更多。
Home

在持续集成流程中实现 git-flow 发布模型

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.86/5 (5投票s)

2016年2月26日

MIT

5分钟阅读

viewsIcon

16702

downloadIcon

92

git flow 发布模型的实现

引言

也许大多数开发者都熟悉 Git-flow 模型,它能够控制发布流程。在本文中,我将演示一种在项目中引入 Git-flow 发布的方法,该方法能够与您选择的持续集成工具集成,例如以 Atlassian Bamboo 为例。

背景

如果您以前从未听说过 Git-flow,我建议您在此处研究经典的帖子 这里 && Atlassian 如何解读相同的想法 这里

对于那些知情者,让我提醒您一个熟悉的图表

实施 - 工具

通常,我通过一套文件助手来介绍一种方法,这些文件助手会随着每个新项目而迁移和演进。我支持将代码基础架构与项目代码一起存储的理念。因此,我通常会有一个部署文件夹,其中包含 DevOps 场景(我通常使用 Ansible 工具,尽管我也有 CHEF 部署的经验),并假设开发人员提供构建逻辑,在 build/ 文件夹下输出目标工件文件。结果,典型的 DevOps 魔术结构如下:

|-- build
|-- deployment
|   |-- release_finish.sh
|   |-- release_finish_bamboo.sh
|   |-- release_start.sh
|   `-- release_start_bamboo.sh
|-- bump-version-drynext.sh
|-- bump-version.sh
|-- package.sh
|-- unpackage.sh
`-- version.txt

让我们看看文件的内容和目的。

version.txt

简单的文本文件,包含当前项目版本。我喜欢 Git-flow 中使用 Git 标签的想法,但实际上更希望能够自己控制版本。典型的版本示例是 x.y.z

0.0.1

bump-version-drynext.sh

在大多数持续集成场景中,后续版本仅更改次要版本。得益于源码中归功的便捷 Bash 脚本,我们可以获得下一个次要版本的。值。

➜  releasing  ./bump-version-drynext.sh 
0.0.2

逻辑足够简单 - 我们从 version.txt 读取当前版本,并应用 shell 魔法来获取下一个值。

#!/bin/bash

# credits: http://stackoverflow.com/questions/8653126/how-to-increment-version-number-in-a-shell-script

increment_version ()
{
  declare -a part=( ${1//\./ } )
  declare    new
  declare -i carry=1

  for (( CNTR=${#part[@]}-1; CNTR>=0; CNTR-=1 )); do
    len=${#part[CNTR]}
    new=$((part[CNTR]+carry))
    [ ${#new} -gt $len ] && carry=1 || carry=0
    [ $CNTR -gt 0 ] && part[CNTR]=${new: -len} || part[CNTR]=${new}
  done
  new="${part[*]}"
  echo -e "${new// /.}"
}

VERSION=`cat version.txt`

increment_version $VERSION

bump-version.sh

这是一个非常重要的文件。通常,我更喜欢我的项目文件(如 bower.jsonpackage.json)中的应用版本与当前项目版本匹配。这是可以实现补丁的地方。

代码的作用是为文件应用版本参数,并将新版本写入 version.txt

#!/bin/bash

set -e

CURRENT_DIR=`pwd`
VERSION=$1

echo $VERSION > version.txt

#Optionally - Update your app version in app files, like package.json, bower.json , etc
# Example for nodejs package.json:

#sed -i.bak "s/[[:space:]]*\"version\"[[:space:]]*:[[:space:]]*\".*\",/  \"version\":\"$VERSION\",/g" $CURRENT_DIR/package.json
#rm $CURRENT_DIR/package.json.bak || true

package.sh

此逻辑允许创建 tgz 压缩的工件文件,形式为 project-name-version.tgzproject-name-version-buildnumber.tgz;后者在您需要为每个构建存储工件历史记录时可能很重要。

可以通过更改 PROJECT 变量来调整文件以匹配您的项目名称。此外,如果您想了解更多关于工件的信息,它会打包 version.txt 文件,其中包含 major_versionminor_versiongit_hashbuilt 日期信息。通过这些信息,您可以识别用于生成构建的提交。

此外,Bamboo 或 Jenkins 等构建服务器可以轻松读取此类文件,并将其转换为内部变量。

生成的将放在 build/ 目录中并进行打包。

#!/bin/sh
if [ -z "$1" ]
then
  SUFFIX=""
else
  SUFFIX="-$1"
fi

PROJECT=project-name

rm -rf ./build || true
rm ${PROJECT}-*.tgz || true
mkdir -p ./build || true

VERSION=`cat version.txt`
GITCOMMIT=`git rev-parse --short HEAD`
DATE=`date +%Y-%m-%d:%H:%M:%S`

# do build here, that produces necessary files for artifact under build/ folder

echo "major_version=$VERSION" > build/version.txt
echo "minor_version=$1" >> build/version.txt
echo "git_hash=$GITCOMMIT" >> build/version.txt
echo "built=$DATE" >> build/version.txt

echo PRODUCING ARTIFACT $PROJECT-$VERSION$SUFFIX.tgz  in build/
tar cfz  $PROJECT-$VERSION$SUFFIX.tgz build

Unpackage.sh

此文件通常在构建过程的下一步执行,当工件先前已由构建步骤打包,现在您需要处理内容,例如启动部署。在 100% 的情况下,我预计只有一个工件文件,但如果存在多个版本,我会只选择最新的一个。

结果是,您将在 build 目录中获得解压后的工件。

#!/bin/sh
PROJECT=project-name
rm -rf ./build || true
current_artefact=$(find ./${PROJECT}*.tgz -type f -exec stat -c "%n" {} + | sort -r | head -n1)
echo Working with artefact: $current_artefact
tar xvzf $current_artefact
echo artefact unpacked: $current_artefact

deployment/release_start.sh

它的作用是创建发布,并将发布分支推送到服务器,以便持续集成工具可以获取并构建它。我不得不说,这里存在一些“圣战”:何时增加版本。我有两种客户:客户 - BEGIN 坚持认为 version.txt 包含他要发布的版本,因此一旦我开始发布过程,我就应该立即增加 develop 分支的版本,因为那里所有的新功能都将属于下一个发布。从另一方面,客户-END 通常不关心 version.txt,并且根据他们的理解,增加版本是发布的最后一步 - 即,在那次推送之后,之前提交的所有内容都将是 0.0.1 的进行中开发,现在我们已经发布了 0.0.2。我更倾向于在最后增加版本。如您所见,通过少量注释,两种方法都得到支持。

此批处理通过提供新发布版本作为参数,或从 version.txt 获取版本来实现发布开始。

#!/bin/sh

cd ${PWD}/../
VERSION=$1
if [ -z $1 ]
then
  VERSION=`cat version.txt`
fi

#Initialize gitflow
git flow init -f -d

# ensure you are on latest develop  & master
git checkout develop
git pull origin develop
git checkout -

git checkout master
git pull origin master
git checkout develop

git flow release start $VERSION

# bump released version to server
git push

git checkout develop

# COMMENT LINES BELOW IF YOU BUMP VERSION AT THE END
NEXTVERSION=`./bump-version-drynext.sh`
./bump-version.sh $NEXTVERSION
git commit -am "Bumps version to $NEXTVERSION"
git push origin develop

deployment/release_finish.sh

幸运的是,此步骤不需要任何外部参数。当前发布版本是从分支名称(release/0.0.2)检测到的,其余步骤都很清楚。同样,如果您遵循经典的增加版本方法,您将需要取消注释“./bump-version.sh $RELEASETAG

#!/bin/sh

cd ${PWD}/../

# PREVENT INTERACTIVE MERGE MESSAGE PROMPT AT A FINAL STEP
GIT_MERGE_AUTOEDIT=no
export GIT_MERGE_AUTOEDIT

GITBRANCHFULL=`git rev-parse --abbrev-ref HEAD`
GITBRANCH=`echo "$GITBRANCHFULL" | cut -d "/" -f 1`
RELEASETAG=`echo "$GITBRANCHFULL" | cut -d "/" -f 2`

echo $GITBRANCH
echo $RELEASETAG

if [ $GITBRANCH != "release" ] ; then
   echo "Release can be finished only on release branch!"
   return 1
fi

if [ -z $RELEASETAG ]
then
  echo We expect gitflow to be followed, make sure release branch called release/x.x.x
  exit 1
fi

#Initialize gitflow
git flow init -f -d

# ensure you are on latest develop  & master and return back
git checkout develop
git pull origin develop
git checkout -

git checkout master
git pull origin master
git checkout -

# UNCOMMENT THESE TWO LINES IF YOU BUMP VERSION AT THE END
#./bump-version.sh $RELEASETAG
#git commit -am "Bumps version to $RELEASETAG"

git flow release finish -m "release $RELEASETAG" $RELEASETAG

git push origin develop && git push origin master --tags

链接到构建服务器

所有流行的构建服务器都支持分支检测和构建。例如,Atlassian Bamboo 可以通过 UI 轻松配置,而例如,对于 Jenkins,您将需要更多的操作。

构建服务器上的过程可以实现为允许从 develop 分支启动发布,使用可选的构建步骤

并引入作为发布分支上的可选步骤来完成发布的可能性

如果您尝试使用未调整的配方,您将遇到麻烦,因为几乎所有构建服务器为了速度和大小优势都不会检出完整的存储库历史记录,因此步骤将失败。

对于 Bamboo,可以引入以下“技巧”:我们手动设置新的远程,使用命令 git remote add central "$GIT_REMOTE",所有后续操作都使用自定义远程来实现。

deployment/release_start_bamboo.sh

请参阅以下针对 Bamboo 稍微修改过的 release_start

#!/bin/sh

cd ${PWD}/../

VERSION=$1
if [ -z $1 ]
then
  VERSION=`cat version.txt`
fi

# PREVENT INTERACTIVE MERGE MESSAGE PROMPT
GIT_MERGE_AUTOEDIT=no
export GIT_MERGE_AUTOEDIT
GIT_REMOTE=git@github.com:Voronenko/gitflow-release.git

# add remote due to bamboo git cache shit
git remote add central "$GIT_REMOTE"

#Initialize gitflow
git flow init -f -d

# ensure you are on latest develop  & master
git checkout develop
git pull central develop
git checkout -

git checkout master
git pull central master
git checkout develop

git flow release start $VERSION

# bump released version to server
git push central release/$VERSION

git checkout develop

# COMMENT LINES BELOW IF YOU BUMP VERSION AT THE END
NEXTVERSION=`./bump-version-drynext.sh`
./bump-version.sh $NEXTVERSION
git commit -am "Bumps version to $NEXTVERSION"
git push central develop

deployment/release_finish_bamboo.sh

#!/bin/sh

# IMPORTANT - THIS FILE IS INTENDED TO BE EXECUTED ONLY IN BAMBOO ENVIRONMENT

cd ${PWD}/../

# PREVENT INTERACTIVE MERGE MESSAGE PROMPT AT A FINAL STEP
GIT_MERGE_AUTOEDIT=no
export GIT_MERGE_AUTOEDIT

GITBRANCHFULL=`git rev-parse --abbrev-ref HEAD`
GITBRANCH=`echo "$GITBRANCHFULL" | cut -d "/" -f 1`
RELEASETAG=`echo "$GITBRANCHFULL" | cut -d "/" -f 2`
GIT_REMOTE=git@github.com:Voronenko/gitflow-release.git

echo $GITBRANCH
echo $RELEASETAG

if [ $GITBRANCH != "release" ] ; then
   echo "Release can be finished only on release branch!"
   return 1
fi

if [ -z $RELEASETAG ]
then
  echo We expect gitflow to be followed, make sure release branch called release/x.x.x.x
  exit 1
fi

# add remote due to bamboo git cache shit
git remote add central "$GIT_REMOTE"

#Initialize gitflow
git flow init -f -d

# ensure you are on latest develop  & master and return back
git checkout develop
git pull central develop
git checkout -

git checkout master
git pull central master
git checkout -

# UNCOMMENT THESE TWO LINES IF YOU BUMP VERSION AT THE END
#./bump-version.sh $RELEASETAG
#git commit -am "Bumps version to $RELEASETAG"

git flow release finish -m "release $RELEASETAG" $RELEASETAG

git push central develop && git push central master --tags

关注点

潜在地,您可以以最小的调整重用该方法到您自己的项目。如果您将此方法用于不同的构建服务器,我将非常感谢您分享您的经验。如果您需要在您的项目上实现持续集成 - 欢迎您。

© . All rights reserved.