gitタグ、ブランチ、コミット名を使用したGradleでのビルドアーティファクトのバージョン管理

SVNからGITおよびgitlabへの移行(さらにJenkinsからGitlab-CIへの移行、およびその使用についても説明します)に伴い、アプリケーションアセンブリの結果のアーティファクトをバージョン管理するという疑問が生じました。



SVNには、すべての人にとっておなじみのリビジョン番号があり、コミットごとに単調に増加していました。 バージョン番号を追加すると便利で、これによりほとんどの問題が解決しました。 しかし、gitは確かに多くの利点を提供し、経営陣とチーム全体にプロジェクトを転送するよう説得する価値がありました...

しかし、結果のアセンブリ成果物をバージョン管理するプロセスを再構築する必要がありました。



その結果、非常に優れたGradleプラグインgithub.com/nemerosa/versioningで停止し、その使用についてお話します。





問題



このアプリケーションでは、Gradleは長い間使用されており、SVNでは、build.gradleファイルに直接書き込まれた継承されたレガシー関数を使用しました。 幸いなことに、Gradleのその他の利点の中でも、これは素晴らしいGroovy言語であり、ビルドのロジックを書くことを制限するものではありません。Javaの世界から必要なライブラリを接続し、少なくとも1つのファイル全体でアプリケーションを書き換えてください!



しかし、このアプローチの有害性を理解していますか? バージョン番号を取得するロジックに5〜10行以上かかる場合、また何らかの理由で松葉杖を置くと、すぐにそれを維持することができなくなります...



手動解析のこのような「ソリューション」は、たとえば、 クリーンシステムでUIのない​​AndroidJenkinsの記事や、 git describeを手動で呼び出して正規表現で出力を解析することが提案されているアセンブリへの苦労を通して見ることができます...



もっとシンプルで信頼性が高く、最初は機能するものが欲しかった。



ワークフローとウィッシュリスト



このアプリケーションでは、いくつかのjarファイル、3つの戦争アーティファクト、それらを含む3つのRPMが収集され、Dockerの最後に、RPMがインストールされたアプリケーションのイメージが自動テスト後にすぐにgitlab-ciにプライベートリポジトリに送信されます。



一般的に、git / gitlabへの移行では、標準のgithubフローから継承されたロジックにわずかな変更を加えて、バージョン管理を意味します。





提案されたソリューション:Gradleプラグインnet.nemerosa:バージョン管理



gradleの利用可能なプラグインを見て回ると、ここにそのような素晴らしいオプションが見つかりました: github.com/nemerosa/versioning



そのドキュメントはすぐに魅了されます。すべてがシンプルで、論理的であり、実行された内容を理解できます。

さらに、リリースのセマンティック分離、機能



ビジネスで試してみましょう



そのため、プロジェクトへの接続は非常に簡単です。指示に従ってください。

plugins { id 'net.nemerosa.versioning' version '2.4.0' }
      
      







それだけです。ほとんどの場合、ビルドスクリプトで必要な場所でバージョンを使用することは既に可能です。

 version = versioning.info.full
      
      







さて、またはポイントに近い、戦争アーティファクトの名前で言ってみましょう:

 war { archiveName = "portal-api##${versioning.info.full}.war" }
      
      







feature-1ブランチからアセンブルした後、おおよそ次の命名規則を持つファイルを取得します: portal-api ## feature-1.3e46dc.war (この例ではTomcatスタイルの命名法を使用しています )。 より興味深い状況の値を設定および解析するためのオプションについては、後で説明します。



2つのタスクがすぐに利用できます。

versionDisplay-情報とバージョンを表示し、コンソールに表示します。 デバッグとversionFileは非常に便利です。外部のbashスクリプトにインポートするための既製の変数を含むbuild / version.propertiesファイルを作成します。



 > ./gradlew versionDisplay :versionDisplay [version] scm = git [version] branch = release/0.3 [version] branchType = release [version] branchId = release-0.3 [version] commit = da50c50567073d3d3a7756829926a9590f2644c6 [version] full = release-0.3-da50c50 [version] base = 0.3 [version] build = da50c50 [version] display = 0.3.0
      
      







 > ./gradlew versionFile > cat build/version.properties VERSION_BUILD=da50c50 VERSION_BRANCH=release/0.3 VERSION_BASE=0.3 VERSION_BRANCHID=release-0.3 VERSION_BRANCHTYPE=release VERSION_COMMIT=da50c50567073d3d3a7756829926a9590f2644c6 VERSION_DISPLAY=0.3.0 VERSION_FULL=release-0.3-da50c50 VERSION_SCM=git
      
      







