JenkinsCIをGitHubで動作するように構成しました。$ {workspace}は正常に読み込まれますが、ビルドする実際のプロジェクトはリポジトリのサブディレクトリにあります。
https://github.com/androidfu/CodeExamples
Jenkins内からAntを呼び出すと、build.xmlが見つからないと表示されます。これは、build.xmlが実際には$ {workspace}/DeveloperDebugPreferencesに存在するためです。
Jenkins内で使用するAntのビルドファイルを構成できます。Jenkinsサーバーでジョブを参照している場合は、[構成]を選択してから、Antターゲットの下にある[詳細設定]オプションを選択できます。
ファイルを編集したい場合はconfig.xml
、次のようなビルド設定が表示されます。
<builders>
<hudson.tasks.Ant>
<targets>your_target_name</targets>
<buildFile>${workspace}/DeveloperDebugPreferences/build.xml</buildFile>
</hudson.tasks.Ant>
</builders>
私はこれをもう少し進めて、コードをチェックアウトし、ビルドして SSH 経由で公開する、Git へのコミット時に開始されるビルド システムを作成したいと考えました。さらに、ファイル名にタグ付けされたビルドのコミットが必要でした。最初のステップは、git の post-receive とローカルにインストールされた Jenkins を使用してビルド プロセスを開始することです。リモートの場合は、URL を指定して wget または curl を使用する必要があります。参考までに、これはGit ブランチ モデルです。
# This must be read using read because the values are passed on
# STDIN not as command-line arguments.
read OLDREV NEWREV REFNAME
BRANCH=${REFNAME#refs/heads/}
. /usr/share/doc/git-core/contrib/hooks/post-receive-email
if [ ${BRANCH} == "master" ]; then
/usr/local/bin/jenkins-start "Our Project - Android - Releases"
elif [ ${BRANCH} == "develop" ]; then
/usr/local/bin/jenkins-start "Our Project - Android - Development"
fi
開発側は基本的にリリースと同じですが、マスターの代わりに開発ブランチへのコミットに基づいてビルドします。このサーバーは git と Jenkins のみをホストし、Eclipse と Xcode 環境はビルド サーバーとして使用する Mac Mini にインストールされているため、Jenkins はログイン用の証明書で SSH を使用するように構成されています。Jenkins サーバーはビルド サーバーに SSH 接続し、コードをチェックアウトしてコードをビルドし、その結果をソフトウェア シェルフに SSH 接続します。唯一の特別な部分は、これを機能させる Ant build.xml 部分です。
ビルド - シェルの実行 - コマンドの下に置く
~/android-sdks/tools/android update project -p "$WORKSPACE/OurProject"
Invoke Ant の下
-buildfile "$WORKSPACE/OurProject/build.xml" clean debug
これは、バイナリに署名するためのキーストアに関する情報を配置する場所です。
key.store=ourProject.keystore
key.alias=release
key.store.password=aBigSecret
key.alias.password=aBigSecret
そのため、プロジェクト build.xml では、いくつかのターゲットをオーバーライドして、ファイル名に表示される git コミット ハッシュを取得します。たとえば、OurProject 1.0.0 (deadbeef)-release.apk です。これがビルドされた後、Jenkins はファイルをソフトウェア シェルフにコピーします。
<target name="-set-debug-files" depends="-set-mode-check">
<exec executable="git" outputproperty="git.revision" failifexecutionfails="false" errorproperty="">
<arg value="rev-parse"/>
<arg value="--short"/>
<arg value="HEAD"/>
</exec>
<xpath input="AndroidManifest.xml"
expression="/manifest/@android:versionName"
output="android.app.version.name"
default="Unknown" />
<property name="out.packaged.file" location="${out.absolute.dir}/${ant.project.name}-debug-unaligned.apk" />
<property name="out.final.file" location="${out.absolute.dir}/${ant.project.name}-${android.app.version.name} (${git.revision})-debug.apk" />
<property name="build.is.mode.set" value="true" />
</target>
<target name="-set-release-mode" depends="-set-mode-check">
<exec executable="git" outputproperty="git.revision" failifexecutionfails="false" errorproperty="">
<arg value="rev-parse"/>
<arg value="--short"/>
<arg value="HEAD"/>
</exec>
<xpath input="AndroidManifest.xml"
expression="/manifest/@android:versionName"
output="android.app.version.name"
default="Unknown" />
<property name="out.packaged.file" location="${out.absolute.dir}/${ant.project.name}-release-unsigned.apk" />
<property name="out.final.file" location="${out.absolute.dir}/${ant.project.name}-${android.app.version.name} (${git.revision})-release.apk" />
<property name="build.is.mode.set" value="true" />
<!-- record the current build target -->
<property name="build.target" value="release" />
<property name="build.is.instrumented" value="false" />
<!-- release mode is only valid if the manifest does not explicitly
set debuggable to true. default is false. -->
<xpath input="AndroidManifest.xml" expression="/manifest/application/@android:debuggable"
output="build.is.packaging.debug" default="false"/>
<!-- signing mode: release -->
<property name="build.is.signing.debug" value="false" />
<!-- Renderscript optimization level: aggressive -->
<property name="renderscript.opt.level" value="${renderscript.release.opt.level}" />
<if condition="${build.is.packaging.debug}">
<then>
<echo>*************************************************</echo>
<echo>**** Android Manifest has debuggable=true ****</echo>
<echo>**** Doing DEBUG packaging with RELEASE keys ****</echo>
<echo>*************************************************</echo>
</then>
<else>
<!-- property only set in release mode.
Useful for if/unless attributes in target node
when using Ant before 1.8 -->
<property name="build.is.mode.release" value="true"/>
</else>
</if>
</target>
これは、PHP スクリプトがビルドを日付順に表示する、公的にアクセス可能な Web ページです。
<?php
require('header.html');
?>
<h2>All builds</h2>
<table>
<?php
$dir = dirname($_SERVER[SCRIPT_FILENAME]);
$filenames = scandir($dir);
$files = array();
$fileTimes = array();
$j = 0;
$n = count($filenames);
for ($i = 0; $i < $n; $i++) {
$filename = $filenames[$i];
if ( is_file($filename) && pathinfo($filename, PATHINFO_EXTENSION) == "apk" ) {
$time = filemtime($filename);
$files[$j] = array("name"=>$filename, "time"=>$time );
$fileTimes[$j] = $time;
$j++;
}
}
array_multisort($fileTimes, SORT_DESC, $files);
$tablerow_classes = array("t0", "t1");
$current_class = 0;
$m = count($files);
for ( $i = 0; $i < $m; $i++ ) {
$name = $files[$i]["name"];
$time = date ("d/m/Y H:i:s", $files[$i]["time"]);
$class = $tablerow_classes[$current_class];
$current_class++;
if ( $current_class > 1 ) {
$current_class = 0;
}
echo "<tr class=\"$class\"><td><a href=\"$name\">$name</a></td><td>$time<br /></tr>";
}
?>
</table>
<?php
require('footer.html');
要約すると、このシステムは完全なビルド システムを提供し、特定のバイナリを特定のコミットまで追跡できます。