关于jenkins的环境配置,这里就不介绍了,百度里面的教程够多。做下搬运工,可以参考这篇文章https://blog.csdn.net/potato512/article/details/52289136 mac下强烈建议 使用 brew 去安装 jenkins,不然会有很多坑
brew 安装jenkins 时可能根据需要修改工作目录.
修改工作目录的步骤如下:
一,安装完成后千万不要打开浏览器。
二,打开控制台窗口输入 sudo vi /etc/profile
三,这里需要注意的是这个文件在我这边的环境下默认为只读文件,可使用下面的命令修改其文件权限: sudo chmod 775 /etc/prifile
四,修改成功后再使用第一条指令打开,在文件的最后添加下面内容: export JENKINS_HOME=(要修改的路径)
然后,按ESC键,退出到插入模式,在按:号键+x 命令回车 即可保存文件
五,执行 source /etc/profile 命令。执行完成重启系统,再打开jenkins就能看到其主目录已修改成功、
这里主要介绍一下jenkins的基本使用以及通过C#去调用jenkins API 在unity上进行远程操作jiekins
一,登陆Jenkins
二,创建新的工程
输入 任务名称, 然后在最下面 复制那里输入一个已存在的工程名称,点击确定。就可以复制出一个与已存在工程参数一样的工程目录。进入新任务里面的设置修改一下SVN的地址参数即可
三,Jenkins的基本配置
在配置Jenkins的过程中,有如下配置选项:
1 General
选择参数化构建过程,可以配置所需要的参数,这里参数比较多,就不一一例举了,
2 源码管理
在源码管理里面配置好资源的地址(svn地址或git地址),设定好本地保存的文件夹,然后根据需要设置好checkout方式
SVN配置 checkout会有多个选项
Use‘svnupdate’ as much as possible
第一次发布的时候,会把工作目录下的所有文件清空,然后check-out一份完整的项目到工作目录下;
以后更新的时候,不会判断已有文件是否在svn里存在。比如工作目录下的文件123在svn里不存在,那么更新的时候不会删除,不会判断工作目录下的文件是否被改动,只会判断svn是否有新版本需要更新。
Alwayscheck out a fresh copy
第一次发布的时候,会把工作目录下的所有文件清空,然后check-out一份完整的项目到工作目录下;每一次更新的时候,都会先清除工作目录下的所有文件,然后重新check-out一份完整的项目到工作目录下。
Emulateclean checkout by firstdeleting unversioned/ignored files,then ‘svn update’
第一次发布的时候,会把工作目录下的所有文件清空,然后check-out一份完整的项目到工作目录下。以后更新的时候会判断工作目录下的文件是否在svn里存在,如果不存在则删除,如果存在且有新版本则更新。会判断工作目录下的文件是否被改动,不管有没有新版本,都会还原为svn上的最新版本。svn上删除了文件,更新的时候,工作目录里的此文件也会被删除。
Use‘svn update’ as much aspossible,with‘svn revert’ before update
第一次发布的时候,会把工作目录下的所有文件清空,然后check-out一份完整的项目到工作目录下;先放弃所有本地修改,然后尽可能进行svn更新。避免本地修改导致本地项目与代码仓库不一致
我这里选择的是最后一个。但是在热更新的时候会有问题,打热更新的时候需要转换平台,而svn上的是默认的,热更包打完后本地存在的是转换平台后的资源。在下一次打包热更资源时,会导致本地资源与svn资源不一致的情况。所以下一次打包时,会checkout SVN上的资源,删除本地的资源。
3构建触发器
这里用的build priodically. 每天2:00定时触发
PollSCM 是没隔一段时间会去检测svn上的变化,然后触发构建
4然后是最重要的构建
-batchmode -executeMethodPerformBuild.CommandLineBuild Platform-$Platform AppID-$AppID Version-$VersionIPAddress-$IPAddress -quit
在方法中这样解析参数:
附上unity上接受jenkins 的类
public class PerformBuild
{
static string[] GetBuildScenes()
{
List
foreach(EditorBuildSettingsScene e in EditorBuildSettings.scenes)
{
if(e==null)
continue;
if(e.enabled)
names.Add(e.path);
}
return names.ToArray();
}
///
/// 此方法是从jienkins上接受 数据的 方法
///
static void CommandLineBuild ()
{
try
{
Debug.Log("Command line build\n------------------\n------------------");
string[] scenes = GetBuildScenes();
string path = "";//这里的路径是打包的路径, 定义
Debug.Log(path);
for (int i = 0; i < scenes.Length; ++i)
{
Debug.Log(string.Format("Scene[{0}]: \"{1}\"", i, scenes[i]));
}
// ProjectPackageEditor.BuildByJenkins(GetJenkinsParameter("Platform"), GetJenkinsParameter("AppID"), GetJenkinsParameter("Version"), GetJenkinsParameter("IPAddress"));
Debug.Log("Starting Build!");
Debug.Log(GetJenkinsParameter("Platform"));
if (PlatformAandroid())
{
BuildPipeline.BuildPlayer(scenes, path + ".apk", BuildTarget.Android, BuildOptions.None);
}
else
{
//BuildPipeline.BuildPlayer(scenes, path, BuildTarget.iOS, BuildOptions.AcceptExternalModificationsToPlayer);
}
}
catch(Exception err)
{
Console.WriteLine("方法F中捕捉到:"+err.Message);
throw;//重新抛出当前正在由catch块处理的异常err
}
finally
{
Debug.Log("----------> I am copying! <--------------");
}
}
///
///解释jekins 传输的参数
///
///
///
static string GetJenkinsParameter(string name)
{
foreach(string arg in Environment.GetCommandLineArgs())
{
if (arg.StartsWith(name))
{
return arg.Split("-"[0])[1];
}
}
return null;
}
}
三,jenkins 打包安卓apk过程
在mac机上下载AndroidSDK ,jdk,ndk。并配置好相应环境。在unity Preferences
置好 sdk,jdk,ndk路径
不在unity上设置相对应的路径是不能够转平台的。jenkins 打包时,必须要把unity的工程关掉
注意:
1电脑上存在多版本的 jdk 时,打包过程中会导致打包失败,解决办法是删掉多余的jdk,只保留一个即可
2jenkins打包打出的安卓文件并不是apk格式,所以需要改名后缀为apk才行,所以在生成apk路径的后面加了一个后缀名
3 jenkins 从SVN拉下工程在本地进行分文件夹进行保存
将svn拉下来的工程路径 与 平台名称进行组合。平台前面的名称随意
四,关于mac机上jenkins的打包相关的路径
Workspace 是jenkins的工作目录
Workspace下面的子目录 除build外,其余都是对应的单个项目的目录
也就是jenkins创建任务的名称。创建任务后,会自动在workspace下生成对应名称的文件夹。
拿testAndorid来举例。TestAndroid是我新建的一个任务(名字无视,随便取,最好是对应工程的名称来区分)。 TestAndroid下面会对应4个文件夹,子目录的TestAndroid是存放安卓工程的目录,TestIOS是存放IOS工程的目录。(就是从svn上拉下来的工程,都是经过jenkins转平台后的工程。Android 目录是 存放打包成功后的 apk 包。 XCode 是存放打包后的苹果Xcode工程。
另外还有一个Build文件夹主要是用于打Xcode工程是,从里面拷贝sdk用的
六,关于通过jenkins api 远程访问并操作jenkins的实现
目前是通过 用unity 通过http请求 jenkins的操作
第一步,在jenkins是上设置访问权限,根据需要访问权限
取消勾选防站点请求。
我这里使用的比较暴力的方式,选的任何用户可以使用任何事,也可以根据需要选择下面的安全设置.设置此权限的话,访问jenkins页面就不需要登录了,后面用api访问jenkins时就不用添加认证。
也可以选择登录用户可以做任何事情,此选择需要登录才可以使用,用api访问jenkins时需要添加Basic认证才可以访问成功
第二步,通过http请求特定的jenkins api 进行请求
下面例举部分部分jenkins api 地址
jenkinsUrl 是jenkins的地址
jobName 是 请求的任务名称
1获取build信息:
url= jenkinsUrl + "/job/" +jobName + "/api/json?tree=builds[number]{0,10}";
2 创建工程
url= jenkinsUrl + "/createItem?name="+jobName
创建工程时需要在请求上发送与线上对应的xml文件
在某项目的xml地址如下
http://jenkinsUrl/job/SiChuanQiPai/config.xml
然后在unity本地保存一个 与之一样的格式 xml 文件
Xml 文件格式类似这个样子,创建新的job 时,修改一下xml里面的参数,然后保存在本地。然后请jenkinsUrl+ "/createItem?name=" +jobName 这个地址,将本地的xml文件传输过去。
调用下面的方法即可: 参数 filePath 为xml文件的路径
自己写的:(此方法 上传的文件 的格式必须为 UTF-8无BOM格式)
privatestaticstringPostHttp2(string url, string filePath)
{
stringresponseContent;
varmemStream = newMemoryStream();
varwebRequest = (HttpWebRequest)WebRequest.Create(url);
varfileStream = newFileStream(filePath, FileMode.Open,FileAccess.Read);
// 设置属性
webRequest.Method = "POST";
webRequest.Timeout = 300000;
webRequest.ContentType = "application/xml;charset=UTF-8";
webRequest.KeepAlive = true;
webRequest.UserAgent = "Test";
webRequest.Accept = "gzip,deflate";
CredentialCachemycache = new CredentialCache();
mycache.Add(new Uri(jenkinsUrl),"Basic", new NetworkCredential(username, password));
webRequest.Credentials = mycache;
webRequest.Headers.Add("Authorization", "Basic " +Convert.ToBase64String(new ASCIIEncoding().GetBytes(username + ":" +password)));
// 写入文件
varbuffer = newbyte[1024];
intbytesRead; // =0
while((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
{
memStream.Write(buffer, 0,bytesRead);
}
webRequest.ContentLength =memStream.Length;
try
{
varrequestStream = webRequest.GetRequestStream();
memStream.Position = 0;
vartempBuffer = newbyte[memStream.Length];
memStream.Read(tempBuffer, 0,tempBuffer.Length);
memStream.Close();
requestStream.Write(tempBuffer, 0,tempBuffer.Length);
requestStream.Close();
varhttpWebResponse = (HttpWebResponse)webRequest.GetResponse();
using (varhttpStreamReader = newStreamReader(httpWebResponse.GetResponseStream(),Encoding.GetEncoding("utf-8")))
{
responseContent =httpStreamReader.ReadToEnd();
}
fileStream.Close();
httpWebResponse.Close();
webRequest.Abort();
returnresponseContent;
}
catch (WebException ex)
{
省略
}
}
使用BestHttp插件的方法是如下:(此方法 上传的文件 的格式必须为 UTF-8格式)
staticvoidPostHttpJenkins(stringurl,string filePath)
{
var request = newHTTPRequest(newUri(url), HTTPMethods.Post,(req, resp) =>
{
HttpPostResponseCode(resp.StatusCode);
Debug.Log(resp.DataAsText);
});
request.Credentials = newCredentials(AuthenticationTypes.Basic, username, password);
var fileStream = newFileStream(filePath,FileMode.Open);
var buffer = newbyte[fileStream.Length];
request.SetHeader("Content-Type","application/xml; charset=UTF-8");
fileStream.Read(buffer, 0,buffer.Length);
request.RawData = buffer;
request.Send();
fileStream.Close();
}
3更新Jenkinsjob配置
url= jenkinsUrl+ "/job/" + jobName + "/config.xml"
更新配置时,与创建job类似,同样调用上面的PostHttp2 方法,将此url与修改的xml文件的地址传过去即可
4 获取jenkins Job配置
url=jenkinsUrl + "/job/" + jobName + "/config.xml"
方法一:
publicstaticstring GetHttp(string url) {
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "GET";
httpWebRequest.Timeout = 20000;
CredentialCache mycache = newCredentialCache();
mycache.Add(newUri(jenkinsUrl),"Basic",newNetworkCredential(username, password));
httpWebRequest.Credentials = mycache;
httpWebRequest.Headers.Add("Authorization","Basic "+ Convert.ToBase64String(newASCIIEncoding().GetBytes(username + ":" + password)));
HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
StreamReader streamReader = newStreamReader(httpWebResponse.GetResponseStream());
string responseContent = streamReader.ReadToEnd();
httpWebResponse.Close();
streamReader.Close();
return responseContent; }
方法二:使用bestHTTP
staticvoidGetHttpJenkins(stringurl)
{
var request = newHTTPRequest(newUri(url), HTTPMethods.Get,(req, resp) =>
{
HttpPostResponseCode(resp.StatusCode);
});
request.Credentials = newCredentials(AuthenticationTypes.Basic, username, password);
request.Send();
}
5,BuildJenkins工程
有参数地址:url= jenkinsUrl + "/job/" + jobName + "/buildWithParameters"
无参数地址: url= jenkinsUrl + "/job/" + jobName + "/build"
下面是有参数的调用方法(使用bestHTTP插件)
publicstaticvoidBuildJenkins()
{
stringurlString = jenkinsUrl + "/job/" + jobName + "/buildWithParameters";
FiltrationPath();
varrequest = newHTTPRequest(newUri(urlString),HTTPMethods.Post, (req, resp) =>
{
Debug.Log(resp.StatusCode);
if(resp.StatusCode != 401)
Debug.Log("Authenticated");
else
Debug.Log("NOTAuthenticated");
Debug.Log(resp.DataAsText);
});
//添加Basic认证
request.Credentials = newCredentials(AuthenticationTypes.Basic, username,password);
request.AddField("Plantform",platformName);
request.AddField("AppID",appID);
request.AddField("VersionNumber",versionNumber);
request.AddField("IPAddress",ipAddress);
request.AddField("isHotFix",isHotFix?"true":"false");
request.AddField("path",content);
request.Send();
}
注意这里有个大坑:如果本身的工程是带有参数的,请求的是无参数地址的时候,会返回错误码 400
另外:jenkin是有账号密码的,所以http请求是需要Credentials认证才能进行访问。有参数的http 请求的数据形式为 form data 形式。Form data格式上面的besthttp插件已经封装好了。
Build热更资源前需要先转换平台
6:关于请求jenkins 服务器返回的错误码
privatestaticvoid HttpPostResponseCode(int errorCode)
{
switch (errorCode)
{
case 400:Debug.LogError("传递的参数不正确");
break;
case 401:Debug.LogError("Not Authenticated");
break;
case 403:Debug.LogError("未添加basic认证");
break;
case 500:Debug.LogError("传递的文件格式不对,需要为UTF-8格式(上面PostHttp2里面需要为UTF-8 无BOM 格式,具体原因还不清楚)");
break;
}
}
Xml文件操作的坑
Xml Linq查询节点
var StringParameterDefinition = xDoc.Element("project")
.Element("properties")
.Element("hudson.model.ParametersDefinitionProperty")
.Element("parameterDefinitions")
.Element("hudson.model.TextParameterDefinition");
对xml文件进行操作时,version的版本要是1.0 ,不然操作会不成功。从jenkins网页上直接获取的的xml文件的version是1.1,所以操作会报错误
发送改xml到jenkins服务器上 ,会出现以下错误