陈江川

邮箱:jiangchuanc@gmail.com

项目管理

因为在公司维护了一个gitbook,所以个人的博客最近很少更新。前些日子和朋友聊天问我最近怎么没写博客,想想还有零星几个朋友关注着,让我觉得博客还是有必要维护下去。

模块化的工作已经陆续开始,为了实现开发过程中的正规化,这段时期做了以下几件事:

1)制定代码规范;
2)git-flow,实现本地代码仓库管理;
3)搭建Phabricator,实现Code-Review;
4)使用OCLint,实现静态代码分析;
5)Jenkins自动化构建。

文中不会过多涉及服务的搭建,一些安装配置问题google吧,自己动手丰衣足食!

<一> git-flow

git-flow 是一个 git 扩展集,按 Vincent Driessen 的分支模型提供高层次的库操作。可以参考git-flow 备忘清单

下面的所有操作都是通过命令行执行的,你也可以使用SourceTree,SourceTree已经提供了git-flow图形化支持。

安装

brew install git-flow-avh

开始

初始化

进入项目目录进行初始化,一直按回车

git flow init

这个命令会做了两件事:

  • 在当前项目下创建一个基于master的develop分支;
  • 切换到develop分支。

新功能开发

1) 初始化

git flow feature start 功能名称

这个命令做了以下几件事:

  • 创建一个基于develop的‘feature/功能名字’分支;
  • 切换到‘feature/功能名称’分支。

2) 完成新功能开发

git flow feature finish 功能名称

这个命令做了以下几件事:

  • 合并‘feature/功能名称’分支到develop分支上;
  • 删除‘feature/功能名称’分支;
  • 切换回develop分支。

3) 如果多人合作开发一个新功能,你需要把代码push到服务器上给其他成员使用:

git flow feature publish 功能名称

这个命令做了:

  • 把‘feature/功能名称’分支push到服务器

4)同理,多人开发一个新功能,你需要获取其他成员的代码,有两种情况:

本地没有'feature/功能名称'分支

git flow feature track 功能名称

本地已经有了'feature/功能名称'分支

git flow feature pull origin 功能名称

这两个命令实际上都是:

  • 拉取服务器上的'feature/功能名称'分支到本地:

5)完成了新功能开发:

git flow feature finish 功能名称

该命令做了以下几件事:

  • 合并‘feature/功能名称’分支到develop分支;
  • 删除‘feature/功能名称’本地分支;
  • 如果远程仓库有'feature/功能名称'分支,删除;
  • 切换回develop分支。

发布版本

当功能点都完成时(需要发布新版本了),就基于develop创建一个发布(release)分支,然后升级版本号并在最后发布日期前把Bug Fix掉吧。

这里的“版本号”对应着上线的版本号!

1)创建一个release版本

git flow release start 版本号

该命令做的事情:
* 创建一个基于develop分支的‘release/版本号’分支;
* 切换到‘release/版本号’分支。

2)如果多人共同修改这个版本的bug,你需要push代码到服务器供其他成员使用:

git flow release publish 版本号

内部做的事情和“新功能开发 -> git flow feature publish”命令一样。

3)获取服务器‘release/版本号’的代码

本地没有'release/版本号'分支

git flow release track 版本号

本地已经有了'release/版本号'分支

git flow release pull origin 版本号

4)完成release版本

git flow release finish 版本号

做了以下几件事:
* 拉取服务器代码,以确保本地代码为最新;
* release内容和合并到master和develop分支上;
* 代码在合并到master和develop分支的同时会打上“版本号”的tag;
* 删除“release/版本号”分支,并切回到develop分支。

紧急修复bug

已发布的版本出现紧急bug需要修复,使用hotfix,该分支基于master:

1)初始化

git flow hotfix start 版本号

做了以下几件事:
* 创建基于master的“hotfix/版本号”分支;
* 切换到“hotfix/版本号”分支。

2)完成紧急修复

git flow hotfix finish 版本号

内部原理和‘git flow release finish’一样

看图说话

gitflo

<二> Phabricator

Phabricator是一套基于Web的软件开发协同工具,包括了代码审核工具Differential,资源库浏览器Diffusion,变更监测工具Herald,Bug跟踪工具Maniphest和维基工具Phriction。

最初是想在OS安装Phabricator,试了三四次都没有成功,后面转到Ubuntu下安装了,下面都是以Ubuntu为例。大部分内容来自官网的Installation Guide

Phabricator服务搭建

安装要求

支持除了Windows外的大部分系统:

  • Linux
  • Mac OS X
  • FreeBSD

需要一个web服务器(下面的任何一个):

  • Apache
  • nginx
  • lighttpd

还需要:

  • MySQL:MySQL5.5版本以上
  • PHP:PHP5.2版本以上

