2014년 12월 12일 금요일

Jenkins + Unity3D

개요

Jenkins의 플러그인중, 유니티빌드를 지원하는 플러그인이 존재한다.
OSX Local에 Jenkins를 도입한후, Unity3DBuilder plugin을 이용해 빌드를 자동화한다.

전제
OSX를 이용하는 Unity Pro(Basic은 무리. 하기 기록을 참고)개발환경

참고자료

https://wiki.jenkins-ci.org/display/JENKINS/Unity3dBuilder+Plugin

도입수순

Jenkins OSX Installer를 통한 인스톨

인스톨이 완료된후 http://localhost:8080/ 로 접근하여 대쉬보드를 확인

필요한 플러그인을 인스톨

플러그인의 인스톨은 Jenkins 대쉬보드에서

Jenkins > UpdateCenter > Manage Plugins > Available

에서 선택후 인스톨 할 수 있음(GUI상만으로 가능)

Jenkins > Configure System > Unity3D

에서 유니티 앱을 추가.
(이름(임의)와 유니티 에디터 앱의 로컬 패스를 지정해야함. 이 부분 때문에 Linux상에서의 구성은 힘든가...?)

사용수순

유니티 프로젝트를 Jenkins로 빌드함에 앞서, 아래의 사전준비가 필요하다.

https://wiki.jenkins-ci.org/display/JENKINS/Unity3dBuilder+Plugin#Unity3dBuilderPlugin-Prerequisites

아래의 스크립트가 프로젝트상에 존재할 필요가 있다.
같은 패스에 스크립트를 작성해 입력.


Assets/Editor/MyEditorScript.cs
using UnityEngine;
using UnityEditor;
using System;
using System.Collections;
using System.Collections.Generic;

class MyEditorScript {
        static string[] SCENES = FindEnabledEditorScenes();

        static string APP_NAME = "YourProject";
        static string TARGET_DIR = "target";

        [MenuItem ("Custom/CI/Build Mac OS X")]
        static void PerformMacOSXBuild ()
        {
                 string target_dir = APP_NAME + ".app";
                 GenericBuild(SCENES, TARGET_DIR + "/" + target_dir, BuildTarget.StandaloneOSXIntel,BuildOptions.None);
        }

 private static string[] FindEnabledEditorScenes() {
  List<string> EditorScenes = new List<string>();
  foreach(EditorBuildSettingsScene scene in EditorBuildSettings.scenes) {
   if (!scene.enabled) continue;
   EditorScenes.Add(scene.path);
  }
  return EditorScenes.ToArray();
 }

        static void GenericBuild(string[] scenes, string target_dir, BuildTarget build_target, BuildOptions build_options)
        {
                EditorUserBuildSettings.SwitchActiveBuildTarget(build_target);
                string res = BuildPipeline.BuildPlayer(scenes,target_dir,build_target,build_options);
                if (res.Length > 0) {
                        throw new Exception("BuildPlayer failure: " + res);
                }
        }
}
---

[Jenkins상의 특정 프로젝트] > Configure > Build
에서 위에서 정의한 유니티앱의 종류(이름으로 선택)를 지정후, 빌드옵션을 지정. 빌드 옵션에는 하기 옵션을 추가.

-quit -batchmode -executeMethod MyEditorScript.PerformMacOSXBuild 

상기옵션은 unity3dbuilder에서 기본적으로 제공하는 옵션이다.
구체적으론 아래의 공식문서를 참고하는게 좋을듯.

http://docs.unity3d.com/Manual/CommandLineArguments.html

-executeMethod가 내부에 작성된 코드를 호출할 수 있는 부분인듯 하다.
이 기능을 응용하면 이전부터 불편하게 느꼈던 AssetBundle의 일괄작성과 같은 부분의 기능도 커맨드라인 상으로만 구축이 가능할거 같이도 보인다.

또한 OSX를 기준으로 했을때는 권한에 관련된 문제가 발생함.

_RegisterApplication(), FAILED TO establish the default connection to the WindowServer, _CGSDefaultConnection() is NULL. 2014-12-12 00:01:53.560 Unity[88456:d07] NSDocumentController Info.plist warning: The values of CFBundleTypeRole entries must be 'Editor', 'Viewer', 'None', or 'Shell'.

