新建一个配置类包含打包的内容
type buildInfo struct {
Path string `json:"path"`
Branch string `json:"branch"`
Workspace string `json:"workspace"`
Scheme string `json:"scheme"`
ArchPath string `json:"archPath"`
ExportPath string `json:"exportPath"`
Config string `json:"config"`
InstallType string `json:"installType"`
Password string `json:"password"`
UpdateDescription string `json:"updateDescription"`
Upload bool `json:"upload"`
}
根据配置信息进行打包,主要用到xcodebuild工具的支持,另外就是利用golang对命令行进行调用。
func Archive(info buildInfo) {
e := os.Chdir(info.Path)
if e != nil {
panic(e.Error())
}
workspace := info.Workspace + ".xcworkspace"
archCommand := exec.Command("xcodebuild", "archive", "-workspace", workspace,
"-scheme", info.Scheme, "-archivePath", info.ArchPath)
archCommand.Stdout = os.Stdout
e = archCommand.Run()
if e != nil {
panic(e.Error())
}
}
导出成ipa 最新的xcode 9 需要一个配置文件,可以手动导出一次进行获取
func Export(info buildInfo) {
arch := info.ArchPath + ".xcarchive"
export := exec.Command("xcodebuild", "-exportArchive", "-archivePath", arch,
"-exportPath", info.ExportPath, "-exportOptionsPlist", info.Config)
export.Stdout = os.Stdout
e := export.Run()
if e != nil {
panic(e.Error())
}
}
git分支的切换,可以新建一个分支专门对于这个程序的配合使用
func switchBranch(info buildInfo) {
e := os.Chdir(info.Path)
if e != nil {
panic(e.Error())
}
branch := info.Branch
println(branch)
if len(branch) > 0 {
git := exec.Command("git", "checkout", branch)
git.Stdout = os.Stdout
e = git.Run()
if e != nil {
panic(e.Error())
}
}
}
配置读取,参数为config,对应配置Json文件的路径
func main() {
config := flag.String("config", "", "the path of the config file")
flag.Parse()
content, e := ioutil.ReadFile(*config)
if e != nil {
panic(e.Error())
}
var info buildInfo
e = json.Unmarshal(content, &info)
if e != nil {
panic(e.Error())
}
switchBranch(info)
Archive(info)
Export(info)
e = Upload(info)
if e != nil {
fmt.Println(e.Error())
}
}
蒲公英对应的上传接口
const (
userKey = ""
apiKey = ""
apiURL = "https://qiniu-storage.pgyer.com/apiv1/app/upload"
)
func Upload(info buildInfo) error {
if !info.Upload {
println("will not upload to pgy")
return nil
}
file := info.ExportPath + info.Scheme + ".ipa"
buf := new(bytes.Buffer) // caveat IMO dont use this for large files, \
w := multipart.NewWriter(buf)
fw, err := w.CreateFormFile("file", file)
if err != nil {
fmt.Println("c")
return err
}
fd, err := os.Open(file)
if err != nil {
fmt.Println("d")
return err
}
defer fd.Close()
// Write file field from file to upload
_, err = io.Copy(fw, fd)
if err != nil {
fmt.Println("e")
return err
}
w.WriteField("uKey", userKey)
w.WriteField("_api_key", apiKey)
w.WriteField("installType", info.InstallType)
w.WriteField("password", info.Password)
w.WriteField("updateDescription", info.UpdateDescription)
e := w.Close()
if e != nil {
fmt.Println("e")
return e
}
request, e := http.NewRequest(http.MethodPost, apiURL, buf)
if e != nil {
fmt.Println("e")
return e
}
//这里纠结了好久,发现设置了content-type之后貌似参数才能被服务器取到
request.Header.Add("Content-Type", w.FormDataContentType())
request.Header.Set("enctype", "multipart/form-data")
client := &http.Client{}
resp, e := client.Do(request)
if e != nil {
fmt.Println("e")
return e
}
io.Copy(os.Stdout, resp.Body)
defer resp.Body.Close()
return nil
}
配置的json文件内容
{
"path":"~/Desktop/demo",
"branch":"demo",
"workspace":"demo",
"scheme":"demo",
"archPath":"~/demo/demo",
"exportPath":"~/demo/ipas/",
"config":"~/demo/config.plist",
"password":"demo",
"updateDescription":"demo",
"installType":"2",
"upload":true
}
目录结构
➜ demo tree
.
├── config.plist
├── demo.json
└── ipas
1 directory, 2 files