安装

Ubuntu和RedHat官方都有提供安装脚本,很方便。

把下载的install_ubuntu.sh放在一个任何一个文件夹下,我放在/var/www/下,执行:

chmod 777 install_ubuntu.sh
./install_ubuntu.sh

安装完后,目录下会有arcanist、libphutil、phabricator三个文件夹。
打开浏览器输入127.0.0.1,不出意外会出现Phabricator的首页;如果出了意外google吧。

配置

启动Phabricator后,在Web端会发现很多警告,基本上按照上面的提示操作就可以消除警告。这里提示下,git clone如果使用http的话,会有上传大小限制,修改Apache和php上传文件大小限制,如何修改,还是那句话:问google。

完成如下图所示:

命令行工具Arcanist(arc)

Arcanist是Phabricator提供的一个Differential(代码审核)命令行工具,下面以OS系统为例。

安装

1)进入你想安装arc的目录,以~/Documents/arc为例:

mkdir ~/Documents/arc
cd ~/Documents/arc
git clone git://github.com/facebook/libphutil.git
git clone git://github.com/facebook/arcanist.git

2)将arc添加到环境变量中

open ~/.profile

添加:

export PATH=$PATH:~/Documents/arc/arcanist/bin/

重启终端,或者在命令行输入:

source ~/.profile

配置

  • 全局配置

1)设置arc默认编辑器

arc set-config editor "vim"

2)设置phabricator的url(根据实际情况配置)

arc set-config default http://192.168.51.75:8080
  • 当从phabricator代码地址git clone后,需要在本地电脑上安装证书:
cd 项目的根目录
arc install-certificate

使用

1)提交审核请求,不需要使用git add、git commit

arc diff

2)代码通过了审核后(可以在phabrictor网站上看到),发布代码

arc land

3)查看所有的提交状态

arc list

<三> git-flow结合arc

git-flow很好的解决了本地的代码仓库的管理,而Phabricator的arc工具解决了远程仓库的代码审核问题。

在远程仓库中将有两个分支:master和develop。与本地的master和develop分支对应,代码审核基于develop分支进行。

准备

1)设置代码审核(arc diff)的分支以及通过审核后push的分支(arc land),在项目的一级目录创建.arcconfig文件,并添加如下内容(如果有跳过此步):

{
# 这个地址是你自己的phabricator服务器地址
"phabricator.uri" : "http://192.168.51.75/", 
"base": "git:merge-base(origin/develop), arc:prompt",
"arc.land.onto.default": "develop"
}

2)设置命令别名,因为在arc land之后还需要输入两个命令,这里为了方便,把两个命令合并成一个。打开~/.profile,如果你使用的是zsh,则打开~/.zshrc,添加:

alias git-codeReview-start="git branch code-review develop; git checkout code-review; git push origin code-review"
alias git-codeReview-beforArcLand="git checkout develop; git merge code-review"
alias git-codeReview-finish="git push origin --delete code-review; git branch -D code-review"

然后关闭终端重新打开,或者在终端输入:

source ~/.profile

流程

1)git-codeReview-start:为审核做准备,在本地仓库和远程仓库创建一个code-review分支,并切换到code-review分支;

2)arc diff:提交代码审核;

3)git-codeReview-beforeArcLand:把code-review分支合并到develop上,切换到develop分支;

4)arc land:审核通过,提交代码到服务器;

5)git-codeReview-finish:审核完成,删除远程仓库和本地仓库的code-review分支,切回到develop分支。

看图说话

git clone

<四> OCLint静态代码分析

可参考Code Review-OCLint系列开篇,这里就不过多累赘。

<五> Jenkins自动化构建

安装可参考Jenkins官网,然后就是安装自己需要的插件,网上很多文章,这里不细说。

Jenkins结合OCLint

1)安装PMD Plug-in插件;

2)配置项目


前提:目前分析的都是私有CocoaPods私有库,而私有库的源码是在Pods.xcodeProj中。

#!/bin/bash

# 在这修改target和scheme名字,以及不需要分析的文件夹
TARGET_NAME=""
SCHEME_NAME=""
IGNORE_FOLDER=""

pod update
rm -rf build/

cd Pods/

rm report.html compile_commands.json

xcodebuild clean

xcodebuild -target ${TARGET_NAME} -scheme ${SCHEME_NAME} | xcpretty -r json-compilation-database -o compile_commands.json

