[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
Google の API Client Library for Java | Google Developers を眺めながら maven で google-api-client 1.30.5 をぶち込み以下のソースコードを書いたらなんか上手くいかなかった。
/** Authorizes the installed application to access user's protected data. */
private static Credential authorize() throws Exception {
// load client secrets
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY,
new InputStreamReader(CalendarSample.class.getResourceAsStream("/client_secrets.json")));
// set up authorization code flow
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
httpTransport, JSON_FACTORY, clientSecrets,
Collections.singleton(CalendarScopes.CALENDAR)).setDataStoreFactory(dataStoreFactory)
.build();
// authorize
return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");
}
AuthorizationCodeInstalledAppが未定義だと言われるのだ。実はこのクラス、google-oauth-client から 1.30.1 を最後に消されている、のか?(根拠:javadoc になんかそんな感じの事が書かれている)
しかし、こちら以下を pom.xml に明記したら解決された。
<dependency> <groupId>com.google.oauth-client</groupId> <artifactId>google-oauth-client-java6</artifactId> <version>1.30.5</version> </dependency>
こういう関連するライブラリについては Setup Instructions | OAuth Client Library for Java | Google Developers に色々書かれている。また、「java6 って書いてあるけど大丈夫なのかよ」と思うが Java 6 (and higher) extensions to the Google OAuth Client Library for Java (google-oauth-client-java6) support Java6+ applications. This module depends on google-oauth-client.
(Java 6 以降 向けの Google OAuth Client Library の拡張です。google-oauth-client に依存しています)らしいので大丈夫。
Jenkins の groovy pipeline で書いたもの。
approvalResult = input(
id: "myInput",
message: "承認しますか?",
parameters: [
string( name: 'comment', defaultValue: '承認します')
],
submitterParameter : "approver"
)
wrap([$class: 'BuildUser']) {
if( approvalResult.approver.equals(BUILD_USER_ID) ) {
error "承認者と作業者が同じ人です!!";
} else {
echo approvalResult.comment;
}
}
一人で何でもできる状況でお仕事とか管理をしたりするとスムーズに事が進んで大変に楽なのだが「それやっちゃまずくね?」を止める人がいない。お仕事や管理の内容によっては不正やよろしくない判断をだれも止めることができない、ということになる。
それを防ぐために不正やよろしくない判断に基づく可能性のある作業に対しては作業者じゃない誰かが確認するプロセスを踏んだ方がよい、とされる。上述のソースコードはこの確認するプロセスを実現している。
Jenkins の groovy pipeline の Input Step と BuildUser を使っている。
input を使うとビルドの最中にユーザの入力を受け付けることが可能となる。これを使ってビルドの途中で「承認しますか?」を確認する。承認時にはしばしば承認の根拠になる資料を添付したくなるのでそういう URL を添付しやすいようにコメントを書き込めるようにしてある。他にも様々な値を与えることが可能である。しかし、最も重要なのは submitterParameter だろう。これに指定した値を key とする value に承認者のユーザ ID が代入される。上述の例だと approvalResult.approver に承認者のユーザ ID が格納される。
しかし、この承認が作業者自身によるものだったらダブルチェックになっていない。別人が確認していることを確認するために作業者のユーザ ID が格納される BUILD_USER_ID と approvalResult.approver を比較し、双方が異なる値を持つことを確認している。
input の submitter パラメータを設定することでそもそも input に入力できる人を制限できる。これを用いれば BuildUser のチェックを省略したり、より高度な確認プロセスを作れるかもしれない。ただし、承認できる人の全リストのメンテナンスをしないといけなくなるので、若干面倒。そこのメンテナンス方法を考えていないと徐々に面倒になってくるはず。
Jenkins に Rebuild Plugin を入れておけば1回だか2回だがクリックするだけでリビルドができる。色々あって今やっているビルドがリビルドなのか否かを判定したくなった。
リビルドの際には Build Cause に com.sonyericsson.rebuild.RebuildCause が入る。なので、groovy ならば currentBuild.rawBuild.getCause(com.sonyericsson.rebuild.RebuildCause) すればよいのでは、と考える。これの結果が null でないならばリビルドだろう、と。しかし、この方法だと null が返ってくる。何故なのかはまだちゃんと調べていない……今ググってみたらそれで取れているケースもあるし、何か根本的に私が勘違いしている?
私はジョブの情報を API で取得し、そこに com.sonyericsson.rebuild.RebuildCause があるのかを検索する、という方法を採った。すなわち、BUILD_URL + "api/json" を curl 等で取得し、この中身を検索するのである。なんか getCause でやれない人が迂回するのに使えるかもしれない。
さておき、 getCause でやれているという話があるのでやれない理由を調べないとな―……
タイトルの通り。私の場合は Jenkins でかなりの量の引数をつっこんだら java.io.IOException: error=7, Argument list too long と怒られた。原因はまんまで「bash のコマンドに与える引数が長すぎるよ」である。解決のためには引数を短くしたり、引数を別のリストとして与える等する必要がある。
どれだけの量の引数を与えられるのかはコマンドを実行させるサーバ上で getconf ARG_MAX を実行すればわかる。
Webhock だけでもアレなので Bot に発言をさせてみようとする。Slack Bot の token は次のような形式である。
xoxb-000000000000-000000000000-17afdxySLsIgJkUMu0eJHGMq
Bot は Slack api の Your Apps のページから作る。Add features and functionality から Bots を設定し、 OAuth & Permissions から token を取得する。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
public class SlackTokenNotificationClient {
private final String token;
private final String userName;
public SlackTokenNotificationClient (String token, String userName) {
this.token = token;
this.userName = userName;
}
public void sendNotify(String message, String channelName) throws IOException {
HttpURLConnection con = null;
try {
String baseUrl = String.format("https://slack.com/api/chat.postMessage?token=%s&channel=%s&text=%s&username=%s",
token,
channelName,
URLEncoder.encode(message.replaceAll(" ", "%20"), "UTF-8").replaceAll("%2520", "%20").replaceAll("%7E", "~"),
URLEncoder.encode(userName.replaceAll(" ", "%20"), "UTF-8").replaceAll("%2520", "%20").replaceAll("%7E", "~")
);
URL url = new URL(baseUrl);
con = (HttpURLConnection) url.openConnection();
con.setDoOutput(true);
con.setRequestMethod("GET");
con.getOutputStream();
if(con.getResponseCode() != HttpURLConnection.HTTP_OK) {
StringBuilder sb = new StringBuilder();
try(InputStream is = con.getInputStream()) {
String encoding = con.getContentEncoding();
if( encoding == null ) {
encoding = "UTF-8";
}
try( InputStreamReader isReader = new InputStreamReader(is, encoding);
BufferedReader bufReader = new BufferedReader(isReader); ) {
String line = null;
while((line = bufReader.readLine()) != null) {
sb.append(line);
}
}
}
throw new IOException("Failed to access :" + con.getResponseCode() + " / Result: " + sb.toString());
}
} catch (IOException ioe) {
throw ioe;
}
}
}
SlackTokenNotificationClient client = new SlackTokenNotificationClient (
// 上述の手順で取得した token
"xoxb-000000000000-000000000000-17afdxySLsIgJkUMu0eJHGMq",
// 発言する名前
"My Notification Bot" );
// 第二引数は発言するチャネル
client.sendNotify("発言だよー発言だよー", "notification");