GitHubにGradleでリリース作業する。

タグをpushしてダウンロードAPI叩くだけなんですけども。

パスフレーズ付のSSH鍵を使っていると良い感じにハマるのでメモしておきます。

  • 今回のスクリプトを実行する為の依存関係とかそういうの
import org.eclipse.egit.github.core.*
import org.eclipse.egit.github.core.client.*
import org.eclipse.egit.github.core.service.*

import org.eclipse.jgit.api.*
import org.eclipse.jgit.lib.*
import org.eclipse.jgit.transport.*
import org.eclipse.jgit.errors.*

apply plugin: 'java'
apply plugin: 'war'

buildscript {
	repositories {
		mavenCentral()
		mavenRepo(url: 'http://download.eclipse.org/jgit/maven')
		flatDir { dirs 'lib' }
	}
	dependencies {
		classpath 'org.eclipse.jgit:org.eclipse.jgit:1.+'
		classpath 'org.eclipse.mylyn.github:org.eclipse.egit.github.core:1.+'
	}
}

タグを打ってpushするコード。

class PassphraseProvider extends CredentialsProvider {
	def passphrase = ""
	PassphraseProvider() {
		def pass = System.console().readPassword("\nenter ssh passphrase: ")
		this.passphrase = "$pass"
	}
	def boolean isInteractive() {
		false
	}
	def boolean supports(CredentialItem... items) {
		true
	}
	def boolean get(URIish uri, CredentialItem... items) {
		items.each {
			if(it instanceof CredentialItem.StringType) {
				it.value = passphrase
				return true
			} else {
				throw new UnsupportedCredentialItem(uri, it.promptText);
			}
		}
	}
}

task tag << {
	def g = Git.open file('.git')
	def tag = null
	try {
		def n = "$version-$war.classifier"
		tag = g.tag() setName n setMessage "release $n" call()
		g.push().setPushTags().setCredentialsProvider new PassphraseProvider() setProgressMonitor new TextProgressMonitor() call()
	} catch(e) {
		g.tagDelete().setTags(tag?.tagName).call()
		throw e
	} finally {
		g.repository.close()
	}
}

pushでコケたら使ったタグを消さないと、パスフレーズのエントリに失敗するたんびに謎のタグがガシガシ出来てしまうからでつ。

PassphraseProviderなんてクラスを実装しとりますが、これはJGitの実装を誤魔化す為にやっとります。

  • org.eclipse.jgit.transport.JschConfigSessionFactory.createSession(CredentialsProvider, FS, String, String, String, int, Host)
private Session createSession(CredentialsProvider credentialsProvider,
		FS fs, String user, final String pass, String host, int port,
		final OpenSshConfig.Host hc) throws JSchException {
	final Session session = createSession(hc, user, host, port, fs);
	if (pass != null)
		session.setPassword(pass);
	final String strictHostKeyCheckingPolicy = hc
			.getStrictHostKeyChecking();
	if (strictHostKeyCheckingPolicy != null)
		session.setConfig("StrictHostKeyChecking",
				strictHostKeyCheckingPolicy);
	final String pauth = hc.getPreferredAuthentications();
	if (pauth != null)
		session.setConfig("PreferredAuthentications", pauth);
	if (credentialsProvider != null
			&& (!hc.isBatchMode() || !credentialsProvider.isInteractive())) {
		session.setUserInfo(new CredentialsProviderUserInfo(session,
				credentialsProvider));
	}
	configure(hc, session);
	return session;
}

バッチモードだとしても、インタラクティブ性があって良い様な気がしないでもないけど、良く分からない。
自動的な作業はパスフレーズの無いSSH鍵を使えってのは、何か良く聞く気がしないでもない。


次に、GitHubAPIのJava実装を使って、各リポジトリにあるダウンロードタブからアーカイブをダウンロード出来る様にしるます。

task uploadArchives(overwrite: true, dependsOn: war) << {
	def client = new GitHubClient()
	client.setCredentials(github_username, github_password)
	def repoid = RepositoryId.create('username', 'reponame')
	def dls = new DownloadService(client)
	def d = new Download()
	d.name = war.archiveName
	dls.createDownload(repoid, d, war.archivePath)
}

このコードではwarタスクで作ったアーカイブをアップロードしているます。
repoidの辺りにはテキトーにユーザ名とリポジトリ名を埋めてクダサシ。
アクセスに必要なユーザIDとパスワードは、gradle.propertiesの中に書いてリポジトリには共有しない様にしてあるます。

github_username=oreore
github_password=KaA30re0re

最後にリリース用のタスクを定義しる。

task release(dependsOn:[build, tag, uploadArchives]) << { println "release fishined !!" }

最近、そろそろgradleのGitプラグインがあっても良いんじゃないかと思い始めているのだけど、
僕が見つけられてないだけで存在しているのかな?