oclint-json-compilation-database \
  -e ${IGNORE_FOLDER} \
  -- \
  -stats \
  -verbose \
  -report-type pmd -o=report.html \
  -max-priority-1=99999 -max-priority-2=99999 -max-priority-3=99999 \
  -rc LONG_LINE=200 \
  -rc SHORT_VARIABLE_NAME=3 \
  -disable-rule=BrokenOddnessCheck \
  -disable-rule=VerifyProhibitedCall \
  -disable-rule=VerifyProtectedMethod \
  -disable-rule=SubclassMustImplement \
  -disable-rule=BaseClassDestructorShouldBeVirtualOrProtected \
  -disable-rule=DestructorOfVirtualClass \
  -disable-rule=ParameterReassignment \
  -disable-rule=AvoidDefaultArgumentsOnVirtualMethods \
  -disable-rule=AvoidPrivateStaticMembers \

重点说下构建 -> Execute shell里面的内容:

  • source ~/.zshrc可不写;
  • cd Pods/因为要编译Pods.xcodeProj;
  • rm report.html compile_commands.json删除旧数据;
  • xcodebuild clean clean;
  • xcodebuild -target xxx -scheme xxx | xcpretty -r json-compilation-database -o compile_commands.json 编译Pods.xcodeProj中的名字为xxx的target和scheme,并生成compile_commands.json
  • oclint-json-compilation-database根据compile_commands.json进行静态代码分析,里面的 -e xxx表示忽略xxx这个文件夹,这个文件夹里面的代码不做分析。

3)构建成功会有一个PMD Warnings

Jenkins自动化打包iOS App

出现的问题

1)在Xcode8时代,构建中直接使用Xcode插件进行配置,但是到Xcode9打包会报错:

xcodebuild[10696:413621] [MT] IDEDistribution: Step failed: <IDEDistributionSigningAssetsStep: 0x7fb3f664e8e0>: Error Domain=IDEDistributionSigningAssetStepErrorDomain Code=0 "Locating signing assets failed." UserInfo={NSLocalizedDescription=Locating signing assets failed., IDEDistributionSigningAssetStepUnderlyingErrors=(
    "Error Domain=IDEProvisioningErrorDomain Code=9 \"\"NAME.app\" requires a provisioning profile with the Push Notifications feature.\" UserInfo={NSLocalizedDescription=\"NAME.app\" requires a provisioning profile with the Push Notifications feature., NSLocalizedRecoverySuggestion=Add a profile to the \"provisioningProfiles\" dictionary in your Export Options property list.}"
)}
error: exportArchive: "NAME.app" requires a provisioning profile with the Push Notifications feature.

Error Domain=IDEProvisioningErrorDomain Code=9 ""NAME.app" requires a provisioning profile with the Push Notifications feature." UserInfo={NSLocalizedDescription="NAME.app" requires a provisioning profile with the Push Notifications feature., NSLocalizedRecoverySuggestion=Add a profile to the "provisioningProfiles" dictionary in your Export Options property list.}

解决方法:在构建->Xcode->Advanced Xocde build options中的Custom xcodebuild arguments添加-allowProvisioningUpdates

2)接着报了另一个错误

DeveloperPortal: Completed request 4ED8F6F3-B002-4B66-AFD4-AF2531A44A6E (failure): {
    creationTimestamp = "2017-12-07T06:13:37Z";
    httpCode = 200;
    protocolVersion = QH65B2;
    requestUrl = "https://developerservices2.apple.com/services/QH65B2/viewDeveloper.action";
    responseId = "0d45768c-7a91-4a65-b3b2-b885668408fa";
    resultCode = 1100;
    resultString = "authentication.failed";
    userLocale = "en_US";
    userString = "Your session has expired.  Please log in.";
}

网上说重新登录Xcode的iOS Develop账号,但是没有效果。没办法,只能走shell路子了。

使用shell进行打包

#!/bin/bash

# 根据实际情况修改target和scheme名字
TARGET_NAME=""
SCHEME_NAME=""
XCARCHIVE_NAME="XXX.xcarchive"

# clean
xcodebuild clean -target ${TARGET_NAME} \
    -scheme ${SCHEME_NAME} \
    -configuration Debug

rm -rf ${WORKSPACE}/build
mkdir -p ${WORKSPACE}/build/Debug-iphoneos

# build xcarchive
xcodebuild -archivePath ${WORKSPACE}/build/Debug-iphoneos/${XCARCHIVE_NAME} \
    -target ${TARGET_NAME} \
    -scheme ${SCHEME_NAME} \
    -configuration Debug \
    archive

# ipa
xcodebuild -exportArchive -archivePath  ${WORKSPACE}/build/Debug-iphoneos/${XCARCHIVE_NAME}\
    -exportPath  ${WORKSPACE}/build/Debug-iphoneos/ \
    -exportOptionsPlist  ${WORKSPACE}/ExportOptions.plist \
    -allowProvisioningUpdates

这里ExportOptions.plist的文件使用Xcode进行Archive获取的,然后把ExportOptions.plist放到项目的根目录下。

« 回顾、展望 Thinking »