From 41111b218ce18c16ffe1808abe42b980b606be0a Mon Sep 17 00:00:00 2001 From: motoki317 Date: Wed, 3 May 2023 20:45:55 +0900 Subject: [PATCH 01/11] use ws bot --- bot.go | 148 +++++-------------- command.go | 12 +- config.go | 6 +- exec-log.go | 42 ++---- go.mod | 13 +- go.sum | 414 ++++++++++++++++++++++++++++++++++++++++++++++------ main.go | 48 +++--- utils.go | 85 ++--------- 8 files changed, 471 insertions(+), 297 deletions(-) diff --git a/bot.go b/bot.go index 6ecdf44..d057012 100644 --- a/bot.go +++ b/bot.go @@ -1,154 +1,80 @@ package main import ( - "errors" + "context" "fmt" - "github.com/dghubble/sling" - "github.com/go-chi/render" + "github.com/kballard/go-shellquote" + "github.com/traPtitech/go-traq" + "github.com/traPtitech/traq-ws-bot/payload" "go.uber.org/zap" - "net/http" - "time" ) -var traQClient *sling.Sling - type Map map[string]interface{} -// MessageCreatedPayload MESSAGE_CREATEDイベントペイロード -type MessageCreatedPayload struct { - EventTime time.Time `json:"eventTime"` - Message struct { - ID string `json:"id"` - User struct { - ID string `json:"id"` - Name string `json:"name"` - Bot bool `json:"bot"` - } `json:"user"` - ChannelID string `json:"channelId"` - Text string `json:"text"` - PlainText string `json:"plainText"` - CreatedAt string `json:"createdAt"` - } `json:"message"` -} - -// BotEndPoint Botサーバーエンドポイント -func BotEndPoint(w http.ResponseWriter, r *http.Request) { - // トークン検証 - if r.Header.Get("X-TRAQ-BOT-TOKEN") != config.VerificationToken { - http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) - return - } - - switch r.Header.Get("X-TRAQ-BOT-EVENT") { - case "PING", "JOINED", "LEFT": - w.WriteHeader(http.StatusNoContent) - case "MESSAGE_CREATED": - var payload MessageCreatedPayload - if err := render.Decode(r, &payload); err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - go BotMessageReceived(payload) - w.WriteHeader(http.StatusNoContent) - default: - http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) - } -} - // BotMessageReceived BOTのMESSAGE_CREATEDイベントハンドラ -func BotMessageReceived(p MessageCreatedPayload) { +func BotMessageReceived(p *payload.MessageCreated) { + ctx := context.Background() + if p.Message.ChannelID != config.DevOpsChannelID { return // DevOpsチャンネル以外からのメッセージは無視 } args, err := shellquote.Split(p.Message.PlainText) if err != nil { - _ = SendTRAQMessage(p.Message.ChannelID, fmt.Sprintf("invalid syntax error\n%s", cite(p.Message.ID))) - _ = PushTRAQStamp(p.Message.ID, config.Stamps.BadCommand) + _ = SendTRAQMessage(ctx, p.Message.ChannelID, fmt.Sprintf("invalid syntax error\n%s", cite(p.Message.ID))) + _ = PushTRAQStamp(ctx, p.Message.ID, config.Stamps.BadCommand) return } if len(args[0]) == 0 { return // 空メッセージは無視 } - ctx := &Context{ - P: &p, - Args: args, + cmdCtx := &Context{ + Context: ctx, + P: p, + Args: args, } c, ok := commands[args[0]] if !ok { // コマンドが見つからない - _ = ctx.ReplyBad(fmt.Sprintf("Unknown command: `%s`", args[0])) + _ = cmdCtx.ReplyBad(fmt.Sprintf("Unknown command: `%s`", args[0])) return } - err = c.Execute(ctx) + err = c.Execute(cmdCtx) if err != nil { - ctx.L().Error("failed to execute command", zap.Error(err)) + cmdCtx.L().Error("failed to execute command", zap.Error(err)) } } // SendTRAQMessage traQにメッセージ送信 -func SendTRAQMessage(channelID string, text string) error { - req, err := traQClient.New(). - Post(fmt.Sprintf("api/v3/channels/%s/messages", channelID)). - BodyJSON(Map{"content": text}). - Request() - if err != nil { - return err - } - - res, err := http.DefaultClient.Do(req) - if err != nil { - return err - } - defer res.Body.Close() - if res.StatusCode != http.StatusCreated { - return errors.New(res.Status) - } - return nil +func SendTRAQMessage(ctx context.Context, channelID string, text string) error { + _, _, err := bot.API(). + ChannelApi. + PostMessage(ctx, channelID). + PostMessageRequest(traq.PostMessageRequest{Content: text}). + Execute() + return err } // SendTRAQDirectMessage traQにダイレクトメッセージ送信 -func SendTRAQDirectMessage(userID string, text string) error { - req, err := traQClient.New(). - Post(fmt.Sprintf("api/v3/users/%s/messages", userID)). - BodyJSON(Map{"content": text}). - Request() - if err != nil { - return err - } - - res, err := http.DefaultClient.Do(req) - if err != nil { - return err - } - defer res.Body.Close() - if res.StatusCode != http.StatusCreated { - return errors.New(res.Status) - } - return nil +func SendTRAQDirectMessage(ctx context.Context, userID string, text string) error { + _, _, err := bot.API(). + UserApi. + PostDirectMessage(ctx, userID). + PostMessageRequest(traq.PostMessageRequest{Content: text}). + Execute() + return err } // PushTRAQStamp traQのメッセージにスタンプを押す -func PushTRAQStamp(messageID, stampID string) error { - req, err := traQClient.New(). - Post(fmt.Sprintf("api/v3/messages/%s/stamps/%s", messageID, stampID)). - BodyJSON(Map{"count": 1}). - Request() - if err != nil { - return err - } - - res, err := http.DefaultClient.Do(req) - if err != nil { - return err - } - defer res.Body.Close() - if res.StatusCode != http.StatusNoContent { - return errors.New(res.Status) - } - return nil +func PushTRAQStamp(ctx context.Context, messageID, stampID string) error { + _, err := bot.API(). + MessageApi. + AddMessageStamp(ctx, messageID, stampID). + PostMessageStampRequest(traq.PostMessageStampRequest{Count: 1}). + Execute() + return err } // cite traQのメッセージ引用形式を作る diff --git a/command.go b/command.go index 79893f3..7228f53 100644 --- a/command.go +++ b/command.go @@ -1,6 +1,9 @@ package main import ( + "context" + + "github.com/traPtitech/traq-ws-bot/payload" "go.uber.org/zap" ) @@ -14,8 +17,9 @@ type Command interface { // Context コマンド実行コンテキスト type Context struct { + context.Context // P BOTが受信したMESSAGE_CREATEDイベントの生のペイロード - P *MessageCreatedPayload + P *payload.MessageCreated // Args 投稿メッセージを空白区切りで分けたもの Args []string } @@ -28,13 +32,13 @@ func (ctx *Context) GetExecutor() string { // ReplyViaDM コマンドメッセージに返信します func (ctx *Context) Reply(message, stamp string) (err error) { if len(message) > 0 { - err = SendTRAQMessage(ctx.P.Message.ChannelID, message) + err = SendTRAQMessage(ctx, ctx.P.Message.ChannelID, message) if err != nil { return } } if len(stamp) > 0 { - err = PushTRAQStamp(ctx.P.Message.ID, stamp) + err = PushTRAQStamp(ctx, ctx.P.Message.ID, stamp) if err != nil { return } @@ -44,7 +48,7 @@ func (ctx *Context) Reply(message, stamp string) (err error) { // ReplyViaDM コマンド実行者にDMで返信します func (ctx *Context) ReplyViaDM(message string) error { - return SendTRAQDirectMessage(ctx.P.Message.User.ID, message) + return SendTRAQDirectMessage(ctx, ctx.P.Message.User.ID, message) } // ReplyBad コマンドメッセージにBadスタンプをつけて返信します diff --git a/config.go b/config.go index 3f2042c..159b68b 100644 --- a/config.go +++ b/config.go @@ -1,16 +1,14 @@ package main import ( - "gopkg.in/yaml.v2" "os" + + "gopkg.in/yaml.v2" ) type Config struct { - BindAddr string `yaml:"bindAddr"` TraqOrigin string `yaml:"traqOrigin"` - DevOpsBotOrigin string `yaml:"devOpsBotOrigin"` DevOpsChannelID string `yaml:"devOpsChannelId"` - VerificationToken string `yaml:"verificationToken"` BotAccessToken string `yaml:"botAccessToken"` ConohaIdentityApiOrigin string `yaml:"conohaIdentityApiOrigin"` ConohaComputeApiOrigin string `yaml:"conohaComputeApiOrigin"` diff --git a/exec-log.go b/exec-log.go index 6d2d7d0..4f9b715 100644 --- a/exec-log.go +++ b/exec-log.go @@ -2,11 +2,12 @@ package main import ( "fmt" - "github.com/go-chi/chi/v5" - "github.com/patrickmn/go-cache" - "net/http" + "io" + "os" "path/filepath" "strconv" + + "go.uber.org/zap" ) // ExecLogCommand `exec-log [service|server] [name] [command] [unix]` @@ -73,32 +74,17 @@ func (ec *ExecLogCommand) Execute(ctx *Context) error { return ctx.ReplyBad("Log not found") } - key := RandAlphaNumericString(30) - logAccessUrls.Set(key, logName, cache.DefaultExpiration) - _ = ctx.ReplyAccept() - - fileURL := fmt.Sprintf("%s/log/%s", config.DevOpsBotOrigin, key) - return ctx.ReplyViaDM(fmt.Sprintf("[View](%s) [Download](%s?dl=1)\n\nThese URL is valid for 3 minutes.", fileURL, fileURL)) -} - -func GetLog(w http.ResponseWriter, r *http.Request) { - key := chi.URLParam(r, "key") - if len(key) == 0 { - http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) - return - } - shouldDownloadFile := r.URL.Query().Get("dl") == "1" - - logName, ok := logAccessUrls.Get(key) - if !ok { - http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) - return + f, err := os.Open(logFilePath) + if err != nil { + ctx.L().Error("opening log file", zap.Error(err)) + return ctx.ReplyFailure("Error opening log file") } - - if shouldDownloadFile { - w.Header().Set("content-disposition", fmt.Sprintf("attachment; filename=\"%s\"", logName.(string))) + b, err := io.ReadAll(f) + if err != nil { + ctx.L().Error("reading log file", zap.Error(err)) + return ctx.ReplyFailure("Error reading log file") } - http.ServeFile(w, r, filepath.Join(config.LogsDir, logName.(string))) - return + _ = ctx.ReplyAccept() + return ctx.ReplyViaDM("```\n" + safeConvertString(b) + "\n```") } diff --git a/go.mod b/go.mod index d8a61a5..6faf42b 100644 --- a/go.mod +++ b/go.mod @@ -4,19 +4,24 @@ go 1.20 require ( github.com/dghubble/sling v1.4.1 - github.com/go-chi/chi/v5 v5.0.8 - github.com/go-chi/render v1.0.2 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 - github.com/patrickmn/go-cache v2.1.0+incompatible + github.com/traPtitech/go-traq v0.0.0-20220426061605-adc15dcfc6d0 + github.com/traPtitech/traq-ws-bot v1.1.2 go.uber.org/zap v1.24.0 golang.org/x/crypto v0.8.0 gopkg.in/yaml.v2 v2.4.0 ) require ( - github.com/ajg/form v1.5.1 // indirect + github.com/gofrs/uuid v4.2.0+incompatible // indirect + github.com/golang/protobuf v1.5.2 // indirect github.com/google/go-querystring v1.1.0 // indirect + github.com/gorilla/websocket v1.5.0 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.11.0 // indirect + golang.org/x/net v0.9.0 // indirect + golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect golang.org/x/sys v0.7.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/protobuf v1.28.0 // indirect ) diff --git a/go.sum b/go.sum index 5f21866..1a8f4b3 100644 --- a/go.sum +++ b/go.sum @@ -1,101 +1,425 @@ -github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= -github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dghubble/sling v1.4.0 h1:/n8MRosVTthvMbwlNZgLx579OGVjUOy3GNEv5BIqAWY= -github.com/dghubble/sling v1.4.0/go.mod h1:0r40aNsU9EdDUVBNhfCstAtFgutjgJGYbO1oNzkMoM8= github.com/dghubble/sling v1.4.1 h1:AxjTubpVyozMvbBCtXcsWEyGGgUZutC5YGrfxPNVOcQ= github.com/dghubble/sling v1.4.1/go.mod h1:QoMB1KL3GAo+7HsD8Itd6S+6tW91who8BGZzuLvpOyc= -github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8= -github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= -github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0= -github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= -github.com/go-chi/render v1.0.1 h1:4/5tis2cKaNdnv9zFLfXzcquC9HbeZgCnxGnKrltBS8= -github.com/go-chi/render v1.0.1/go.mod h1:pq4Rr7HbnsdaeHagklXub+p6Wd16Af5l9koip1OvJns= -github.com/go-chi/render v1.0.2 h1:4ER/udB0+fMWB2Jlf15RV3F4A2FDuYi/9f+lFttR/Lg= -github.com/go-chi/render v1.0.2/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0= -github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0= +github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= -github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= -go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/traPtitech/go-traq v0.0.0-20220426061605-adc15dcfc6d0 h1:OmzaVUbkE9bkPsRcVMdohAo6Jdr2zOrqw48QSrCk3Dc= +github.com/traPtitech/go-traq v0.0.0-20220426061605-adc15dcfc6d0/go.mod h1:p85KAwzfN5gbgsbQ//Ge1wMbdsy1v9TguH5TYt9TznI= +github.com/traPtitech/traq-ws-bot v1.1.2 h1:gBmSJ2B4lx/zAzL3aBxbe7jGEPVNhJviWVard40yU7s= +github.com/traPtitech/traq-ws-bot v1.1.2/go.mod h1:mnUHbZiFLydoUxS2q8kzR1E+1RMRXrmEpUdSAxh0jvo= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.1.11-0.20210813005559-691160354723 h1:sHOAIxRGBp443oHZIPB+HsUGaksVCXVQENPxwTfQdH4= -go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec= -go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= -go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M= -golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ= golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 h1:OSnWWcOd/CtWQC2cYSBgbTSJv3ciqd8r54ySIW2y3RE= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/main.go b/main.go index 36e96d3..e29b095 100644 --- a/main.go +++ b/main.go @@ -1,22 +1,19 @@ package main import ( + "context" "fmt" - "github.com/go-chi/chi/v5" - "github.com/go-chi/chi/v5/middleware" - "github.com/patrickmn/go-cache" - "net/http" - "time" - "github.com/dghubble/sling" + traqwsbot "github.com/traPtitech/traq-ws-bot" + "go.uber.org/zap" ) var ( - version = "UNKNOWN" - config *Config - logger *zap.Logger - logAccessUrls *cache.Cache + version = "UNKNOWN" + config *Config + logger *zap.Logger + bot *traqwsbot.Bot ) func main() { @@ -39,27 +36,24 @@ func main() { commands["exec-log"] = &ExecLogCommand{} commands["version"] = &VersionCommand{} - // traQクライアント初期化 - traQClient = sling.New().Base(config.TraqOrigin).Set("Authorization", "Bearer "+config.BotAccessToken) - - // アクセスキーマップ初期化 - logAccessUrls = cache.New(3*time.Minute, 5*time.Minute) + bot, err = traqwsbot.NewBot(&traqwsbot.Options{ + AccessToken: config.BotAccessToken, + Origin: config.TraqOrigin, + }) + if err != nil { + logger.Fatal("setting up traq-ws-bot", zap.Error(err)) + } - // HTTPルーター初期化 - r := chi.NewRouter() - r.Use(middleware.RequestID) - r.Use(middleware.RealIP) - r.Use(middleware.RequestLogger(&AccessLoggingFormatter{l: logger.Named("http")})) - r.Use(middleware.Recoverer) - r.Use(middleware.Heartbeat("/ping")) - r.Post("/_bot", BotEndPoint) - r.Get("/log/{key}", GetLog) + bot.OnMessageCreated(BotMessageReceived) // 起動 - if err := SendTRAQMessage(config.DevOpsChannelID, fmt.Sprintf(":up: DevOpsBot `v%s` is ready", version)); err != nil { + if err = SendTRAQMessage(context.Background(), config.DevOpsChannelID, fmt.Sprintf(":up: DevOpsBot `v%s` is ready", version)); err != nil { logger.Fatal("failed to send starting message", zap.Error(err)) } - logger.Info(fmt.Sprintf("DevOpsBot `v%s` is ready", version)) - http.ListenAndServe(config.BindAddr, r) + + err = bot.Start() + if err != nil { + logger.Fatal("starting ws bot", zap.Error(err)) + } } diff --git a/utils.go b/utils.go index 5739b55..1397ea8 100644 --- a/utils.go +++ b/utils.go @@ -1,43 +1,10 @@ package main import ( - "fmt" - "github.com/go-chi/chi/v5/middleware" - "go.uber.org/zap" - "math/rand" - "net/http" - "net/http/httputil" "os" - "time" - "unsafe" + "strings" ) -const ( - rs6Letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" - rs6LetterIdxBits = 6 - rs6LetterIdxMask = 1<= 0; { - if remain == 0 { - cache, remain = rand.Int63(), rs6LetterIdxMax - } - idx := int(cache & rs6LetterIdxMask) - if idx < len(rs6Letters) { - b[i] = rs6Letters[idx] - i-- - } - cache >>= rs6LetterIdxBits - remain-- - } - return *(*string)(unsafe.Pointer(&b)) -} - func StringArrayContains(arr []string, v string) bool { for i := range arr { if arr[i] == v { @@ -67,45 +34,15 @@ func fileExists(filename string) bool { return err == nil } -type AccessLoggingFormatter struct { - l *zap.Logger -} - -// NewLogEntry implements LogFormatter interface -func (f *AccessLoggingFormatter) NewLogEntry(r *http.Request) middleware.LogEntry { - return &logEntry{ - AccessLoggingFormatter: f, - req: r, +func safeConvertString(b []byte) string { + bld := strings.Builder{} + bld.Grow(len(b)) + for _, c := range string(b) { + if c == '\uFFFD' { + bld.WriteRune('.') + } else { + bld.WriteRune(c) + } } -} - -type logEntry struct { - *AccessLoggingFormatter - req *http.Request -} - -// Write implements LogEntry interface -func (e *logEntry) Write(status, bytes int, header http.Header, elapsed time.Duration, extra interface{}) { - e.l.Info(fmt.Sprintf("[%d] %s %s", status, e.req.Method, e.req.URL.Path), - zap.Int("status", status), - zap.String("method", e.req.Method), - zap.String("path", e.req.URL.Path), - zap.String("ip", e.req.RemoteAddr), - zap.String("ua", e.req.UserAgent()), - zap.Duration("latency", elapsed), - zap.Int("respSize", bytes), - zap.String("reqId", middleware.GetReqID(e.req.Context())), - ) -} - -// Panic implements LogEntry interface -func (e *logEntry) Panic(v interface{}, stack []byte) { - dump, _ := httputil.DumpRequest(e.req, false) - e.l.Error("[Recovery from panic]", - zap.Time("time", time.Now()), - zap.Any("error", v), - zap.String("request", string(dump)), - zap.String("stack", string(stack)), - zap.String("reqId", middleware.GetReqID(e.req.Context())), - ) + return bld.String() } From 76443d1b9bee01345749d0c9ec8816b39b27f4fd Mon Sep 17 00:00:00 2001 From: motoki317 Date: Thu, 4 May 2023 14:27:55 +0900 Subject: [PATCH 02/11] restructure config --- config.go | 43 ++++++++++++++++++++++++++++--------------- exec-log.go | 11 ++++++++--- main.go | 14 +++++++++++--- server.go | 35 +++++++++++++++-------------------- service.go | 43 ++++++++++++++++++------------------------- 5 files changed, 80 insertions(+), 66 deletions(-) diff --git a/config.go b/config.go index 159b68b..f65a681 100644 --- a/config.go +++ b/config.go @@ -7,21 +7,11 @@ import ( ) type Config struct { - TraqOrigin string `yaml:"traqOrigin"` - DevOpsChannelID string `yaml:"devOpsChannelId"` - BotAccessToken string `yaml:"botAccessToken"` - ConohaIdentityApiOrigin string `yaml:"conohaIdentityApiOrigin"` - ConohaComputeApiOrigin string `yaml:"conohaComputeApiOrigin"` - ConohaApiUsername string `yaml:"conohaApiUsername"` - ConohaApiPassword string `yaml:"conohaApiPassword"` - ConohaTenantID string `yaml:"conohaTenantId"` - LocalHostName string `yaml:"localhostName"` - DefaultSSHUser string `yaml:"defaultSSHUser"` - SSHPrivateKey string `yaml:"sshPrivateKey"` - LogsDir string `yaml:"logsDir"` - Stamps Stamps `yaml:"stamps"` - Services Services `yaml:"services"` - Servers Servers `yaml:"servers"` + TraqOrigin string `yaml:"traqOrigin"` + DevOpsChannelID string `yaml:"devOpsChannelId"` + BotAccessToken string `yaml:"botAccessToken"` + Stamps Stamps `yaml:"stamps"` + Commands CommandsConfig `yaml:"commands"` } type Stamps struct { @@ -33,6 +23,29 @@ type Stamps struct { Running string `yaml:"running"` } +type CommandsConfig struct { + Services ServicesConfig `yaml:"services"` + Servers ServersConfig `yaml:"servers"` +} + +type ServicesConfig struct { + LogsDir string `yaml:"logsDir"` + LocalHostName string `yaml:"localhostName"` + DefaultSSHUser string `yaml:"defaultSSHUser"` + SSHPrivateKey string `yaml:"sshPrivateKey"` + Services []*Service `yaml:"services"` +} + +type ServersConfig struct { + ConohaIdentityApiOrigin string `yaml:"conohaIdentityApiOrigin"` + ConohaComputeApiOrigin string `yaml:"conohaComputeApiOrigin"` + ConohaApiUsername string `yaml:"conohaApiUsername"` + ConohaApiPassword string `yaml:"conohaApiPassword"` + ConohaTenantID string `yaml:"conohaTenantId"` + LogsDir string `yaml:"logsDir"` + Servers []*Server `yaml:"servers"` +} + func LoadConfig(configFile string) (*Config, error) { f, err := os.Open(configFile) if err != nil { diff --git a/exec-log.go b/exec-log.go index 4f9b715..5374346 100644 --- a/exec-log.go +++ b/exec-log.go @@ -12,6 +12,8 @@ import ( // ExecLogCommand `exec-log [service|server] [name] [command] [unix]` type ExecLogCommand struct { + svc Services + svr Servers } func (ec *ExecLogCommand) Execute(ctx *Context) error { @@ -26,10 +28,11 @@ func (ec *ExecLogCommand) Execute(ctx *Context) error { } var logName string + var logsDir string switch args[0] { case "service": - s, ok := config.Services[args[1]] + s, ok := ec.svc[args[1]] if !ok { // サービスが見つからない return ctx.ReplyBad(fmt.Sprintf("Unknown service: `%s`", args[1])) @@ -45,9 +48,10 @@ func (ec *ExecLogCommand) Execute(ctx *Context) error { return ctx.ReplyForbid() } + logsDir = config.Commands.Services.LogsDir logName = c.getLogFileNameByUnixTime(unix) case "server": - s, ok := config.Servers[args[1]] + s, ok := ec.svr[args[1]] if !ok { // サーバーが見つからない return ctx.ReplyBad(fmt.Sprintf("Unknown server: `%s`", args[1])) @@ -63,12 +67,13 @@ func (ec *ExecLogCommand) Execute(ctx *Context) error { return ctx.ReplyForbid() } + logsDir = config.Commands.Servers.LogsDir logName = c.getLogFileNameByUnixTime(unix) default: return ctx.ReplyBad("Invalid Arguments") } - logFilePath := filepath.Join(config.LogsDir, logName) + logFilePath := filepath.Join(logsDir, logName) if !fileExists(logFilePath) { return ctx.ReplyBad("Log not found") diff --git a/main.go b/main.go index e29b095..34c50a0 100644 --- a/main.go +++ b/main.go @@ -31,9 +31,17 @@ func main() { if err != nil { logger.Fatal("failed to load config", zap.Error(err)) } - commands["service"] = config.Services - commands["server"] = config.Servers - commands["exec-log"] = &ExecLogCommand{} + svcCmd, err := config.Commands.Services.Compile() + if err != nil { + logger.Fatal("invalid services config", zap.Error(err)) + } + commands["service"] = svcCmd + svrCmd, err := config.Commands.Servers.Compile() + if err != nil { + logger.Fatal("invalid servers config", zap.Error(err)) + } + commands["server"] = svrCmd + commands["exec-log"] = &ExecLogCommand{svc: svcCmd, svr: svrCmd} commands["version"] = &VersionCommand{} bot, err = traqwsbot.NewBot(&traqwsbot.Options{ diff --git a/server.go b/server.go index 3142e81..918ee58 100644 --- a/server.go +++ b/server.go @@ -16,24 +16,19 @@ import ( type Servers map[string]*Server -// UnmarshalYAML gopkg.in/yaml.v2.Unmarshaler 実装 -func (ss *Servers) UnmarshalYAML(unmarshal func(interface{}) error) error { - var tmp map[string]*Server - if err := unmarshal(&tmp); err != nil { - return err - } - *ss = tmp - for name, s := range *ss { +func (sc *ServersConfig) Compile() (Servers, error) { + ss := make(Servers, len(sc.Servers)) + for _, s := range sc.Servers { // helpは予約済み - if name == "help" { - return errors.New("`help` cannot be used as server name") + if s.Name == "help" { + return nil, errors.New("`help` cannot be used as server name") } - s.Name = name s.Commands = map[string]ServerCommand{ "restart": &ServerRestartCommand{s}, } + ss[s.Name] = s } - return nil + return ss, nil } // Execute Commandインターフェース実装 @@ -77,7 +72,7 @@ func (ss Servers) MakeHelpMessage() string { // Server サーバー type Server struct { // Name サーバー名 - Name string `yaml:"-"` + Name string `yaml:"name"` // ServerID サーバーID ServerID string `yaml:"serverId"` // Description サーバー説明 @@ -158,8 +153,8 @@ func (sc *ServerRestartCommand) Execute(ctx *Context) error { } req, err := sling.New(). - Base(config.ConohaComputeApiOrigin). - Post(fmt.Sprintf("v2/%s/servers/%s/action", config.ConohaTenantID, sc.server.ServerID)). + Base(config.Commands.Servers.ConohaComputeApiOrigin). + Post(fmt.Sprintf("v2/%s/servers/%s/action", config.Commands.Servers.ConohaTenantID, sc.server.ServerID)). BodyJSON(Map{"reboot": Map{"type": args[0]}}). Set("Accept", "application/json"). Set("X-Auth-Token", token). @@ -206,7 +201,7 @@ func (sc *ServerRestartCommand) Execute(ctx *Context) error { } func (sc *ServerRestartCommand) openLogFile(ctx *Context) (*os.File, error) { - logFilePath := filepath.Join(config.LogsDir, sc.getLogFileName(ctx)) + logFilePath := filepath.Join(config.Commands.Servers.LogsDir, sc.getLogFileName(ctx)) logFile, err := os.OpenFile(logFilePath, os.O_RDWR|os.O_CREATE, 0600) if err != nil { ctx.L().Error("failed to open log file", zap.String("path", logFilePath), zap.Error(err)) @@ -246,15 +241,15 @@ func getConohaAPIToken() (string, error) { }{ Auth: auth{ PasswordCredentials: passwordCredentials{ - Username: config.ConohaApiUsername, - Password: config.ConohaApiPassword, + Username: config.Commands.Servers.ConohaApiUsername, + Password: config.Commands.Servers.ConohaApiPassword, }, - TenantId: config.ConohaTenantID, + TenantId: config.Commands.Servers.ConohaTenantID, }, } req, err := sling.New(). - Base(config.ConohaIdentityApiOrigin). + Base(config.Commands.Servers.ConohaIdentityApiOrigin). Post("v2.0/tokens"). BodyJSON(requestJson). Set("Accept", "application/json"). diff --git a/service.go b/service.go index 163f1c8..a81ee44 100644 --- a/service.go +++ b/service.go @@ -3,44 +3,37 @@ package main import ( "errors" "fmt" - "github.com/kballard/go-shellquote" - "go.uber.org/zap" - "golang.org/x/crypto/ssh" "io" - "io/ioutil" "os" "os/exec" "path/filepath" "strings" "sync" + + "github.com/kballard/go-shellquote" + "go.uber.org/zap" + "golang.org/x/crypto/ssh" ) -// Services サービスマップ type Services map[string]*Service -// UnmarshalYAML gopkg.in/yaml.v2.Unmarshaler 実装 -func (ss *Services) UnmarshalYAML(unmarshal func(interface{}) error) error { - var tmp map[string]*Service - if err := unmarshal(&tmp); err != nil { - return err - } - *ss = tmp - for name, s := range *ss { +func (sc *ServicesConfig) Compile() (Services, error) { + ss := make(Services, len(sc.Services)) + for _, s := range sc.Services { // helpは予約済み - if name == "help" { - return errors.New("`help` cannot be used as service name") + if s.Name == "help" { + return nil, errors.New("`help` cannot be used as service name") } - s.Name = name for name, c := range s.Commands { // helpは予約済み if name == "help" { - return errors.New("`help` cannot be used as service command name") + return nil, errors.New("`help` cannot be used as service command name") } c.Name = name c.service = s } } - return nil + return ss, nil } // Execute Commandインターフェース実装 @@ -84,7 +77,7 @@ func (ss Services) MakeHelpMessage() string { // Service サービス type Service struct { // Name サービス名 - Name string `yaml:"-"` + Name string `yaml:"name"` // Description サービス説明 Description string `yaml:"description"` // Host サービス稼働ホスト名 @@ -212,7 +205,7 @@ func (sc *ServiceCommand) GetSSHUser() string { case len(sc.service.SSHUser) > 0: return sc.service.SSHUser default: - return config.DefaultSSHUser + return config.Commands.Services.DefaultSSHUser } } @@ -252,7 +245,7 @@ func (sc *ServiceCommand) Execute(ctx *Context) error { _ = ctx.ReplyAccept() ctx.L().Info("shell command execution starts") - ctx.ReplyRunning() + _ = ctx.ReplyRunning() err := sc.execute(ctx) ctx.L().Info("shell command execution ends", zap.Error(err)) @@ -275,7 +268,7 @@ func (sc *ServiceCommand) Execute(ctx *Context) error { return ctx.ReplyFailure("An internal error has occurred") } defer logFile.Close() - b, err := ioutil.ReadAll(io.LimitReader(logFile, 1<<20)) // 1KBまでに抑えとく + b, err := io.ReadAll(io.LimitReader(logFile, 1<<20)) // 1KBまでに抑えとく if err != nil { ctx.L().Error("failed to read log file", zap.Error(err)) return ctx.ReplyFailure("An internal error has occurred") @@ -304,7 +297,7 @@ func (sc *ServiceCommand) Execute(ctx *Context) error { func (sc *ServiceCommand) execute(ctx *Context) error { // local or remote switch sc.GetExecutionHost() { - case "", config.LocalHostName: + case "", config.Commands.Services.LocalHostName: return sc.executeLocal(ctx) default: return sc.executeRemote(ctx) @@ -321,7 +314,7 @@ func (sc *ServiceCommand) executeRemote(ctx *Context) error { defer logFile.Close() // 秘密鍵のパース - key, err := ssh.ParsePrivateKey([]byte(config.SSHPrivateKey)) + key, err := ssh.ParsePrivateKey([]byte(config.Commands.Services.SSHPrivateKey)) if err != nil { ctx.L().Error("failed to read private key for ssh", zap.Error(err)) return err @@ -405,7 +398,7 @@ func (sc *ServiceCommand) executeLocal(ctx *Context) error { // openLogFile ログファイルを開く func (sc *ServiceCommand) openLogFile(ctx *Context) (*os.File, error) { - logFilePath := filepath.Join(config.LogsDir, sc.getLogFileName(ctx)) + logFilePath := filepath.Join(config.Commands.Services.LogsDir, sc.getLogFileName(ctx)) logFile, err := os.OpenFile(logFilePath, os.O_RDWR|os.O_CREATE, 0600) if err != nil { ctx.L().Error("failed to open log file", zap.String("path", logFilePath), zap.Error(err)) From e572a3964871828abce8e9ec3005e955379668ae Mon Sep 17 00:00:00 2001 From: motoki317 Date: Thu, 4 May 2023 18:10:29 +0900 Subject: [PATCH 03/11] add deploy cmd --- command.go | 41 ++++++++-------- config.go | 19 ++++++++ deploy.go | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++ go.mod | 2 + go.sum | 4 ++ main.go | 10 ++++ server.go | 11 +++-- service.go | 7 +-- utils.go | 16 ------ 9 files changed, 208 insertions(+), 43 deletions(-) create mode 100644 deploy.go diff --git a/command.go b/command.go index 7228f53..5f93583 100644 --- a/command.go +++ b/command.go @@ -2,6 +2,7 @@ package main import ( "context" + "strings" "github.com/traPtitech/traq-ws-bot/payload" "go.uber.org/zap" @@ -29,56 +30,58 @@ func (ctx *Context) GetExecutor() string { return ctx.P.Message.User.Name } -// ReplyViaDM コマンドメッセージに返信します -func (ctx *Context) Reply(message, stamp string) (err error) { - if len(message) > 0 { - err = SendTRAQMessage(ctx, ctx.P.Message.ChannelID, message) - if err != nil { - return - } +// Reply コマンドメッセージに返信します +func (ctx *Context) Reply(message ...string) error { + return SendTRAQMessage(ctx, ctx.P.Message.ChannelID, strings.Join(message, "\n")) +} + +func (ctx *Context) ReplyWithStamp(stamp string, message ...string) error { + err := PushTRAQStamp(ctx, ctx.P.Message.ID, stamp) + if err != nil { + return err } - if len(stamp) > 0 { - err = PushTRAQStamp(ctx, ctx.P.Message.ID, stamp) + if len(message) > 0 { + err = ctx.Reply(message...) if err != nil { - return + return err } } - return + return nil } // ReplyViaDM コマンド実行者にDMで返信します -func (ctx *Context) ReplyViaDM(message string) error { - return SendTRAQDirectMessage(ctx, ctx.P.Message.User.ID, message) +func (ctx *Context) ReplyViaDM(message ...string) error { + return SendTRAQDirectMessage(ctx, ctx.P.Message.User.ID, strings.Join(message, "\n")) } // ReplyBad コマンドメッセージにBadスタンプをつけて返信します func (ctx *Context) ReplyBad(message ...string) (err error) { - return ctx.Reply(stringOrEmpty(message...), config.Stamps.BadCommand) + return ctx.ReplyWithStamp(config.Stamps.BadCommand, message...) } // ReplyForbid コマンドメッセージにForbidスタンプをつけて返信します func (ctx *Context) ReplyForbid(message ...string) error { - return ctx.Reply(stringOrEmpty(message...), config.Stamps.Forbid) + return ctx.ReplyWithStamp(config.Stamps.Forbid, message...) } // ReplyAccept コマンドメッセージにAcceptスタンプをつけて返信します func (ctx *Context) ReplyAccept(message ...string) error { - return ctx.Reply(stringOrEmpty(message...), config.Stamps.Accept) + return ctx.ReplyWithStamp(config.Stamps.Accept, message...) } // ReplySuccess コマンドメッセージにSuccessスタンプをつけて返信します func (ctx *Context) ReplySuccess(message ...string) error { - return ctx.Reply(stringOrEmpty(message...), config.Stamps.Success) + return ctx.ReplyWithStamp(config.Stamps.Success, message...) } // ReplyFailure コマンドメッセージにFailureスタンプをつけて返信します func (ctx *Context) ReplyFailure(message ...string) error { - return ctx.Reply(stringOrEmpty(message...), config.Stamps.Failure) + return ctx.ReplyWithStamp(config.Stamps.Failure, message...) } // ReplyRunning コマンドメッセージにRunningスタンプをつけて返信します func (ctx *Context) ReplyRunning(message ...string) error { - return ctx.Reply(stringOrEmpty(message...), config.Stamps.Running) + return ctx.ReplyWithStamp(config.Stamps.Running, message...) } func (ctx *Context) L() *zap.Logger { diff --git a/config.go b/config.go index f65a681..5e85200 100644 --- a/config.go +++ b/config.go @@ -24,10 +24,29 @@ type Stamps struct { } type CommandsConfig struct { + Deploy DeployConfig `yaml:"deploy"` Services ServicesConfig `yaml:"services"` Servers ServersConfig `yaml:"servers"` } +type DeployConfig struct { + Templates []*DeployTemplateConfig `yaml:"templates"` + Commands []*DeployCommandConfig `yaml:"commands"` +} + +type DeployTemplateConfig struct { + Name string `yaml:"name"` + Command string `yaml:"command"` + CommandFile string `yaml:"commandFile"` +} + +type DeployCommandConfig struct { + Name string `yaml:"name"` + TemplateRef string `yaml:"templateRef"` + ArgsPrefix []string `yaml:"argsPrefix"` + Operators []string `yaml:"operators"` +} + type ServicesConfig struct { LogsDir string `yaml:"logsDir"` LocalHostName string `yaml:"localhostName"` diff --git a/deploy.go b/deploy.go new file mode 100644 index 0000000..cbcf320 --- /dev/null +++ b/deploy.go @@ -0,0 +1,141 @@ +package main + +import ( + "bytes" + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + + "github.com/samber/lo" +) + +type DeployCommand struct { + instances map[string]*DeployCommandInstance +} + +type DeployCommandInstance struct { + commandFile string + argsPrefix []string + operators []string +} + +func (dc *DeployConfig) Compile() (*DeployCommand, error) { + var cmd DeployCommand + + templates := make(map[string]string, len(dc.Templates)) // name to filename + for _, tc := range dc.Templates { + if tc.Name == "" { + return nil, fmt.Errorf("template needs to have a name") + } + if _, ok := templates[tc.Name]; ok { + return nil, fmt.Errorf("template %s conflict", tc.Name) + } + if tc.Command != "" && tc.CommandFile != "" { + return nil, fmt.Errorf("template %s cannot have both command and commandFile set", tc.Name) + } + if tc.Command == "" && tc.CommandFile == "" { + return nil, fmt.Errorf("template %s needs to have either command or commandFile", tc.Name) + } + + filename := tc.CommandFile + if filename == "" { + f, err := os.CreateTemp("", "command-") + if err != nil { + return nil, fmt.Errorf("creating command file: %w", err) + } + err = f.Chmod(0755) + if err != nil { + return nil, fmt.Errorf("changing file permission: %w", err) + } + _, err = f.WriteString(tc.Command) + if err != nil { + return nil, fmt.Errorf("writing command to file: %w", err) + } + err = f.Close() + if err != nil { + return nil, fmt.Errorf("closing command file: %w", err) + } + + filename = filepath.Join(os.TempDir(), f.Name()) + } + templates[tc.Name] = filename + } + + for _, cc := range dc.Commands { + tmplFile, ok := templates[cc.TemplateRef] + if !ok { + return nil, fmt.Errorf("invalid template ref %s", cc.TemplateRef) + } + + if _, ok = cmd.instances[cc.Name]; ok { + return nil, fmt.Errorf("command name %s conflict", cc.Name) + } + cmd.instances[cc.Name] = &DeployCommandInstance{ + commandFile: tmplFile, + argsPrefix: cc.ArgsPrefix, + operators: cc.Operators, + } + } + + return &cmd, nil +} + +func (dc *DeployCommand) Execute(ctx *Context) error { + // ctx.Args = deploy [name] [args...] + + if len(ctx.Args) <= 1 { + return ctx.Reply(dc.MakeHelpMessage()...) + } + + name := ctx.Args[1] + c, ok := dc.instances[name] + if !ok { + return ctx.ReplyBad(fmt.Sprintf("unrecognized deploy subcommand %s", name)) + } + + // Check operator + if len(c.operators) > 0 { + if !lo.Contains(c.operators, ctx.GetExecutor()) { + return ctx.ReplyForbid() + } + } + + // Run + var args []string + args = append(args, c.argsPrefix...) + args = append(args, ctx.Args[2:]...) + var buf bytes.Buffer + cmd := exec.Command(c.commandFile, args...) + cmd.Stdout = &buf + cmd.Stderr = &buf + + err := cmd.Run() + if err != nil { + return ctx.ReplyFailure( + fmt.Sprintf("exec failed: %v", err), + "```", + safeConvertString(buf.Bytes()), + "```", + ) + } + + return ctx.ReplySuccess( + "```", + safeConvertString(buf.Bytes()), + "```", + ) +} + +func (dc *DeployCommand) MakeHelpMessage() []string { + var lines []string + lines = append(lines, "# deploy") + for name, cmd := range dc.instances { + lines = append(lines, fmt.Sprintf("- deploy %s", name)) + if len(cmd.operators) > 0 { + lines = append(lines, fmt.Sprintf("- operators: %s", strings.Join(cmd.operators, ", "))) + } + } + return lines +} diff --git a/go.mod b/go.mod index 6faf42b..142d685 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.20 require ( github.com/dghubble/sling v1.4.1 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 + github.com/samber/lo v1.38.1 github.com/traPtitech/go-traq v0.0.0-20220426061605-adc15dcfc6d0 github.com/traPtitech/traq-ws-bot v1.1.2 go.uber.org/zap v1.24.0 @@ -19,6 +20,7 @@ require ( github.com/gorilla/websocket v1.5.0 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.11.0 // indirect + golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect golang.org/x/net v0.9.0 // indirect golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect golang.org/x/sys v0.7.0 // indirect diff --git a/go.sum b/go.sum index 1a8f4b3..51f0933 100644 --- a/go.sum +++ b/go.sum @@ -126,6 +126,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= +github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= @@ -167,6 +169,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM= +golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= diff --git a/main.go b/main.go index 34c50a0..b200906 100644 --- a/main.go +++ b/main.go @@ -31,16 +31,26 @@ func main() { if err != nil { logger.Fatal("failed to load config", zap.Error(err)) } + + // Register commands + deployCmd, err := config.Commands.Deploy.Compile() + if err != nil { + logger.Fatal("compiling deploy cmd", zap.Error(err)) + } + commands["deploy"] = deployCmd + svcCmd, err := config.Commands.Services.Compile() if err != nil { logger.Fatal("invalid services config", zap.Error(err)) } commands["service"] = svcCmd + svrCmd, err := config.Commands.Servers.Compile() if err != nil { logger.Fatal("invalid servers config", zap.Error(err)) } commands["server"] = svrCmd + commands["exec-log"] = &ExecLogCommand{svc: svcCmd, svr: svrCmd} commands["version"] = &VersionCommand{} diff --git a/server.go b/server.go index 918ee58..e4c4539 100644 --- a/server.go +++ b/server.go @@ -11,6 +11,7 @@ import ( "strings" "github.com/dghubble/sling" + "github.com/samber/lo" "go.uber.org/zap" ) @@ -41,7 +42,7 @@ func (ss Servers) Execute(ctx *Context) error { if args[0] == "help" { // サーバー一覧表示 - return ctx.Reply(ss.MakeHelpMessage(), "") + return ctx.Reply(ss.MakeHelpMessage()) } s, ok := ss[args[0]] @@ -85,7 +86,7 @@ type Server struct { } // Execute Commandインターフェース実装 -func (s Server) Execute(ctx *Context) error { +func (s *Server) Execute(ctx *Context) error { if len(ctx.Args) < 3 { return ctx.ReplyBad("Invalid Arguments") } @@ -93,7 +94,7 @@ func (s Server) Execute(ctx *Context) error { args := ctx.Args[2:] if args[0] == "help" { - return ctx.Reply(s.MakeHelpMessage(), "") + return ctx.Reply(s.MakeHelpMessage()) } c, ok := s.Commands[args[0]] @@ -139,7 +140,7 @@ func (sc *ServerRestartCommand) Execute(ctx *Context) error { // ctx.Args = server [server_name] restart [SOFT|HARD] args := ctx.Args[3:] - if !StringArrayContains([]string{"SOFT", "HARD"}, args[0]) { + if !lo.Contains([]string{"SOFT", "HARD"}, args[0]) { return ctx.ReplyBad(fmt.Sprintf("Unknown restart type: `%s`", args[0])) } @@ -224,7 +225,7 @@ func (s *Server) GetOperators() []string { // CheckOperator nameユーザーがこのコマンドを実行可能かどうか func (s *Server) CheckOperator(name string) bool { - return StringArrayContains(s.GetOperators(), name) + return lo.Contains(s.GetOperators(), name) } func getConohaAPIToken() (string, error) { diff --git a/service.go b/service.go index a81ee44..dd2768b 100644 --- a/service.go +++ b/service.go @@ -11,6 +11,7 @@ import ( "sync" "github.com/kballard/go-shellquote" + "github.com/samber/lo" "go.uber.org/zap" "golang.org/x/crypto/ssh" ) @@ -46,7 +47,7 @@ func (ss Services) Execute(ctx *Context) error { if args[0] == "help" { // サービス一覧表示 - return ctx.Reply(ss.MakeHelpMessage(), "") + return ctx.Reply(ss.MakeHelpMessage()) } s, ok := ss[args[0]] @@ -106,7 +107,7 @@ func (s *Service) Execute(ctx *Context) error { if args[0] == "help" { // サービスヘルプを表示 - return ctx.Reply(s.MakeHelpMessage(), "") + return ctx.Reply(s.MakeHelpMessage()) } c, ok := s.Commands[args[0]] @@ -218,7 +219,7 @@ func (sc *ServiceCommand) GetOperators() []string { // CheckOperator nameユーザーがこのコマンドを実行可能かどうか func (sc *ServiceCommand) CheckOperator(name string) bool { - return StringArrayContains(sc.GetOperators(), name) + return lo.Contains(sc.GetOperators(), name) } // Execute Commandインターフェース実装 diff --git a/utils.go b/utils.go index 1397ea8..f7ac0e2 100644 --- a/utils.go +++ b/utils.go @@ -5,22 +5,6 @@ import ( "strings" ) -func StringArrayContains(arr []string, v string) bool { - for i := range arr { - if arr[i] == v { - return true - } - } - return false -} - -func stringOrEmpty(s ...string) string { - if len(s) > 0 { - return s[0] - } - return "" -} - func getEnvOrDefault(env, def string) string { s := os.Getenv(env) if len(s) > 0 { From 9261548b9976d6d90d5151ca1e856b7866e22b9d Mon Sep 17 00:00:00 2001 From: motoki317 Date: Thu, 4 May 2023 18:21:05 +0900 Subject: [PATCH 04/11] use prefix for commands --- bot.go | 9 +++++++-- config.go | 1 + deploy.go | 2 +- main.go | 8 ++------ 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/bot.go b/bot.go index d057012..302626f 100644 --- a/bot.go +++ b/bot.go @@ -3,8 +3,10 @@ package main import ( "context" "fmt" + "strings" "github.com/kballard/go-shellquote" + "github.com/samber/lo" "github.com/traPtitech/go-traq" "github.com/traPtitech/traq-ws-bot/payload" "go.uber.org/zap" @@ -26,9 +28,12 @@ func BotMessageReceived(p *payload.MessageCreated) { _ = PushTRAQStamp(ctx, p.Message.ID, config.Stamps.BadCommand) return } - if len(args[0]) == 0 { - return // 空メッセージは無視 + _, argStart, ok := lo.FindIndexOf(args, func(arg string) bool { return strings.HasPrefix(arg, config.Prefix) }) + if !ok { + return } + args = args[argStart:] + args[0] = strings.TrimPrefix(args[0], config.Prefix) cmdCtx := &Context{ Context: ctx, diff --git a/config.go b/config.go index 5e85200..76e5caf 100644 --- a/config.go +++ b/config.go @@ -10,6 +10,7 @@ type Config struct { TraqOrigin string `yaml:"traqOrigin"` DevOpsChannelID string `yaml:"devOpsChannelId"` BotAccessToken string `yaml:"botAccessToken"` + Prefix string `yaml:"prefix"` Stamps Stamps `yaml:"stamps"` Commands CommandsConfig `yaml:"commands"` } diff --git a/deploy.go b/deploy.go index cbcf320..639d87f 100644 --- a/deploy.go +++ b/deploy.go @@ -107,7 +107,7 @@ func (dc *DeployCommand) Execute(ctx *Context) error { args = append(args, c.argsPrefix...) args = append(args, ctx.Args[2:]...) var buf bytes.Buffer - cmd := exec.Command(c.commandFile, args...) + cmd := exec.CommandContext(ctx, c.commandFile, args...) cmd.Stdout = &buf cmd.Stderr = &buf diff --git a/main.go b/main.go index b200906..80261e3 100644 --- a/main.go +++ b/main.go @@ -1,7 +1,6 @@ package main import ( - "context" "fmt" traqwsbot "github.com/traPtitech/traq-ws-bot" @@ -26,6 +25,8 @@ func main() { } defer logger.Sync() + logger.Info(fmt.Sprintf("DevOpsBot `v%s` initializing", version)) + // 設定ファイル読み込み config, err = LoadConfig(getEnvOrDefault("CONFIG_FILE", "./config.yml")) if err != nil { @@ -65,11 +66,6 @@ func main() { bot.OnMessageCreated(BotMessageReceived) // 起動 - if err = SendTRAQMessage(context.Background(), config.DevOpsChannelID, fmt.Sprintf(":up: DevOpsBot `v%s` is ready", version)); err != nil { - logger.Fatal("failed to send starting message", zap.Error(err)) - } - logger.Info(fmt.Sprintf("DevOpsBot `v%s` is ready", version)) - err = bot.Start() if err != nil { logger.Fatal("starting ws bot", zap.Error(err)) From 50fecbaa98a8287431d779bd6fcaa55490a948e7 Mon Sep 17 00:00:00 2001 From: motoki317 Date: Thu, 4 May 2023 18:23:25 +0900 Subject: [PATCH 05/11] add prefix to usage help --- deploy.go | 2 +- server.go | 4 ++-- service.go | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/deploy.go b/deploy.go index 639d87f..94021e8 100644 --- a/deploy.go +++ b/deploy.go @@ -132,7 +132,7 @@ func (dc *DeployCommand) MakeHelpMessage() []string { var lines []string lines = append(lines, "# deploy") for name, cmd := range dc.instances { - lines = append(lines, fmt.Sprintf("- deploy %s", name)) + lines = append(lines, fmt.Sprintf("- %sdeploy %s", config.Prefix, name)) if len(cmd.operators) > 0 { lines = append(lines, fmt.Sprintf("- operators: %s", strings.Join(cmd.operators, ", "))) } diff --git a/server.go b/server.go index e4c4539..3b41dc0 100644 --- a/server.go +++ b/server.go @@ -58,7 +58,7 @@ func (ss Servers) MakeHelpMessage() string { var sb strings.Builder sb.WriteString("## server\n") sb.WriteString("### usage:\n") - sb.WriteString("`server [server_name] restart [SOFT|HARD]`\n") + sb.WriteString(fmt.Sprintf("`%sserver [server_name] restart [SOFT|HARD]`\n", config.Prefix)) sb.WriteString("### servers:\n") for name, s := range ss { if len(s.Description) > 0 { @@ -110,7 +110,7 @@ func (s *Server) MakeHelpMessage() string { var sb strings.Builder sb.WriteString(fmt.Sprintf("## server: %s\n", s.Name)) sb.WriteString("### usage:\n") - sb.WriteString(fmt.Sprintf("`server %s restart [SOFT|HARD]`\n", s.Name)) + sb.WriteString(fmt.Sprintf("`%sserver %s restart [SOFT|HARD]`\n", config.Prefix, s.Name)) sb.WriteString("### operators:\n") var quotedUsers []string for _, u := range s.GetOperators() { diff --git a/service.go b/service.go index dd2768b..af4fe63 100644 --- a/service.go +++ b/service.go @@ -63,7 +63,7 @@ func (ss Services) MakeHelpMessage() string { var sb strings.Builder sb.WriteString("## service\n") sb.WriteString("### usage:\n") - sb.WriteString("`service [service_name] [command]`\n") + sb.WriteString(fmt.Sprintf("`%sservice [service_name] [command]`\n", config.Prefix)) sb.WriteString("### services:\n") for name, s := range ss { if len(s.Description) > 0 { @@ -123,7 +123,7 @@ func (s *Service) MakeHelpMessage() string { var sb strings.Builder sb.WriteString(fmt.Sprintf("## service: %s\n", s.Name)) sb.WriteString("### usage:\n") - sb.WriteString(fmt.Sprintf("`service %s [command]`\n", s.Name)) + sb.WriteString(fmt.Sprintf("`%sservice %s [command]`\n", config.Prefix, s.Name)) sb.WriteString("### commands:\n") for name, c := range s.Commands { sb.WriteString(fmt.Sprintf("+ `%s`\n", name)) From 506396abc3a2c6ff8f53cb3adc38da431ad6c4f7 Mon Sep 17 00:00:00 2001 From: motoki317 Date: Thu, 4 May 2023 18:54:16 +0900 Subject: [PATCH 06/11] refactor help message build --- server.go | 44 ++++++++++++++++++++------------------------ service.go | 51 +++++++++++++++++++-------------------------------- 2 files changed, 39 insertions(+), 56 deletions(-) diff --git a/server.go b/server.go index 3b41dc0..7f25339 100644 --- a/server.go +++ b/server.go @@ -35,14 +35,14 @@ func (sc *ServersConfig) Compile() (Servers, error) { // Execute Commandインターフェース実装 func (ss Servers) Execute(ctx *Context) error { if len(ctx.Args) < 2 { - return ctx.ReplyBad("Invalid Arguments") + return ctx.Reply(ss.MakeHelpMessage()...) } // ctx.Args = server [server_name] restart [SOFT|HARD] args := ctx.Args[1:] if args[0] == "help" { // サーバー一覧表示 - return ctx.Reply(ss.MakeHelpMessage()) + return ctx.Reply(ss.MakeHelpMessage()...) } s, ok := ss[args[0]] @@ -54,20 +54,20 @@ func (ss Servers) Execute(ctx *Context) error { } // MakeHelpMessage server help用のメッセージを作成 -func (ss Servers) MakeHelpMessage() string { - var sb strings.Builder - sb.WriteString("## server\n") - sb.WriteString("### usage:\n") - sb.WriteString(fmt.Sprintf("`%sserver [server_name] restart [SOFT|HARD]`\n", config.Prefix)) - sb.WriteString("### servers:\n") +func (ss Servers) MakeHelpMessage() []string { + var lines []string + lines = append(lines, "# server") for name, s := range ss { if len(s.Description) > 0 { - sb.WriteString(fmt.Sprintf("+ `%s` - %s\n", name, s.Description)) + lines = append(lines, fmt.Sprintf("+ `%s` - %s", name, s.Description)) } else { - sb.WriteString(fmt.Sprintf("+ `%s`\n", name)) + lines = append(lines, fmt.Sprintf("+ `%s`", name)) } + + // restart cmd + lines = append(lines, fmt.Sprintf(" + %sserver %s restart [SOFT|HARD]", config.Prefix, name)) } - return sb.String() + return lines } // Server サーバー @@ -94,7 +94,7 @@ func (s *Server) Execute(ctx *Context) error { args := ctx.Args[2:] if args[0] == "help" { - return ctx.Reply(s.MakeHelpMessage()) + return ctx.Reply(s.MakeHelpMessage()...) } c, ok := s.Commands[args[0]] @@ -106,18 +106,14 @@ func (s *Server) Execute(ctx *Context) error { } // MakeHelpMessage server [name] help用のメッセージを作成 -func (s *Server) MakeHelpMessage() string { - var sb strings.Builder - sb.WriteString(fmt.Sprintf("## server: %s\n", s.Name)) - sb.WriteString("### usage:\n") - sb.WriteString(fmt.Sprintf("`%sserver %s restart [SOFT|HARD]`\n", config.Prefix, s.Name)) - sb.WriteString("### operators:\n") - var quotedUsers []string - for _, u := range s.GetOperators() { - quotedUsers = append(quotedUsers, fmt.Sprintf("`%s`", u)) - } - sb.WriteString(strings.Join(quotedUsers, ",")) - return sb.String() +func (s *Server) MakeHelpMessage() []string { + var lines []string + lines = append(lines, fmt.Sprintf("## server: %s", s.Name)) + lines = append(lines, "### usage:") + lines = append(lines, fmt.Sprintf("`%sserver %s restart [SOFT|HARD]`", config.Prefix, s.Name)) + lines = append(lines, "### operators:") + lines = append(lines, strings.Join(s.GetOperators(), ", ")) + return lines } type ServerCommand interface { diff --git a/service.go b/service.go index af4fe63..25735bf 100644 --- a/service.go +++ b/service.go @@ -40,14 +40,14 @@ func (sc *ServicesConfig) Compile() (Services, error) { // Execute Commandインターフェース実装 func (ss Services) Execute(ctx *Context) error { if len(ctx.Args) < 2 { - return ctx.ReplyBad("Invalid Arguments") + return ctx.Reply(ss.MakeHelpMessage()...) } // ctx.Args = service [name] [command] args := ctx.Args[1:] if args[0] == "help" { // サービス一覧表示 - return ctx.Reply(ss.MakeHelpMessage()) + return ctx.Reply(ss.MakeHelpMessage()...) } s, ok := ss[args[0]] @@ -59,20 +59,16 @@ func (ss Services) Execute(ctx *Context) error { } // MakeHelpMessage service help用のメッセージを作成 -func (ss Services) MakeHelpMessage() string { - var sb strings.Builder - sb.WriteString("## service\n") - sb.WriteString("### usage:\n") - sb.WriteString(fmt.Sprintf("`%sservice [service_name] [command]`\n", config.Prefix)) - sb.WriteString("### services:\n") - for name, s := range ss { - if len(s.Description) > 0 { - sb.WriteString(fmt.Sprintf("+ `%s` - %s\n", name, s.Description)) - } else { - sb.WriteString(fmt.Sprintf("+ `%s`\n", name)) +func (ss Services) MakeHelpMessage() []string { + var lines []string + lines = append(lines, "# service") + lines = append(lines, fmt.Sprintf("`%sservice [service_name]` for more help", config.Prefix)) + for _, s := range ss { + for _, sub := range s.Commands { + lines = append(lines, fmt.Sprintf("+ %sservice %s %s", config.Prefix, s.Name, sub.Name)) } } - return sb.String() + return lines } // Service サービス @@ -100,14 +96,14 @@ type Service struct { // Execute Commandインターフェース実装 func (s *Service) Execute(ctx *Context) error { if len(ctx.Args) < 3 { - return ctx.ReplyBad("Invalid Arguments") + return ctx.Reply(s.MakeHelpMessage()...) } // ctx.Args = service [name] [command] args := ctx.Args[2:] if args[0] == "help" { // サービスヘルプを表示 - return ctx.Reply(s.MakeHelpMessage()) + return ctx.Reply(s.MakeHelpMessage()...) } c, ok := s.Commands[args[0]] @@ -119,26 +115,17 @@ func (s *Service) Execute(ctx *Context) error { } // MakeHelpMessage service [name] help用のメッセージを作成 -func (s *Service) MakeHelpMessage() string { - var sb strings.Builder - sb.WriteString(fmt.Sprintf("## service: %s\n", s.Name)) - sb.WriteString("### usage:\n") - sb.WriteString(fmt.Sprintf("`%sservice %s [command]`\n", config.Prefix, s.Name)) - sb.WriteString("### commands:\n") +func (s *Service) MakeHelpMessage() []string { + var lines []string + lines = append(lines, fmt.Sprintf("# service %s", s.Name)) for name, c := range s.Commands { - sb.WriteString(fmt.Sprintf("+ `%s`\n", name)) - + lines = append(lines, fmt.Sprintf("+ %sservice %s %s", config.Prefix, s.Name, name)) if len(s.Description) > 0 { - sb.WriteString(fmt.Sprintf(" + %s\n", s.Description)) - } - - var quotedUsers []string - for _, u := range c.GetOperators() { - quotedUsers = append(quotedUsers, fmt.Sprintf("`%s`", u)) + lines = append(lines, fmt.Sprintf(" + %s", s.Description)) } - sb.WriteString(fmt.Sprintf(" + available users: %s\n", strings.Join(quotedUsers, ","))) + lines = append(lines, fmt.Sprintf(" + available users: %s", strings.Join(c.GetOperators(), ","))) } - return sb.String() + return lines } // ServiceCommand サービスコマンド From 10ef35350f333920685ba88aa20af18b07a84e1a Mon Sep 17 00:00:00 2001 From: motoki317 Date: Thu, 4 May 2023 19:07:19 +0900 Subject: [PATCH 07/11] refactor server config structure --- config.go | 25 +++++++++++++------ server.go | 73 ++++++++++++++++++++++++++++++------------------------- 2 files changed, 58 insertions(+), 40 deletions(-) diff --git a/config.go b/config.go index 76e5caf..1e8fc3e 100644 --- a/config.go +++ b/config.go @@ -57,13 +57,24 @@ type ServicesConfig struct { } type ServersConfig struct { - ConohaIdentityApiOrigin string `yaml:"conohaIdentityApiOrigin"` - ConohaComputeApiOrigin string `yaml:"conohaComputeApiOrigin"` - ConohaApiUsername string `yaml:"conohaApiUsername"` - ConohaApiPassword string `yaml:"conohaApiPassword"` - ConohaTenantID string `yaml:"conohaTenantId"` - LogsDir string `yaml:"logsDir"` - Servers []*Server `yaml:"servers"` + ConohaIdentityApiOrigin string `yaml:"conohaIdentityApiOrigin"` + ConohaComputeApiOrigin string `yaml:"conohaComputeApiOrigin"` + ConohaApiUsername string `yaml:"conohaApiUsername"` + ConohaApiPassword string `yaml:"conohaApiPassword"` + ConohaTenantID string `yaml:"conohaTenantId"` + LogsDir string `yaml:"logsDir"` + Servers []*ServerInstanceConfig `yaml:"servers"` +} + +type ServerInstanceConfig struct { + // Name サーバー名 + Name string `yaml:"name"` + // ServerID サーバーID + ServerID string `yaml:"serverId"` + // Description サーバー説明 + Description string `yaml:"description"` + // Operators コマンド実行可能なユーザーの名前のデフォルト配列 + Operators []string `yaml:"operators"` } func LoadConfig(configFile string) (*Config, error) { diff --git a/server.go b/server.go index 7f25339..05283bc 100644 --- a/server.go +++ b/server.go @@ -15,37 +15,50 @@ import ( "go.uber.org/zap" ) -type Servers map[string]*Server +type ServersCommand struct { + instances map[string]*ServerInstance +} + +func (sc *ServersConfig) Compile() (*ServersCommand, error) { + var cmd ServersCommand -func (sc *ServersConfig) Compile() (Servers, error) { - ss := make(Servers, len(sc.Servers)) - for _, s := range sc.Servers { + cmd.instances = make(map[string]*ServerInstance, len(sc.Servers)) + for _, sic := range sc.Servers { // helpは予約済み - if s.Name == "help" { + if sic.Name == "help" { return nil, errors.New("`help` cannot be used as server name") } - s.Commands = map[string]ServerCommand{ - "restart": &ServerRestartCommand{s}, + if sic.ServerID == "" { + return nil, errors.New("serverID cannot be empty") } - ss[s.Name] = s + + s := &ServerInstance{ + Name: sic.Name, + ServerID: sic.ServerID, + Description: sic.Description, + Operators: sic.Operators, + Commands: make(map[string]ServerCommand), + } + s.Commands["restart"] = &ServerRestartCommand{s} + cmd.instances[s.Name] = s } - return ss, nil + return &cmd, nil } // Execute Commandインターフェース実装 -func (ss Servers) Execute(ctx *Context) error { +func (sc *ServersCommand) Execute(ctx *Context) error { if len(ctx.Args) < 2 { - return ctx.Reply(ss.MakeHelpMessage()...) + return ctx.Reply(sc.MakeHelpMessage()...) } // ctx.Args = server [server_name] restart [SOFT|HARD] args := ctx.Args[1:] if args[0] == "help" { // サーバー一覧表示 - return ctx.Reply(ss.MakeHelpMessage()...) + return ctx.Reply(sc.MakeHelpMessage()...) } - s, ok := ss[args[0]] + s, ok := sc.instances[args[0]] if !ok { // サーバーが見つからない return ctx.ReplyBad(fmt.Sprintf("Unknown server: `%s`", args[0])) @@ -54,10 +67,10 @@ func (ss Servers) Execute(ctx *Context) error { } // MakeHelpMessage server help用のメッセージを作成 -func (ss Servers) MakeHelpMessage() []string { +func (sc *ServersCommand) MakeHelpMessage() []string { var lines []string lines = append(lines, "# server") - for name, s := range ss { + for name, s := range sc.instances { if len(s.Description) > 0 { lines = append(lines, fmt.Sprintf("+ `%s` - %s", name, s.Description)) } else { @@ -70,23 +83,17 @@ func (ss Servers) MakeHelpMessage() []string { return lines } -// Server サーバー -type Server struct { - // Name サーバー名 - Name string `yaml:"name"` - // ServerID サーバーID - ServerID string `yaml:"serverId"` - // Description サーバー説明 - Description string `yaml:"description"` - // Operators コマンド実行可能なユーザーの名前のデフォルト配列 - Operators []string `yaml:"operators"` - - // Commands サーバーコマンド UnmarshalYAMLで追加 - Commands map[string]ServerCommand `yaml:"-"` +type ServerInstance struct { + Name string + ServerID string + Description string + Operators []string + + Commands map[string]ServerCommand } // Execute Commandインターフェース実装 -func (s *Server) Execute(ctx *Context) error { +func (s *ServerInstance) Execute(ctx *Context) error { if len(ctx.Args) < 3 { return ctx.ReplyBad("Invalid Arguments") } @@ -106,7 +113,7 @@ func (s *Server) Execute(ctx *Context) error { } // MakeHelpMessage server [name] help用のメッセージを作成 -func (s *Server) MakeHelpMessage() []string { +func (s *ServerInstance) MakeHelpMessage() []string { var lines []string lines = append(lines, fmt.Sprintf("## server: %s", s.Name)) lines = append(lines, "### usage:") @@ -122,7 +129,7 @@ type ServerCommand interface { } type ServerRestartCommand struct { - server *Server + server *ServerInstance } func (sc *ServerRestartCommand) Execute(ctx *Context) error { @@ -215,12 +222,12 @@ func (sc *ServerRestartCommand) getLogFileNameByUnixTime(unix int64) string { return fmt.Sprintf("exec-%s-%s-%d", sc.server.Name, "restart", unix) } -func (s *Server) GetOperators() []string { +func (s *ServerInstance) GetOperators() []string { return s.Operators } // CheckOperator nameユーザーがこのコマンドを実行可能かどうか -func (s *Server) CheckOperator(name string) bool { +func (s *ServerInstance) CheckOperator(name string) bool { return lo.Contains(s.GetOperators(), name) } From 6bc0680f7674505f6157ae2dc9bd006eb398fd69 Mon Sep 17 00:00:00 2001 From: motoki317 Date: Thu, 4 May 2023 19:11:49 +0900 Subject: [PATCH 08/11] rm service cmd --- config.go | 13 +- exec-log.go | 26 +--- go.mod | 2 - go.sum | 5 - main.go | 8 +- service.go | 404 ---------------------------------------------------- 6 files changed, 6 insertions(+), 452 deletions(-) delete mode 100644 service.go diff --git a/config.go b/config.go index 1e8fc3e..af419e7 100644 --- a/config.go +++ b/config.go @@ -25,9 +25,8 @@ type Stamps struct { } type CommandsConfig struct { - Deploy DeployConfig `yaml:"deploy"` - Services ServicesConfig `yaml:"services"` - Servers ServersConfig `yaml:"servers"` + Deploy DeployConfig `yaml:"deploy"` + Servers ServersConfig `yaml:"servers"` } type DeployConfig struct { @@ -48,14 +47,6 @@ type DeployCommandConfig struct { Operators []string `yaml:"operators"` } -type ServicesConfig struct { - LogsDir string `yaml:"logsDir"` - LocalHostName string `yaml:"localhostName"` - DefaultSSHUser string `yaml:"defaultSSHUser"` - SSHPrivateKey string `yaml:"sshPrivateKey"` - Services []*Service `yaml:"services"` -} - type ServersConfig struct { ConohaIdentityApiOrigin string `yaml:"conohaIdentityApiOrigin"` ConohaComputeApiOrigin string `yaml:"conohaComputeApiOrigin"` diff --git a/exec-log.go b/exec-log.go index 5374346..5c24d84 100644 --- a/exec-log.go +++ b/exec-log.go @@ -12,12 +12,11 @@ import ( // ExecLogCommand `exec-log [service|server] [name] [command] [unix]` type ExecLogCommand struct { - svc Services - svr Servers + svr *ServersCommand } func (ec *ExecLogCommand) Execute(ctx *Context) error { - // ctx.Args = exec-log [service|server] [name] [command] [unix] + // ctx.Args = exec-log server [name] [command] [unix] if len(ctx.Args) != 5 { return ctx.ReplyBad("Invalid Arguments") } @@ -31,27 +30,8 @@ func (ec *ExecLogCommand) Execute(ctx *Context) error { var logsDir string switch args[0] { - case "service": - s, ok := ec.svc[args[1]] - if !ok { - // サービスが見つからない - return ctx.ReplyBad(fmt.Sprintf("Unknown service: `%s`", args[1])) - } - c, ok := s.Commands[args[2]] - if !ok { - // コマンドが見つからない - return ctx.ReplyBad(fmt.Sprintf("Unknown command: `%s`", args[2])) - } - - // オペレーター確認 - if !c.CheckOperator(ctx.GetExecutor()) { - return ctx.ReplyForbid() - } - - logsDir = config.Commands.Services.LogsDir - logName = c.getLogFileNameByUnixTime(unix) case "server": - s, ok := ec.svr[args[1]] + s, ok := ec.svr.instances[args[1]] if !ok { // サーバーが見つからない return ctx.ReplyBad(fmt.Sprintf("Unknown server: `%s`", args[1])) diff --git a/go.mod b/go.mod index 142d685..9489f86 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,6 @@ require ( github.com/traPtitech/go-traq v0.0.0-20220426061605-adc15dcfc6d0 github.com/traPtitech/traq-ws-bot v1.1.2 go.uber.org/zap v1.24.0 - golang.org/x/crypto v0.8.0 gopkg.in/yaml.v2 v2.4.0 ) @@ -23,7 +22,6 @@ require ( golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect golang.org/x/net v0.9.0 // indirect golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect - golang.org/x/sys v0.7.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.28.0 // indirect ) diff --git a/go.sum b/go.sum index 51f0933..2f1f81b 100644 --- a/go.sum +++ b/go.sum @@ -157,8 +157,6 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ= -golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -269,11 +267,8 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= -golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/main.go b/main.go index 80261e3..df5bf0c 100644 --- a/main.go +++ b/main.go @@ -40,19 +40,13 @@ func main() { } commands["deploy"] = deployCmd - svcCmd, err := config.Commands.Services.Compile() - if err != nil { - logger.Fatal("invalid services config", zap.Error(err)) - } - commands["service"] = svcCmd - svrCmd, err := config.Commands.Servers.Compile() if err != nil { logger.Fatal("invalid servers config", zap.Error(err)) } commands["server"] = svrCmd - commands["exec-log"] = &ExecLogCommand{svc: svcCmd, svr: svrCmd} + commands["exec-log"] = &ExecLogCommand{svr: svrCmd} commands["version"] = &VersionCommand{} bot, err = traqwsbot.NewBot(&traqwsbot.Options{ diff --git a/service.go b/service.go deleted file mode 100644 index 25735bf..0000000 --- a/service.go +++ /dev/null @@ -1,404 +0,0 @@ -package main - -import ( - "errors" - "fmt" - "io" - "os" - "os/exec" - "path/filepath" - "strings" - "sync" - - "github.com/kballard/go-shellquote" - "github.com/samber/lo" - "go.uber.org/zap" - "golang.org/x/crypto/ssh" -) - -type Services map[string]*Service - -func (sc *ServicesConfig) Compile() (Services, error) { - ss := make(Services, len(sc.Services)) - for _, s := range sc.Services { - // helpは予約済み - if s.Name == "help" { - return nil, errors.New("`help` cannot be used as service name") - } - for name, c := range s.Commands { - // helpは予約済み - if name == "help" { - return nil, errors.New("`help` cannot be used as service command name") - } - c.Name = name - c.service = s - } - } - return ss, nil -} - -// Execute Commandインターフェース実装 -func (ss Services) Execute(ctx *Context) error { - if len(ctx.Args) < 2 { - return ctx.Reply(ss.MakeHelpMessage()...) - } - // ctx.Args = service [name] [command] - args := ctx.Args[1:] - - if args[0] == "help" { - // サービス一覧表示 - return ctx.Reply(ss.MakeHelpMessage()...) - } - - s, ok := ss[args[0]] - if !ok { - // サービスが見つからない - return ctx.ReplyBad(fmt.Sprintf("Unknown service: `%s`", args[0])) - } - return s.Execute(ctx) -} - -// MakeHelpMessage service help用のメッセージを作成 -func (ss Services) MakeHelpMessage() []string { - var lines []string - lines = append(lines, "# service") - lines = append(lines, fmt.Sprintf("`%sservice [service_name]` for more help", config.Prefix)) - for _, s := range ss { - for _, sub := range s.Commands { - lines = append(lines, fmt.Sprintf("+ %sservice %s %s", config.Prefix, s.Name, sub.Name)) - } - } - return lines -} - -// Service サービス -type Service struct { - // Name サービス名 - Name string `yaml:"name"` - // Description サービス説明 - Description string `yaml:"description"` - // Host サービス稼働ホスト名 - // - // このホスト上でコマンドが実行されます - Host string `yaml:"host"` - // SSHPort サービス稼働ホストのSSHポート番号 - SSHPort int `yaml:"sshPort"` - // SSHUser サービス稼働ホストのSSHユーザー名 - SSHUser string `yaml:"sshUser"` - // Operators コマンド実行可能なユーザーの名前のデフォルト配列 - // - // 各コマンド設定においてオーバーライド可能 - Operators []string `yaml:"operators"` - // Commands サービスコマンド - Commands map[string]*ServiceCommand `yaml:"commands"` -} - -// Execute Commandインターフェース実装 -func (s *Service) Execute(ctx *Context) error { - if len(ctx.Args) < 3 { - return ctx.Reply(s.MakeHelpMessage()...) - } - // ctx.Args = service [name] [command] - args := ctx.Args[2:] - - if args[0] == "help" { - // サービスヘルプを表示 - return ctx.Reply(s.MakeHelpMessage()...) - } - - c, ok := s.Commands[args[0]] - if !ok { - // コマンドが見つからない - return ctx.ReplyBad(fmt.Sprintf("Unknown command: `%s`", args[0])) - } - return c.Execute(ctx) -} - -// MakeHelpMessage service [name] help用のメッセージを作成 -func (s *Service) MakeHelpMessage() []string { - var lines []string - lines = append(lines, fmt.Sprintf("# service %s", s.Name)) - for name, c := range s.Commands { - lines = append(lines, fmt.Sprintf("+ %sservice %s %s", config.Prefix, s.Name, name)) - if len(s.Description) > 0 { - lines = append(lines, fmt.Sprintf(" + %s", s.Description)) - } - lines = append(lines, fmt.Sprintf(" + available users: %s", strings.Join(c.GetOperators(), ","))) - } - return lines -} - -// ServiceCommand サービスコマンド -type ServiceCommand struct { - // Name コマンド名 - Name string `yaml:"-"` - // Description コマンド説明 - Description string `yaml:"description"` - // Host サービス稼働ホスト名 - // - // この設定はサービス設定のHostをオーバーライドします - Host string `yaml:"host"` - // SSHPort サービス稼働ホストのSSHポート番号 - // - // この設定はサービス設定のSSHPortをオーバーライドします - SSHPort int `yaml:"sshPort"` - // SSHUser サービス稼働ホストのSSHユーザー名 - // - // この設定はサービス設定のSSHUserをオーバーライドします - SSHUser string `yaml:"sshUser"` - // Command 実行コマンド - Command string `yaml:"command"` - // CommandArgs 実行コマンド引数 - CommandArgs []string `yaml:"commandArgs"` - // WorkingDirectory コマンド実行ディレクトリ - WorkingDirectory string `yaml:"workingDir"` - // Operators コマンド実行可能なユーザーの名前の配列 - // - // この設定はサービス設定のOperatorsをオーバーライドします - Operators []string `yaml:"operators"` - // AllowConcurrency このコマンドの同時並列実行を許可するか - AllowConcurrency bool `yaml:"allowConcurrency"` - // AppendVariableArgs このコマンドの実行引数に、メッセージから追加で与えられた引数を追記するか - AppendVariableArgs bool `yaml:"appendVariableArgs"` - // PrintOutputOnMessage コマンド実行結果をメッセージとして送信するか - PrintOutputOnMessage bool `yaml:"printOutputOnMessage"` - - service *Service `yaml:"-"` - running bool `yaml:"-"` - m sync.Mutex `yaml:"-"` -} - -func (sc *ServiceCommand) GetExecutionHost() string { - if len(sc.Host) > 0 { - return sc.Host - } - return sc.service.Host -} - -func (sc *ServiceCommand) GetSSHPort() int { - switch { - case sc.SSHPort != 0: - return sc.SSHPort - case sc.service.SSHPort != 0: - return sc.service.SSHPort - default: - return 22 - } -} - -func (sc *ServiceCommand) GetSSHUser() string { - switch { - case len(sc.SSHUser) > 0: - return sc.SSHUser - case len(sc.service.SSHUser) > 0: - return sc.service.SSHUser - default: - return config.Commands.Services.DefaultSSHUser - } -} - -func (sc *ServiceCommand) GetOperators() []string { - if len(sc.Operators) > 0 { - return sc.Operators - } - return sc.service.Operators -} - -// CheckOperator nameユーザーがこのコマンドを実行可能かどうか -func (sc *ServiceCommand) CheckOperator(name string) bool { - return lo.Contains(sc.GetOperators(), name) -} - -// Execute Commandインターフェース実装 -func (sc *ServiceCommand) Execute(ctx *Context) error { - // ctx.Args = service [name] [command] - - // オペレーター確認 - if !sc.CheckOperator(ctx.GetExecutor()) { - return ctx.ReplyForbid() - } - - if !sc.AllowConcurrency { - // 同時実行ロック - sc.m.Lock() - if sc.running { - // 既に実行中 - sc.m.Unlock() - return nil - } - sc.running = true - sc.m.Unlock() - } - - _ = ctx.ReplyAccept() - - ctx.L().Info("shell command execution starts") - _ = ctx.ReplyRunning() - err := sc.execute(ctx) - ctx.L().Info("shell command execution ends", zap.Error(err)) - - sc.m.Lock() - sc.running = false - sc.m.Unlock() - - success := err == nil - - if !sc.PrintOutputOnMessage { - if success { - return ctx.ReplySuccess(fmt.Sprintf(":white_check_mark: Command execution was successful. \n log: `exec-log service %s %s %d` %s", sc.service.Name, sc.Name, ctx.P.EventTime.Unix(), cite(ctx.P.Message.ID))) - } - return ctx.ReplyFailure(fmt.Sprintf(":x: An error has occurred while executing command. \nPlease check the execution log. `exec-log service %s %s %d` %s", sc.service.Name, sc.Name, ctx.P.EventTime.Unix(), cite(ctx.P.Message.ID))) - } - - logFile, err := sc.openLogFile(ctx) - if err != nil { - ctx.L().Error("failed to open log file", zap.Error(err)) - return ctx.ReplyFailure("An internal error has occurred") - } - defer logFile.Close() - b, err := io.ReadAll(io.LimitReader(logFile, 1<<20)) // 1KBまでに抑えとく - if err != nil { - ctx.L().Error("failed to read log file", zap.Error(err)) - return ctx.ReplyFailure("An internal error has occurred") - } - - var message strings.Builder - if success { - message.WriteString(":white_check_mark: Command execution was successful.\n") - } else { - message.WriteString(":x: An error has occurred while executing command.\n") - } - message.WriteString(fmt.Sprintf("```:exec-%s-%s-%d\n", sc.service.Name, sc.Name, ctx.P.EventTime.Unix())) - message.Write(b) - if !strings.HasSuffix(string(b), "\n") { - message.WriteString("\n") - } - message.WriteString("```\n") - message.WriteString(cite(ctx.P.Message.ID)) - - if success { - return ctx.ReplySuccess(message.String()) - } - return ctx.ReplyFailure(message.String()) -} - -func (sc *ServiceCommand) execute(ctx *Context) error { - // local or remote - switch sc.GetExecutionHost() { - case "", config.Commands.Services.LocalHostName: - return sc.executeLocal(ctx) - default: - return sc.executeRemote(ctx) - } -} - -// executeRemote SSHで実行 -func (sc *ServiceCommand) executeRemote(ctx *Context) error { - // ログファイル生成 - logFile, err := sc.openLogFile(ctx) - if err != nil { - return err - } - defer logFile.Close() - - // 秘密鍵のパース - key, err := ssh.ParsePrivateKey([]byte(config.Commands.Services.SSHPrivateKey)) - if err != nil { - ctx.L().Error("failed to read private key for ssh", zap.Error(err)) - return err - } - - // ssh接続 - host := sc.GetExecutionHost() - conn, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", host, sc.GetSSHPort()), &ssh.ClientConfig{ - User: sc.GetSSHUser(), - Auth: []ssh.AuthMethod{ - ssh.PublicKeys(key), - }, - HostKeyCallback: ssh.InsecureIgnoreHostKey(), - }) - if err != nil { - ctx.L().Error(fmt.Sprintf("failed to ssh to %s", host), zap.Error(err)) - return err - } - defer conn.Close() - session, err := conn.NewSession() - if err != nil { - ctx.L().Error(fmt.Sprintf("failed to create ssh session to %s", host), zap.Error(err)) - return err - } - defer session.Close() - - // ログファイル設定 - session.Stdout = logFile - session.Stderr = logFile - - // コマンド生成 - execCmd := append([]string{sc.Command}, sc.CommandArgs...) - if sc.AppendVariableArgs { - execCmd = append(execCmd, ctx.Args[3:]...) - } - - cmdStr := fmt.Sprintf("%s && %s", shellquote.Join("cd", sc.WorkingDirectory), shellquote.Join(execCmd...)) - - // コマンド実行 - if err = session.Start(cmdStr); err != nil { - ctx.L().Error("failed to execute shell command", zap.String("cmd", cmdStr), zap.Error(err)) - return err - } - - // 終了待機 - return session.Wait() -} - -// executeLocal ローカルで実行 -func (sc *ServiceCommand) executeLocal(ctx *Context) error { - // ログファイル生成 - logFile, err := sc.openLogFile(ctx) - if err != nil { - return err - } - defer logFile.Close() - - // execコマンド生成 - args := make([]string, 0) - args = append(args, sc.CommandArgs...) - if sc.AppendVariableArgs { - args = append(args, ctx.Args[3:]...) - } - - cmd := exec.Command(sc.Command, args...) - cmd.Dir = sc.WorkingDirectory - - // ログファイル設定 - cmd.Stdout = logFile - cmd.Stderr = logFile - - // コマンド実行 - if err := cmd.Start(); err != nil { - ctx.L().Error("failed to execute shell command", zap.Stringer("cmd", cmd), zap.Error(err)) - return err - } - - // 終了待機 - return cmd.Wait() -} - -// openLogFile ログファイルを開く -func (sc *ServiceCommand) openLogFile(ctx *Context) (*os.File, error) { - logFilePath := filepath.Join(config.Commands.Services.LogsDir, sc.getLogFileName(ctx)) - logFile, err := os.OpenFile(logFilePath, os.O_RDWR|os.O_CREATE, 0600) - if err != nil { - ctx.L().Error("failed to open log file", zap.String("path", logFilePath), zap.Error(err)) - return nil, err - } - return logFile, nil -} - -func (sc *ServiceCommand) getLogFileName(ctx *Context) string { - return sc.getLogFileNameByUnixTime(ctx.P.EventTime.Unix()) -} - -func (sc *ServiceCommand) getLogFileNameByUnixTime(unix int64) string { - return fmt.Sprintf("exec-%s-%s-%d", sc.service.Name, sc.Name, unix) -} From d89dda0369750711f9135bcac406cdc4c807fa5d Mon Sep 17 00:00:00 2001 From: motoki317 Date: Thu, 4 May 2023 21:36:20 +0900 Subject: [PATCH 09/11] use spf13/viper --- .gitignore | 10 ++-- bot.go | 5 +- config.go | 127 +++++++++++++++++++++++++++++++------------------- deploy.go | 19 ++++++-- go.mod | 20 ++++++-- go.sum | 133 +++++++++++++++++++++++++++++++++++++++++++++++------ help.go | 17 +++++++ main.go | 13 +++--- server.go | 36 ++++++++------- utils.go | 8 ---- version.go | 10 ---- 11 files changed, 280 insertions(+), 118 deletions(-) create mode 100644 help.go delete mode 100644 version.go diff --git a/.gitignore b/.gitignore index 53ccad9..d48d1e9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ *.iml /.idea/ -./DevOpsBot -./log -./config.yaml -./dist + +/DevOpsBot +/log +/config.yaml +/dist +/test.sh diff --git a/bot.go b/bot.go index 302626f..35a7c33 100644 --- a/bot.go +++ b/bot.go @@ -18,7 +18,10 @@ type Map map[string]interface{} func BotMessageReceived(p *payload.MessageCreated) { ctx := context.Background() - if p.Message.ChannelID != config.DevOpsChannelID { + if p.Message.User.Bot { + return // Ignore bots + } + if p.Message.ChannelID != config.ChannelID { return // DevOpsチャンネル以外からのメッセージは無視 } diff --git a/config.go b/config.go index af419e7..5788a3f 100644 --- a/config.go +++ b/config.go @@ -2,82 +2,113 @@ package main import ( "os" + "strings" - "gopkg.in/yaml.v2" + "github.com/spf13/viper" ) +var config Config + type Config struct { - TraqOrigin string `yaml:"traqOrigin"` - DevOpsChannelID string `yaml:"devOpsChannelId"` - BotAccessToken string `yaml:"botAccessToken"` - Prefix string `yaml:"prefix"` - Stamps Stamps `yaml:"stamps"` - Commands CommandsConfig `yaml:"commands"` + TraqOrigin string `mapstructure:"traqOrigin" yaml:"traqOrigin"` + ChannelID string `mapstructure:"channelID" yaml:"channelID"` + Token string `mapstructure:"token" yaml:"token"` + Prefix string `mapstructure:"prefix" yaml:"prefix"` + Stamps Stamps `mapstructure:"stamps" yaml:"stamps"` + Commands CommandsConfig `mapstructure:"commands" yaml:"commands"` } type Stamps struct { - Accept string `yaml:"accept"` - BadCommand string `yaml:"badCommand"` - Forbid string `yaml:"forbid"` - Success string `yaml:"success"` - Failure string `yaml:"failure"` - Running string `yaml:"running"` + Accept string `mapstructure:"accept" yaml:"accept"` + BadCommand string `mapstructure:"badCommand" yaml:"badCommand"` + Forbid string `mapstructure:"forbid" yaml:"forbid"` + Success string `mapstructure:"success" yaml:"success"` + Failure string `mapstructure:"failure" yaml:"failure"` + Running string `mapstructure:"running" yaml:"running"` } type CommandsConfig struct { - Deploy DeployConfig `yaml:"deploy"` - Servers ServersConfig `yaml:"servers"` + Deploy DeployConfig `mapstructure:"deploy" yaml:"deploy"` + Servers ServersConfig `mapstructure:"servers" yaml:"servers"` } type DeployConfig struct { - Templates []*DeployTemplateConfig `yaml:"templates"` - Commands []*DeployCommandConfig `yaml:"commands"` + Templates []*DeployTemplateConfig `mapstructure:"templates" yaml:"templates"` + Commands []*DeployCommandConfig `mapstructure:"commands" yaml:"commands"` } type DeployTemplateConfig struct { - Name string `yaml:"name"` - Command string `yaml:"command"` - CommandFile string `yaml:"commandFile"` + Name string `mapstructure:"name" yaml:"name"` + Command string `mapstructure:"command" yaml:"command"` + CommandFile string `mapstructure:"commandFile" yaml:"commandFile"` } type DeployCommandConfig struct { - Name string `yaml:"name"` - TemplateRef string `yaml:"templateRef"` - ArgsPrefix []string `yaml:"argsPrefix"` - Operators []string `yaml:"operators"` + Name string `mapstructure:"name" yaml:"name"` + TemplateRef string `mapstructure:"templateRef" yaml:"templateRef"` + Description string `mapstructure:"description" yaml:"description"` + ArgsPrefix []string `mapstructure:"argsPrefix" yaml:"argsPrefix"` + Operators []string `mapstructure:"operators" yaml:"operators"` } type ServersConfig struct { - ConohaIdentityApiOrigin string `yaml:"conohaIdentityApiOrigin"` - ConohaComputeApiOrigin string `yaml:"conohaComputeApiOrigin"` - ConohaApiUsername string `yaml:"conohaApiUsername"` - ConohaApiPassword string `yaml:"conohaApiPassword"` - ConohaTenantID string `yaml:"conohaTenantId"` - LogsDir string `yaml:"logsDir"` - Servers []*ServerInstanceConfig `yaml:"servers"` + Servers []*ServerInstanceConfig `mapstructure:"servers" yaml:"servers"` + LogsDir string `mapstructure:"logsDir" yaml:"logsDir"` + Conoha struct { + Origin struct { + Identity string `mapstructure:"identity" yaml:"identity"` + Compute string `mapstructure:"compute" yaml:"compute"` + } `mapstructure:"origin" yaml:"origin"` + Username string `mapstructure:"apiUsername" yaml:"apiUsername"` + Password string `mapstructure:"apiPassword" yaml:"apiPassword"` + TenantID string `mapstructure:"tenantID" yaml:"tenantID"` + } `mapstructure:"conoha" yaml:"conoha"` } type ServerInstanceConfig struct { - // Name サーバー名 - Name string `yaml:"name"` - // ServerID サーバーID - ServerID string `yaml:"serverId"` - // Description サーバー説明 - Description string `yaml:"description"` - // Operators コマンド実行可能なユーザーの名前のデフォルト配列 - Operators []string `yaml:"operators"` + Name string `mapstructure:"name" yaml:"name"` + ServerID string `mapstructure:"serverID" yaml:"serverID"` + Description string `mapstructure:"description" yaml:"description"` + Operators []string `mapstructure:"operators" yaml:"operators"` } -func LoadConfig(configFile string) (*Config, error) { - f, err := os.Open(configFile) - if err != nil { - return nil, err +func init() { + viper.SetDefault("traqOrigin", "wss://q.trap.jp") + viper.SetDefault("channelID", "") + viper.SetDefault("token", "") + viper.SetDefault("prefix", "/") + + viper.SetDefault("stamps.accept", "") + viper.SetDefault("stamps.badCommand", "") + viper.SetDefault("stamps.forbid", "") + viper.SetDefault("stamps.success", "") + viper.SetDefault("stamps.failure", "") + viper.SetDefault("stamps.running", "") + + viper.SetDefault("commands.deploy.templates", nil) + viper.SetDefault("commands.deploy.commands", nil) + + viper.SetDefault("commands.servers.servers", nil) + viper.SetDefault("commands.servers.logsDir", "/logs") + viper.SetDefault("commands.servers.conoha.origin.identity", "https://identity.tyo1.conoha.io/") + viper.SetDefault("commands.servers.conoha.origin.compute", "https://compute.tyo1.conoha.io/") + viper.SetDefault("commands.servers.conoha.username", "") + viper.SetDefault("commands.servers.conoha.password", "") + viper.SetDefault("commands.servers.conoha.tenantID", "") +} + +func LoadConfig() error { + configFile := os.Getenv("CONFIG_FILE") + if configFile == "" { + configFile = "./config.yaml" } - defer f.Close() + viper.SetConfigFile(configFile) + viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) + viper.AutomaticEnv() - var c Config - if err := yaml.NewDecoder(f).Decode(&c); err != nil { - return nil, err + err := viper.ReadInConfig() + if err != nil { + return err } - return &c, nil + return viper.Unmarshal(&config) } diff --git a/deploy.go b/deploy.go index 94021e8..376032a 100644 --- a/deploy.go +++ b/deploy.go @@ -17,12 +17,15 @@ type DeployCommand struct { type DeployCommandInstance struct { commandFile string + description string argsPrefix []string operators []string } func (dc *DeployConfig) Compile() (*DeployCommand, error) { - var cmd DeployCommand + cmd := &DeployCommand{ + instances: make(map[string]*DeployCommandInstance), + } templates := make(map[string]string, len(dc.Templates)) // name to filename for _, tc := range dc.Templates { @@ -74,12 +77,13 @@ func (dc *DeployConfig) Compile() (*DeployCommand, error) { } cmd.instances[cc.Name] = &DeployCommandInstance{ commandFile: tmplFile, + description: cc.Description, argsPrefix: cc.ArgsPrefix, operators: cc.Operators, } } - return &cmd, nil + return cmd, nil } func (dc *DeployCommand) Execute(ctx *Context) error { @@ -130,11 +134,16 @@ func (dc *DeployCommand) Execute(ctx *Context) error { func (dc *DeployCommand) MakeHelpMessage() []string { var lines []string - lines = append(lines, "# deploy") + lines = append(lines, "## deploy commands") for name, cmd := range dc.instances { - lines = append(lines, fmt.Sprintf("- %sdeploy %s", config.Prefix, name)) + lines = append(lines, fmt.Sprintf( + "- `%sdeploy %s`%s", + config.Prefix, + name, + lo.Ternary(cmd.description != "", " - "+cmd.description, ""), + )) if len(cmd.operators) > 0 { - lines = append(lines, fmt.Sprintf("- operators: %s", strings.Join(cmd.operators, ", "))) + lines = append(lines, fmt.Sprintf(" - operators: %s", strings.Join(cmd.operators, ", "))) } } return lines diff --git a/go.mod b/go.mod index 9489f86..d1869f3 100644 --- a/go.mod +++ b/go.mod @@ -6,22 +6,36 @@ require ( github.com/dghubble/sling v1.4.1 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 github.com/samber/lo v1.38.1 + github.com/spf13/viper v1.15.0 github.com/traPtitech/go-traq v0.0.0-20220426061605-adc15dcfc6d0 github.com/traPtitech/traq-ws-bot v1.1.2 go.uber.org/zap v1.24.0 - gopkg.in/yaml.v2 v2.4.0 ) require ( + github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/gofrs/uuid v4.2.0+incompatible // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/pelletier/go-toml/v2 v2.0.6 // indirect + github.com/spf13/afero v1.9.3 // indirect + github.com/spf13/cast v1.5.0 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/subosito/gotenv v1.4.2 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect golang.org/x/net v0.9.0 // indirect - golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect + golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 // indirect + golang.org/x/sys v0.7.0 // indirect + golang.org/x/text v0.9.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.28.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 2f1f81b..51f1947 100644 --- a/go.sum +++ b/go.sum @@ -3,6 +3,7 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= @@ -13,6 +14,9 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -30,6 +34,7 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= @@ -40,14 +45,22 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dghubble/sling v1.4.1 h1:AxjTubpVyozMvbBCtXcsWEyGGgUZutC5YGrfxPNVOcQ= github.com/dghubble/sling v1.4.1/go.mod h1:QoMB1KL3GAo+7HsD8Itd6S+6tW91who8BGZzuLvpOyc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -77,6 +90,7 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= @@ -90,12 +104,14 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -103,34 +119,72 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= +github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= +github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= +github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= +github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= +github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= +github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/traPtitech/go-traq v0.0.0-20220426061605-adc15dcfc6d0 h1:OmzaVUbkE9bkPsRcVMdohAo6Jdr2zOrqw48QSrCk3Dc= github.com/traPtitech/go-traq v0.0.0-20220426061605-adc15dcfc6d0/go.mod h1:p85KAwzfN5gbgsbQ//Ge1wMbdsy1v9TguH5TYt9TznI= github.com/traPtitech/traq-ws-bot v1.1.2 h1:gBmSJ2B4lx/zAzL3aBxbe7jGEPVNhJviWVard40yU7s= @@ -138,12 +192,14 @@ github.com/traPtitech/traq-ws-bot v1.1.2/go.mod h1:mnUHbZiFLydoUxS2q8kzR1E+1RMRX github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= @@ -156,7 +212,9 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -181,6 +239,7 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -189,6 +248,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -216,9 +277,12 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -226,8 +290,12 @@ golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 h1:OSnWWcOd/CtWQC2cYSBgbTSJv3ciqd8r54ySIW2y3RE= -golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 h1:nt+Q6cXKz4MosCSpnbMtqiQ8Oz0pxTef2B4Vca2lvfk= +golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -236,6 +304,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -262,20 +332,31 @@ golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -319,11 +400,17 @@ golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -341,6 +428,9 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -378,6 +468,13 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -390,6 +487,10 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -402,16 +503,18 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/help.go b/help.go new file mode 100644 index 0000000..04e5893 --- /dev/null +++ b/help.go @@ -0,0 +1,17 @@ +package main + +import ( + "fmt" +) + +type HelpCommand struct{} + +func (h *HelpCommand) Execute(ctx *Context) error { + var lines []string + lines = append(lines, fmt.Sprintf("## DevOpsBot v%s", version)) + lines = append(lines, fmt.Sprintf("- `%sdeploy` - Do deployments", config.Prefix)) + lines = append(lines, fmt.Sprintf("- `%sserver` - Server management", config.Prefix)) + lines = append(lines, fmt.Sprintf("- `%sexec-log` - Retrieve command logs", config.Prefix)) + lines = append(lines, fmt.Sprintf("- `%shelp` - This help", config.Prefix)) + return ctx.Reply(lines...) +} diff --git a/main.go b/main.go index df5bf0c..aa9f9fb 100644 --- a/main.go +++ b/main.go @@ -10,7 +10,6 @@ import ( var ( version = "UNKNOWN" - config *Config logger *zap.Logger bot *traqwsbot.Bot ) @@ -18,7 +17,7 @@ var ( func main() { var err error - // ロガー初期化 + // Initialize logger logger, err = zap.NewProduction() if err != nil { panic(err) @@ -27,8 +26,8 @@ func main() { logger.Info(fmt.Sprintf("DevOpsBot `v%s` initializing", version)) - // 設定ファイル読み込み - config, err = LoadConfig(getEnvOrDefault("CONFIG_FILE", "./config.yml")) + // Load config + err = LoadConfig() if err != nil { logger.Fatal("failed to load config", zap.Error(err)) } @@ -47,10 +46,11 @@ func main() { commands["server"] = svrCmd commands["exec-log"] = &ExecLogCommand{svr: svrCmd} - commands["version"] = &VersionCommand{} + commands["help"] = &HelpCommand{} + // Start bot bot, err = traqwsbot.NewBot(&traqwsbot.Options{ - AccessToken: config.BotAccessToken, + AccessToken: config.Token, Origin: config.TraqOrigin, }) if err != nil { @@ -59,7 +59,6 @@ func main() { bot.OnMessageCreated(BotMessageReceived) - // 起動 err = bot.Start() if err != nil { logger.Fatal("starting ws bot", zap.Error(err)) diff --git a/server.go b/server.go index 05283bc..23af703 100644 --- a/server.go +++ b/server.go @@ -20,9 +20,10 @@ type ServersCommand struct { } func (sc *ServersConfig) Compile() (*ServersCommand, error) { - var cmd ServersCommand + cmd := &ServersCommand{ + instances: make(map[string]*ServerInstance, len(sc.Servers)), + } - cmd.instances = make(map[string]*ServerInstance, len(sc.Servers)) for _, sic := range sc.Servers { // helpは予約済み if sic.Name == "help" { @@ -42,7 +43,7 @@ func (sc *ServersConfig) Compile() (*ServersCommand, error) { s.Commands["restart"] = &ServerRestartCommand{s} cmd.instances[s.Name] = s } - return &cmd, nil + return cmd, nil } // Execute Commandインターフェース実装 @@ -69,16 +70,17 @@ func (sc *ServersCommand) Execute(ctx *Context) error { // MakeHelpMessage server help用のメッセージを作成 func (sc *ServersCommand) MakeHelpMessage() []string { var lines []string - lines = append(lines, "# server") + lines = append(lines, "## server commands") for name, s := range sc.instances { - if len(s.Description) > 0 { - lines = append(lines, fmt.Sprintf("+ `%s` - %s", name, s.Description)) - } else { - lines = append(lines, fmt.Sprintf("+ `%s`", name)) + lines = append(lines, fmt.Sprintf( + "- `%sserver %s restart [SOFT|HARD]`%s", + config.Prefix, + name, + lo.Ternary(s.Description != "", " - "+s.Description, ""), + )) + if len(s.Operators) > 0 { + lines = append(lines, fmt.Sprintf(" - operators: %s", strings.Join(s.Operators, ", "))) } - - // restart cmd - lines = append(lines, fmt.Sprintf(" + %sserver %s restart [SOFT|HARD]", config.Prefix, name)) } return lines } @@ -157,8 +159,8 @@ func (sc *ServerRestartCommand) Execute(ctx *Context) error { } req, err := sling.New(). - Base(config.Commands.Servers.ConohaComputeApiOrigin). - Post(fmt.Sprintf("v2/%s/servers/%s/action", config.Commands.Servers.ConohaTenantID, sc.server.ServerID)). + Base(config.Commands.Servers.Conoha.Origin.Compute). + Post(fmt.Sprintf("v2/%s/servers/%s/action", config.Commands.Servers.Conoha.TenantID, sc.server.ServerID)). BodyJSON(Map{"reboot": Map{"type": args[0]}}). Set("Accept", "application/json"). Set("X-Auth-Token", token). @@ -245,15 +247,15 @@ func getConohaAPIToken() (string, error) { }{ Auth: auth{ PasswordCredentials: passwordCredentials{ - Username: config.Commands.Servers.ConohaApiUsername, - Password: config.Commands.Servers.ConohaApiPassword, + Username: config.Commands.Servers.Conoha.Username, + Password: config.Commands.Servers.Conoha.Password, }, - TenantId: config.Commands.Servers.ConohaTenantID, + TenantId: config.Commands.Servers.Conoha.TenantID, }, } req, err := sling.New(). - Base(config.Commands.Servers.ConohaIdentityApiOrigin). + Base(config.Commands.Servers.Conoha.Origin.Identity). Post("v2.0/tokens"). BodyJSON(requestJson). Set("Accept", "application/json"). diff --git a/utils.go b/utils.go index f7ac0e2..9e84948 100644 --- a/utils.go +++ b/utils.go @@ -5,14 +5,6 @@ import ( "strings" ) -func getEnvOrDefault(env, def string) string { - s := os.Getenv(env) - if len(s) > 0 { - return s - } - return def -} - func fileExists(filename string) bool { _, err := os.Stat(filename) return err == nil diff --git a/version.go b/version.go deleted file mode 100644 index 4261073..0000000 --- a/version.go +++ /dev/null @@ -1,10 +0,0 @@ -package main - -import "fmt" - -// VersionCommand `version` -type VersionCommand struct{} - -func (v VersionCommand) Execute(ctx *Context) error { - return ctx.ReplySuccess(fmt.Sprintf("DevOpsBot `v%s`", version)) -} From d09d37a4e45602db098472879ff4fee917b496f6 Mon Sep 17 00:00:00 2001 From: motoki317 Date: Thu, 4 May 2023 21:42:26 +0900 Subject: [PATCH 10/11] allow customizing commands file dir --- config.go | 6 ++++-- deploy.go | 5 ++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/config.go b/config.go index 5788a3f..dcab00d 100644 --- a/config.go +++ b/config.go @@ -33,8 +33,9 @@ type CommandsConfig struct { } type DeployConfig struct { - Templates []*DeployTemplateConfig `mapstructure:"templates" yaml:"templates"` - Commands []*DeployCommandConfig `mapstructure:"commands" yaml:"commands"` + CommandsDir string `mapstructure:"commandsDir" yaml:"commandsDir"` + Templates []*DeployTemplateConfig `mapstructure:"templates" yaml:"templates"` + Commands []*DeployCommandConfig `mapstructure:"commands" yaml:"commands"` } type DeployTemplateConfig struct { @@ -85,6 +86,7 @@ func init() { viper.SetDefault("stamps.failure", "") viper.SetDefault("stamps.running", "") + viper.SetDefault("commands.deploy.commandsDir", "/commands") viper.SetDefault("commands.deploy.templates", nil) viper.SetDefault("commands.deploy.commands", nil) diff --git a/deploy.go b/deploy.go index 376032a..60692dd 100644 --- a/deploy.go +++ b/deploy.go @@ -5,7 +5,6 @@ import ( "fmt" "os" "os/exec" - "path/filepath" "strings" "github.com/samber/lo" @@ -44,7 +43,7 @@ func (dc *DeployConfig) Compile() (*DeployCommand, error) { filename := tc.CommandFile if filename == "" { - f, err := os.CreateTemp("", "command-") + f, err := os.CreateTemp(dc.CommandsDir, "command-") if err != nil { return nil, fmt.Errorf("creating command file: %w", err) } @@ -61,7 +60,7 @@ func (dc *DeployConfig) Compile() (*DeployCommand, error) { return nil, fmt.Errorf("closing command file: %w", err) } - filename = filepath.Join(os.TempDir(), f.Name()) + filename = f.Name() } templates[tc.Name] = filename } From 43afa2a993934c9d1190c02e5837e7bed753e793 Mon Sep 17 00:00:00 2001 From: motoki317 Date: Thu, 4 May 2023 23:03:16 +0900 Subject: [PATCH 11/11] add runtime cmds --- Dockerfile | 25 +++++++++++++++++++++++++ deploy.go | 2 ++ 2 files changed, 27 insertions(+) diff --git a/Dockerfile b/Dockerfile index 0fd86a8..55f139e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,10 +18,35 @@ ENV GOARCH=$TARGETARCH RUN --mount=type=cache,target=/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build \ go build -o /dev-ops-bot -ldflags="-s -w -X main.version=$VERSION" . +FROM --platform=$BUILDPLATFORM golang:1.20-alpine AS installer + +ENV CGO_ENABLED 0 +ARG TARGETOS +ARG TARGETARCH +ENV GOOS=$TARGETOS +ENV GOARCH=$TARGETARCH + +RUN apk add --no-cache wget + +RUN wget https://github.com/mikefarah/yq/releases/latest/download/yq_"$TARGETOS"_"$TARGETARCH" -O /yq && \ + chmod +x /yq + +RUN --mount=type=cache,target=/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build \ + go install sigs.k8s.io/kustomize/kustomize/v5@latest +# keep output directory the same between platforms; workaround for https://github.com/golang/go/issues/57485 +RUN cp /go/bin/kustomize /kustomize || cp /go/bin/"$GOOS"_"$GOARCH"/kustomize /kustomize + FROM alpine:3 WORKDIR /work +# Install commands for deploy scripts +RUN apk add --no-cache git openssh +RUN mkdir -p /root/.ssh && ssh-keyscan github.com >> /root/.ssh/known_hosts + +COPY --from=installer /yq /usr/local/bin/ +COPY --from=installer /kustomize /usr/local/bin/ + COPY --from=builder /dev-ops-bot ./ ENTRYPOINT ["/work/dev-ops-bot"] diff --git a/deploy.go b/deploy.go index 60692dd..27f932b 100644 --- a/deploy.go +++ b/deploy.go @@ -106,6 +106,8 @@ func (dc *DeployCommand) Execute(ctx *Context) error { } // Run + _ = ctx.ReplyRunning() + var args []string args = append(args, c.argsPrefix...) args = append(args, ctx.Args[2:]...)