mike-neckのブログ

Java or Groovy or Swift or Golang

pixela-java-client の CI(circle-ci) を1日1回まわすための lambda 作った

以前書いたとおり、CI でライブラリーのアップデートをslack に送るようにしてみました。

mike-neck.hatenadiary.com

しかし、特に開発することがなくなったりすると依存ライブラリーのアップデートにも気づけなくなるので、1日1回 CI (circle-ci) をまわすために、lambda 関数を作ってみた。

f:id:mike_neck:20190318001112p:plain
起動イメージ

コードはこんな感じ

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "github.com/aws/aws-lambda-go/lambda"
    "github.com/pkg/errors"
    "io/ioutil"
    "log"
    "net/http"
    "os"
)

func main() {
    debug := os.Getenv("DEBUG_APP")
    if debug != "" {
        log.Println("running debug mode")
        err := callCircleCi()
        if err != nil {
            log.Fatalln("exit by", err)
        }
    } else {
        log.Println("running application mode")
        lambda.Start(callCircleCi)
    }
}

func callCircleCi() error {
    token := os.Getenv("CIRCLE_CI_TOKEN")
    if token == "" {
        log.Println("error no token(CIRCLE_CI_TOKEN) available")
        return errors.New("no token(CIRCLE_CI_TOKEN) available")
    }
    buildUrl := os.Getenv("CIRCLE_CI_URL")
    if buildUrl == "" {
        log.Println("error no url(CIRCLE_CI_URL) available")
        return errors.New("error no url(CIRCLE_CI_URL) available")
    }
    circleCiUrl := fmt.Sprintf("%s?circle-token=%s", buildUrl, token)

    buildRequest := CircleCiBuildRequest{"master"}
    jsonBytes, err := json.Marshal(&buildRequest)
    if err != nil {
        log.Printf("error marshal json %v, detail: %v\n", buildRequest, err)
        return errors.Wrapf(err, "marshal object %s", buildRequest)
    }

    body := bytes.NewReader(jsonBytes)
    request, err := http.NewRequest(http.MethodPost, circleCiUrl, body)
    if err != nil {
        log.Printf("error creating new request, detail: %v\n", err)
        return errors.Wrap(err, "error creating new request")
    }
    request.Header.Add("content-type", "application/json")
    request.Header.Add("accept", "application/json")

    client := http.DefaultClient
    response, err := client.Do(request)
    if err != nil {
        log.Printf("error request to circle-ci, detail: %v\n", err)
        return errors.Wrap(err, "error request to circle-ci")
    }

    respBody, err := ioutil.ReadAll(response.Body)
    if err != nil {
        log.Printf("error read body, status: %d", response.StatusCode)
    }

    if response.StatusCode != 200 {
        responseBody := string(respBody)
        log.Printf("error response %d, %s, body: %s", response.StatusCode, response.Status, responseBody)
        return errors.New(fmt.Sprintf("error response %d, body; %s", response.StatusCode, responseBody))
    }

    var circleCiResponse CircleCiResponse
    err = json.Unmarshal(respBody, &circleCiResponse)
    if err != nil {
        responseBody := string(respBody)
        log.Printf("error unmarshal json: %s, detail: %v", responseBody, err)
        return errors.Wrapf(err, "error unmarshal json: %s", responseBody)
    }

    log.Printf("success: %v", circleCiResponse)
    return nil
}

type CircleCiBuildRequest struct {
    Branch string `json:"branch"`
}

type CircleCiResponse struct {
    Status int    `json:"status"`
    Body   string `json:"body"`
}

で、 sam テンプレートはこんな感じ

AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: "circle-ci-caller function"

Resources:
  CircleCiCallerFunction:
    Type: AWS::Serverless::Function
    Properties:
      Description: "Call Circle CI Build"
      CodeUri: build/linux/
      Handler: app
      Runtime: go1.x
      Tracing: Active
      Events:
        CircleCiCallerFunction:
          Type: Schedule
          Properties:
            Schedule: "rate(1 day)"

Outputs:
  CreatedFunction:
    Description: "Created function"
    Value: !GetAtt CircleCiCallerFunction.Arn

結果

アップデートせえよって怒られが発生した

f:id:mike_neck:20190318001648p:plain

結果2

pixela に色が毎日つくかも…(図は3/17のショートモード)

https://pixe.la/v1/users/pixela-java-client/graphs/run-ci?mode=short&date=20190317