結構です



カスタム解析ロジック



名前の解析、接頭辞、接尾辞の処理、バージョンの解釈には多くのオプションがあります。 ちなみにSVNのサポートもあります。 一般的に、 カスタマイズセクションにいます。



ただし、軟膏にはハエはありません 。 私がそれを使い始めたとき、ドキュメントは異なって見えました

はい、ブランチ名の解釈方法にクロージャを設定できます(たとえば、「リリース/ 1」をリリース、それ以外の場合は「qa / 0.1」を検討してください)。

 versioning { branchParser = { String branch, String separator = '/' -> int pos = branch.indexOf(separator) if (pos > 0) { new BranchInfo( type: branch.substring(0, pos), base: branch.substring(pos + 1)) } else { new BranchInfo(type: branch, base: '') } } }
      
      







これはすべて素晴らしいですが、ブランチがある場合はタグが必要です!?

私はこの考えをあきらめたくありませんでした。 もちろん、一時的な回避策をカットしましたが、著者は解析ロジックをより一般的にするためのリクエストを作成しました: github.com/nemerosa/versioning/issues/32



このプラグインの作成者であるDamien Coraboeufは非常に反応が良く、いくつかの小さな問題を素早く修正しました。

一般的に、よくあることですが、彼は私が私が提供していることを実現することを提案しました。

私は彼のアドバイスに従いました-すぐにプルリクエストを打ちました。



現在、採用後、SCMコミット情報オブジェクト(SVNまたはGIT)を取得し、バージョンを作成する方法を自由に選択できます。 たとえば、上記と同じコードを次のように実装できます。

 versioning { releaseParser = { scmInfo, separator = '/' -> List<String> part = scmInfo.tag.split(separator) + '' new net.nemerosa.versioning.ReleaseInfo(type: part[0], base: part[1]) } }
      
      







完全な閉鎖でも同じこと。



これにより何が得られますか? たとえば、要件で説明したように、ブランチ名を1つのケースで、タグ名を別のケースで使用するためにこれを使用します。ブランチ名の文字列表現だけに限定されません。 私たちにとって、これは次のようになります。

 versioning{ full = { scmInfo -> // Tag name, or '_branch_name_' if it is not 'master' (scmInfo.tag ?: ( 'master' == scmInfo.branch ? '' : "_${scmInfo.branch}_." ) + scmInfo.abbreviated).toLowerCase().replaceAll(/[^a-z0-9-_\.]/, '_') } }
      
      





小文字は、Dockerイメージタグで使用されます。



前述したように、オプションはこれに限定されず、ダーティサフィックスも制御し、Groovyメタマジックを使用して同じオブジェクトにビルド時間を追加します...



CIとの統合



さて、便利な統合について話し始めたので、私はすぐに1つの落とし穴に注意を払う必要があります。 そして、このプラグインはすでに世話されています!



指定されたコードは正常に機能し、テストされ、コミットされました。 しかし、CIの最初のプッシュとビルドは奇妙な結果をもたらしました-ブランチの名前はHEADのようなものでした。



実際、その理由は簡単です。ビルダーが行うことを見ると、彼はブランチではなく特定のコミットを収集します。 アセンブリの時点で、同じブランチにすでに他のメンバーがいる可能性があります。 したがって、コミットハッシュという名前のチェックアウトが常に行われます。 したがって、gitリポジトリは分離ヘッド状態になります。



先に言ったように、この状況は普通でほとんどの場合このように機能しますが、このプラグインでは、実際のブランチ名を取得する必要がある外部変数の名前を示す1行を記述するだけで、gitlab-ciが必要になります追加:

 branchEnv = ['CI_BUILD_REF_NAME']
      
      







Jenkinsでは、 JENKINS-30252のリクエストにより、このような変数もかなり前に追加されました。 したがって、両方のシステムを一度にサポートしたい場合は、次のように書くことができます。

 branchEnv = ['CI_BUILD_REF_NAME', 'GIT_LOCAL_BRANCH']
      
      







gradleのバージョンを使用する方が便利であることを願っています。 はい、すべての点で著者にバグを投稿するか、リクエストを書くことをお勧めします。著者はバグに非常に迅速に対応します。 良いコーディング!



All Articles