위 문제에 관해서는

 http://la-stranger.tistory.com/entry/unity-jenkins-autobuild2

상기 투고의 Jenkins Slave Agent작성부분을 참고.
Jenkins Slave Agent로 빌드를 실시하는 경우 Java Slave가 빌드를 수행하게끔 해줄 필요가 있음. master node agent로 빌드를 지속할 경우에는 여전히 문제가 발생.

http://serverfault.com/questions/359793/tell-jenkins-to-run-a-specific-project-on-a-particular-slave-node 

따라서 위의 답변내용을 참고로 하여 NodeLabel Parameter 플러그인을 인스톨한후, 특정 슬레이브 노드가 접속중일때만 빌드를 실시하게끔 할 필요가 있음.

또한...
대부분의 현장의 개발환경이라면 UnityPro가 당연한 환경일거라 생각되지만
현재 basic으로 테스트하고 있는 환경에서는 아래와 같은 문제가 확인되었다.

Exception: BuildPlayer failure: Building Player from editor scripts requires Unity PRO 

적어도 Jenkins를 이용하려면 프로 라이센스가 요구되는듯.

http://docs.unity3d.com/ScriptReference/BuildPipeline.BuildPlayer.html

위 url에서 문제가 되는 기능을 확인할 수 있다.

-----------

우선 상기 상태에서 유니티를 일시적으로 30일 체험판모드로 구동후, 빌드를 시험해보았고 NGUI 3.6버전이 들어간 샘플을 하나 빌드씬에 추가한 상태에서 빌드해본 결과, 빌드가 가능했다.

단, 아래의 메세지로부터 동일 프로젝트를 열어둔 상태에서의 CI빌드는 불가능해보인다.

Multiple Unity instances cannot open the same project.

빌드 노드 머신을 따로 분리하던지 할 필요성이 있는듯.

-----------

추가적으로 코드품질 관리를 위한 코드복잡도계산 관련의 플러그인을 살펴보았다.

우선 될거같아 보였던 CCM Analysis Plugin

https://wiki.jenkins-ci.org/display/JENKINS/CCM+Plugin

결론부터 말하자면 Unity에선 못쓸거같다.

.NET을 위한 코드복잡도 리포트 기능이고,
using UnityEngine;
이라는곳에서부터 걸리는듯

Cleanup mono
debugger-agent: Unable to listen on 6
Exiting batchmode successfully now!
[CCM] Collecting CCM analysis files...
[CCM] Finding all files that match the pattern **/*.cs
[CCM] Parsing 219 files in /Users/ruel/Jenkins/slave/workspace/ngui_samples
[CCM] Parsing of file /Users/ruel/Jenkins/slave/workspace/ngui_samples/Assets/Editor/MyEditorScript.cs failed due to an exception:

org.xml.sax.SAXParseException; lineNumber: 2; columnNumber: 1; Content is not allowed in prolog.
 at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
 at org.apache.xerces.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
 at org.apache.commons.digester.Digester.parse(Digester.java:1916)
 at hudson.plugins.ccm.parser.CcmParser.parse(CcmParser.java:90)
 at hudson.plugins.analysis.core.AbstractAnnotationParser.parse(AbstractAnnotationParser.java:53)
 at hudson.plugins.analysis.core.FilesParser.parseFile(FilesParser.java:323)
 at hudson.plugins.analysis.core.FilesParser.parseFiles(FilesParser.java:281)
 at hudson.plugins.analysis.core.FilesParser.parserCollectionOfFiles(FilesParser.java:232)
 at hudson.plugins.analysis.core.FilesParser.invoke(FilesParser.java:201)
 at hudson.plugins.analysis.core.FilesParser.invoke(FilesParser.java:31)
 at hudson.FilePath$FileCallableWrapper.call(FilePath.java:2677)
 at hudson.remoting.UserRequest.perform(UserRequest.java:121)
 at hudson.remoting.UserRequest.perform(UserRequest.java:49)
 at hudson.remoting.Request$2.run(Request.java:324)
 at hudson.remoting.InterceptingExecutorService$1.call(InterceptingExecutorService.java:68)
 at java.util.concurrent.FutureTask.run(FutureTask.java:266)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
 at hudson.remoting.Engine$1$1.run(Engine.java:63)
 at java.lang.Thread.run(Thread.java:745)

-----

댓글 없음:

댓글 쓰기