feat: add midori skeleton, bot scaffolding, CD seeds

This commit is contained in:
41666 2020-09-27 00:32:15 -04:00
parent 7c861b37ca
commit 49d44df231
30 changed files with 854 additions and 123 deletions

View file

@ -41,6 +41,16 @@ jobs:
--stamp \
--workspace_status_command hack/workspace_status.sh
- name: Write Artifact Manifest
run: |
bash hack/generate_versions.sh > manifest.json
- name: Upload Artifact Manifest
uses: actions/upload-artifact
with:
name: manifest.json
path: manifest.json
- name: Publish Dev Container Image
if: github.ref == 'refs/heads/main'
run: |

27
.github/workflows/release.yml vendored Normal file
View file

@ -0,0 +1,27 @@
name: Release Workflow
on: workflow_dispatch
jobs:
commit_release_tag:
name: Commit Roleypoly Release Tag
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
with:
ssh-key: ${{secrets.DEPLOY_KEY}}
# - name: Setup Git
# uses: webfactory/ssh-agent@v0.2.0
# with:
# ssh-private-key: ${{ secrets.DEPLOY_KEY }}
- name: Push changes
id: push
run: |
TAG=$(date +v%Y%m%d-%H%M%S)
git config --local user.email "gh-automation@roleypoly.com"
git config --local user.name "Roleypoly Release Automation"
git tag $TAG
git push origin $TAG
echo "::set-output release_tag=${TAG}"

3
.gitignore vendored
View file

@ -3,4 +3,5 @@ bazel-out
bazel-roleypoly
bazel-testlogs
node_modules
.env
.env
docker-compose.yaml

View file

@ -103,6 +103,12 @@ def go_repositories():
sum = "h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=",
version = "v1.1.1",
)
go_repository(
name = "com_github_dghubble_trie",
importpath = "github.com/dghubble/trie",
sum = "h1:euE/xPG0HIg6XiNXYrAHxX9aVwD1gw/yM2kptLOOj6k=",
version = "v0.0.0-20200716043226-5a94efb202d5",
)
go_repository(
name = "com_github_dgrijalva_jwt_go",
importpath = "github.com/dgrijalva/jwt-go",
@ -202,8 +208,8 @@ def go_repositories():
go_repository(
name = "com_github_golang_protobuf",
importpath = "github.com/golang/protobuf",
sum = "h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=",
version = "v1.3.1",
sum = "h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=",
version = "v1.3.2",
)
go_repository(
name = "com_github_google_btree",
@ -217,6 +223,18 @@ def go_repositories():
sum = "h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=",
version = "v0.3.0",
)
go_repository(
name = "com_github_google_go_github_v32",
importpath = "github.com/google/go-github/v32",
sum = "h1:GWkQOdXqviCPx7Q7Fj+KyPoGm4SwHRh8rheoPhd27II=",
version = "v32.1.0",
)
go_repository(
name = "com_github_google_go_querystring",
importpath = "github.com/google/go-querystring",
sum = "h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=",
version = "v1.0.0",
)
go_repository(
name = "com_github_google_gofuzz",
importpath = "github.com/google/gofuzz",
@ -409,12 +427,6 @@ def go_repositories():
sum = "h1:F9x/1yl3T2AeKLr2AMdilSD8+f9bvMnNN8VS5iDtovc=",
version = "v0.0.0-20161129095857-cc309e4a2223",
)
go_repository(
name = "com_github_niemeyer_pretty",
importpath = "github.com/niemeyer/pretty",
sum = "h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=",
version = "v0.0.0-20200227124842-a10e7caefd8e",
)
go_repository(
name = "com_github_oklog_ulid",
importpath = "github.com/oklog/ulid",
@ -622,8 +634,8 @@ def go_repositories():
go_repository(
name = "in_gopkg_check_v1",
importpath = "gopkg.in/check.v1",
sum = "h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=",
version = "v1.0.0-20200902074654-038fdea0a05b",
sum = "h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=",
version = "v1.0.0-20180628173108-788fd7840127",
)
go_repository(
name = "in_gopkg_errgo_v2",
@ -688,8 +700,8 @@ def go_repositories():
go_repository(
name = "org_golang_x_crypto",
importpath = "golang.org/x/crypto",
sum = "h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=",
version = "v0.0.0-20200820211705-5c72a883971a",
sum = "h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=",
version = "v0.0.0-20200622213623-75b288015ac9",
)
go_repository(
name = "org_golang_x_exp",
@ -700,8 +712,8 @@ def go_repositories():
go_repository(
name = "org_golang_x_lint",
importpath = "golang.org/x/lint",
sum = "h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=",
version = "v0.0.0-20200302205851-738671d3881b",
sum = "h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=",
version = "v0.0.0-20190930215403-16217165b5de",
)
go_repository(
name = "org_golang_x_mod",
@ -730,8 +742,8 @@ def go_repositories():
go_repository(
name = "org_golang_x_sys",
importpath = "golang.org/x/sys",
sum = "h1:L/IKR6COd7ubZrs2oTnTi73IhgqJ71c9s80WsQnh0Es=",
version = "v0.0.0-20200923182605-d9f96fdee20d",
sum = "h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=",
version = "v0.0.0-20200323222414-85ca7c5b95cd",
)
go_repository(
name = "org_golang_x_text",
@ -748,8 +760,8 @@ def go_repositories():
go_repository(
name = "org_golang_x_tools",
importpath = "golang.org/x/tools",
sum = "h1:VUw1+Jf6KJPf82mbTQMia6HCnNMv2BbAipkEZ4KTcqQ=",
version = "v0.0.0-20200923182640-463111b69878",
sum = "h1:xLt+iB5ksWcZVxqc+g9K41ZHy+6MKWfXCDsjSThnsPA=",
version = "v0.0.0-20200904185747-39188db58858",
)
go_repository(
name = "org_golang_x_xerrors",
@ -760,8 +772,8 @@ def go_repositories():
go_repository(
name = "org_uber_go_atomic",
importpath = "go.uber.org/atomic",
sum = "h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=",
version = "v1.7.0",
sum = "h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY=",
version = "v1.5.0",
)
go_repository(
name = "org_uber_go_dig",
@ -784,8 +796,8 @@ def go_repositories():
go_repository(
name = "org_uber_go_multierr",
importpath = "go.uber.org/multierr",
sum = "h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=",
version = "v1.6.0",
sum = "h1:f3WCSC2KzAcBXGATIxAB1E2XuCpNU255wNKZ505qi3E=",
version = "v1.4.0",
)
go_repository(
name = "org_uber_go_tools",

10
go.mod
View file

@ -4,18 +4,14 @@ go 1.15
require (
github.com/bwmarrin/discordgo v0.22.0
github.com/dghubble/trie v0.0.0-20200716043226-5a94efb202d5
github.com/facebook/ent v0.4.3
github.com/google/go-github/v32 v32.1.0
github.com/joho/godotenv v1.3.0
github.com/julienschmidt/httprouter v1.3.0
github.com/lampjaw/discordclient v0.0.0-20200923011548-6558fc9e89df
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/segmentio/ksuid v1.0.3
go.uber.org/fx v1.13.1
go.uber.org/multierr v1.6.0 // indirect
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a // indirect
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d // indirect
golang.org/x/tools v0.0.0-20200923182640-463111b69878 // indirect
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be
k8s.io/klog v1.0.0
)

44
go.sum
View file

@ -19,10 +19,11 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
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/trie v0.0.0-20200716043226-5a94efb202d5 h1:euE/xPG0HIg6XiNXYrAHxX9aVwD1gw/yM2kptLOOj6k=
github.com/dghubble/trie v0.0.0-20200716043226-5a94efb202d5/go.mod h1:xNBeoT4V92/aNvuC3IJ2g59uxuKP4/kzvkpoHrb7v4A=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/facebook/ent v0.4.3 h1:ds9HENceKzpGBgCRlkZNq6TqBIegwKcF3e5reuV9Z0M=
@ -47,14 +48,19 @@ github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4er
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
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/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-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
github.com/google/go-github/v32 v32.1.0 h1:GWkQOdXqviCPx7Q7Fj+KyPoGm4SwHRh8rheoPhd27II=
github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI=
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
@ -68,7 +74,6 @@ github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/julienschmidt/httprouter v1.2.0 h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
@ -77,13 +82,13 @@ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQL
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
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/lampjaw/discordclient v0.0.0-20200923011548-6558fc9e89df h1:Y2o9fEOoAYjCw8IDyxUVaBq44AUbOLyPnYSPpM6Ef3M=
github.com/lampjaw/discordclient v0.0.0-20200923011548-6558fc9e89df/go.mod h1:lOfqvGl1HcXws86Sczusw1DyV5d0KHPtTTtdjneekto=
github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg=
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
@ -99,8 +104,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8=
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
@ -154,8 +157,6 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/dig v1.10.0 h1:yLmDDj9/zuDjv3gz8GQGviXMs9TfysIUMUilCpgzUJY=
go.uber.org/dig v1.10.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw=
go.uber.org/fx v1.13.1 h1:CFNTr1oin5OJ0VCZ8EycL3wzF29Jz2g0xe55RFsf2a4=
@ -165,34 +166,24 @@ go.uber.org/goleak v0.10.0/go.mod h1:VCZuO8V8mFPlL0F5J5GK1rtHV3DrFcQ1R8ryq7FK0aI
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.4.0 h1:f3WCSC2KzAcBXGATIxAB1E2XuCpNU255wNKZ505qi3E=
go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16 h1:y6ce7gCWtnH+m3dCjzQ1PCuwl28DDIc3VNnvY29DlIA=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
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-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422 h1:QzoH/1pFpZguR8NrRHLcO6jKqfv2zpuSqZLgdm7ZmjI=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -200,12 +191,13 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/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 h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
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-20190522155817-f3200d17e092/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-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
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=
@ -217,14 +209,11 @@ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
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-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d h1:L/IKR6COd7ubZrs2oTnTi73IhgqJ71c9s80WsQnh0Es=
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@ -240,11 +229,8 @@ golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191030062658-86caa796c7ab/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191114200427-caa0b0f7d508/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.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200904185747-39188db58858 h1:xLt+iB5ksWcZVxqc+g9K41ZHy+6MKWfXCDsjSThnsPA=
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/tools v0.0.0-20200923182640-463111b69878 h1:VUw1+Jf6KJPf82mbTQMia6HCnNMv2BbAipkEZ4KTcqQ=
golang.org/x/tools v0.0.0-20200923182640-463111b69878/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
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-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
@ -257,11 +243,9 @@ google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
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/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=

25
hack/generate_versions.sh Normal file
View file

@ -0,0 +1,25 @@
#!/bin/bash
artifacts=$(bazel query //src/... 2>/dev/null | grep +publish)
publishedServices=${artifacts//$'//src/'/}
publishedServices=${publishedServices//$':+publish'/}
artifactList=$'{ "services": {} }'
getSha() {
service=$1
cat ./bazel-bin/src/$service/+publish.digest
}
addShaToServiceList() {
service=$1
shaSum=$2
artifactList=$(echo $artifactList | jq ".services+={\"${service}\":\"${shaSum}\"}")
}
for service in $publishedServices; do
shaSum=$(getSha $service)
addShaToServiceList $service $shaSum
done
echo $artifactList | jq

21
src/common/BUILD.bazel Normal file
View file

@ -0,0 +1,21 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "common",
srcs = [
"await-exit.go",
"envconfig.go",
"finders.go",
],
importpath = "github.com/roleypoly/roleypoly/src/common",
visibility = ["//visibility:public"],
)
go_test(
name = "common_test",
srcs = [
"envconfig_test.go",
"finders_test.go",
],
embed = [":common"],
)

19
src/common/await-exit.go Normal file
View file

@ -0,0 +1,19 @@
package common
import (
"os"
"os/signal"
"syscall"
)
func AwaitExit() {
syscallExit := make(chan os.Signal, 1)
signal.Notify(
syscallExit,
syscall.SIGINT,
syscall.SIGTERM,
os.Interrupt,
os.Kill,
)
<-syscallExit
}

View file

@ -0,0 +1,18 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "bot",
srcs = [
"commandmux.go",
"scaffolding.go",
],
importpath = "github.com/roleypoly/roleypoly/src/common/bot",
visibility = ["//visibility:public"],
deps = [
"//src/common",
"@com_github_bwmarrin_discordgo//:discordgo",
"@com_github_dghubble_trie//:trie",
"@com_github_lampjaw_discordclient//:discordclient",
"@io_k8s_klog//:klog",
],
)

View file

@ -0,0 +1,87 @@
package bot
import (
"context"
"regexp"
"strings"
"github.com/dghubble/trie"
"github.com/lampjaw/discordclient"
"k8s.io/klog"
)
type CommandMux struct {
commandTrie *trie.PathTrie
matcher *regexp.Regexp
}
func NewCommandMux(matcher *regexp.Regexp) CommandMux {
return CommandMux{
commandTrie: trie.NewPathTrie(),
matcher: matcher,
}
}
type CommandGroup []Command
func (cg CommandGroup) RegisterCommands(commandTrie *trie.PathTrie, prefix string) {
for _, command := range cg {
commandTrie.Put(prefix+"/"+command.CommandName, command.Handler)
}
}
type Command struct {
CommandName string
Handler HandlerFunc
}
func (c CommandMux) RegisterCommandGroup(prefix string, group CommandGroup) {
group.RegisterCommands(c.commandTrie, prefix)
}
func (c CommandMux) Handler(ctx context.Context, message discordclient.Message) {
if !c.matches(message) {
return
}
key := c.commandKeyFromMessage(message)
command := c.commandTrie.Get(key)
if command == nil {
return
}
handlerFn, ok := command.(HandlerFunc)
if !ok {
klog.Warning("CommandMux.Handler: " + key + " handler was not HandlerFunc")
return
}
c.logCommandRun(key, message)
handlerFn(ctx, message)
}
func (c CommandMux) commandKeyFromMessage(message discordclient.Message) string {
commandParts := strings.Split(message.RawMessage(), " ")[1:]
return commandParts[0] + "/" + commandParts[1]
}
func (c CommandMux) matches(message discordclient.Message) bool {
return c.matcher.MatchString(message.RawMessage())
}
func (c CommandMux) logCommandRun(key string, message discordclient.Message) {
klog.Info("CommandMux: " + key + " by " + message.UserName() + " <@" + message.UserID() + ">")
}
func PrefixMatcher(prefix string) *regexp.Regexp {
return regexp.MustCompile(`^` + prefix)
}
func MentionMatcher(userID string) *regexp.Regexp {
return regexp.MustCompile(`<@!?` + userID + ">")
}
func Tokenize(message discordclient.Message) []string {
return strings.SplitAfterN(message.RawMessage(), " ", 3)
}

View file

@ -0,0 +1,101 @@
package bot
import (
"context"
"github.com/bwmarrin/discordgo"
"github.com/lampjaw/discordclient"
"github.com/roleypoly/roleypoly/src/common"
)
type HandlerFunc func(context.Context, discordclient.Message)
type BotScaffolding struct {
BotToken string
BotClientID string
RootUsers []string
AllowBots bool
AllowEdits bool
AllowDeletes bool
GatewayIntents discordgo.Intent
Handler HandlerFunc
}
type Listener struct {
DiscordClient *discordclient.DiscordClient
config *BotScaffolding
handler HandlerFunc
}
type ctxKey string
var ListenerCtxKey ctxKey = "listener"
var MessageCtxKey ctxKey = "message"
func ScaffoldBot(config BotScaffolding) error {
discordClient := discordclient.NewDiscordClient(config.BotToken, config.RootUsers[0], config.BotClientID)
discordClient.GatewayIntents = config.GatewayIntents
discordClient.AllowBots = config.AllowBots
messageChannel, err := discordClient.Listen(-1)
if err != nil {
return err
}
defer common.AwaitExit()
listener := &Listener{
config: &config,
DiscordClient: discordClient,
handler: config.Handler,
}
go listener.processMessages(messageChannel)
return nil
}
func (l *Listener) processMessages(messageChannel <-chan discordclient.Message) {
listenerCtx := context.WithValue(context.Background(), ListenerCtxKey, l)
for {
message := <-messageChannel
if !l.config.AllowEdits && message.Type() == discordclient.MessageTypeUpdate {
continue
}
if !l.config.AllowDeletes && message.Type() == discordclient.MessageTypeDelete {
continue
}
localCtx := context.WithValue(listenerCtx, MessageCtxKey, message)
go l.handler(localCtx, message)
}
}
// ReplyToMessage will use the message context to reply to a message.
// Message may be one of two types:
// - *discordgo.MessageSend
// - string
func ReplyToMessage(listenerCtx context.Context, message interface{}) error {
l := listenerCtx.Value(ListenerCtxKey).(*Listener)
m := listenerCtx.Value(MessageCtxKey).(discordclient.Message)
channelID := m.Channel()
switch message.(type) {
case *discordgo.MessageSend:
_, err := l.DiscordClient.Session.ChannelMessageSendComplex(channelID, message.(*discordgo.MessageSend))
if err != nil {
return err
}
case string:
return l.DiscordClient.SendMessage(channelID, message.(string))
}
return nil
}
// NoOpHandlerFunc does no operations againdst a message. This can be an equivalent to nil.
func NoOpHandlerFunc(context.Context, discordclient.Message) {
}

65
src/common/envconfig.go Normal file
View file

@ -0,0 +1,65 @@
package common
import (
"encoding/json"
"os"
"strconv"
"strings"
)
// GetenvValue is a holder type for Getenv to translate any Getenv strings to real types
type GetenvValue struct {
value string
}
func Getenv(key string, defaultValue ...string) GetenvValue {
value := ""
if len(defaultValue) > 0 {
value = defaultValue[0]
}
envValue := os.Getenv(key)
if envValue != "" {
value = envValue
}
return GetenvValue{
value: strings.TrimSpace(value),
}
}
func (g GetenvValue) String() string {
return g.value
}
func (g GetenvValue) StringSlice(optionalDelimiter ...string) []string {
delimiter := ","
if len(optionalDelimiter) > 0 {
delimiter = optionalDelimiter[0]
}
return strings.Split(g.value, delimiter)
}
func (g GetenvValue) Bool() bool {
lowercaseValue := strings.ToLower(g.value)
if g.value == "1" || lowercaseValue == "true" || lowercaseValue == "yes" {
return true
} else {
return false
}
}
func (g GetenvValue) Number() int {
result, err := strconv.Atoi(g.value)
if err != nil {
return -999999
}
return result
}
func (g GetenvValue) JSON(target interface{}) error {
return json.Unmarshal([]byte(g.value), target)
}

View file

@ -0,0 +1,123 @@
package common_test
import (
"os"
"testing"
"github.com/roleypoly/roleypoly/src/common"
)
var (
testEnv = map[string]string{
"string": "hello world",
"slice": "hello,world",
"slice_no_delim": "hello world",
"slice_set_delim": "hello|world",
"number": "10005",
"number_bad": "abc123",
"bool": "true",
"bool_bad": "truth",
"bool_no": "false",
"bool_number": "1",
"json": `{"hello":"world","arr":[1,2,3]}`,
}
)
func TestMain(m *testing.M) {
for key, value := range testEnv {
os.Setenv("test__"+key, value)
}
m.Run()
}
func TestEnvconfigString(t *testing.T) {
testStr := common.Getenv("test__string").String()
if testStr != testEnv["string"] {
t.FailNow()
}
}
func TestEnvconfigStringSlice(t *testing.T) {
testSl := common.Getenv("test__slice").StringSlice()
if testSl[0] != "hello" || testSl[1] != "world" {
t.FailNow()
}
}
func TestEnvconfigStringSliceNoDelimeter(t *testing.T) {
testSl := common.Getenv("test__slice_no_delim").StringSlice()
if testSl[0] != testEnv["slice_no_delim"] {
t.FailNow()
}
}
func TestEnvconfigStringSliceSetDelimeter(t *testing.T) {
testSl := common.Getenv("test__slice_set_delim").StringSlice("|")
if testSl[0] != "hello" || testSl[1] != "world" {
t.FailNow()
}
}
func TestEnvconfigNumber(t *testing.T) {
testNum := common.Getenv("test__number").Number()
if testNum != 10005 {
t.FailNow()
}
}
func TestEnvconfigNumberBad(t *testing.T) {
testNum := common.Getenv("test__number_bad").Number()
if testNum != -999999 {
t.FailNow()
}
}
func TestEnvconfigBool(t *testing.T) {
testBool := common.Getenv("test__bool").Bool()
if !testBool {
t.FailNow()
}
}
func TestEnvconfigBoolBad(t *testing.T) {
testBool := common.Getenv("test__bool_bad").Bool()
if testBool {
t.FailNow()
}
}
func TestEnvconfigBoolFalse(t *testing.T) {
testBool := common.Getenv("test__bool_no").Bool()
if testBool {
t.FailNow()
}
}
func TestEnvconfigBoolNumber(t *testing.T) {
testBool := common.Getenv("test__bool_number").Bool()
if !testBool {
t.FailNow()
}
}
func TestEnvconfigDefault(t *testing.T) {
testBool := common.Getenv("test__thing_that_doesnt_exist", "yes").Bool()
if !testBool {
t.FailNow()
}
}
type testJSONData struct {
Hello string `json:"hello,omitempty"`
Arr []int `json:"arr,omitempty"`
}
func TestEnvconfigJSON(t *testing.T) {
data := testJSONData{}
err := common.Getenv("test__json").JSON(&data)
if err != nil || data.Hello != "world" || len(data.Arr) != 3 {
t.FailNow()
}
}

12
src/common/finders.go Normal file
View file

@ -0,0 +1,12 @@
package common
// FindString returns true if needle is in haystack
func FindString(needle string, haystack []string) bool {
for _, str := range haystack {
if str == needle {
return true
}
}
return false
}

View file

@ -0,0 +1,17 @@
package common_test
import (
"testing"
"github.com/roleypoly/roleypoly/src/common"
)
func TestFindString(t *testing.T) {
if !common.FindString("hello", []string{"hello", "world"}) {
t.FailNow()
}
if common.FindString("foo", []string{"a", "b", "c"}) {
t.FailNow()
}
}

View file

@ -11,6 +11,8 @@ go_library(
importpath = "github.com/roleypoly/roleypoly/src/discord-bot",
visibility = ["//visibility:private"],
deps = [
"//src/common",
"//src/common/bot",
"//src/common/version",
"//src/discord-bot/internal/strings",
"@com_github_bwmarrin_discordgo//:discordgo",

View file

@ -1,47 +1,37 @@
package main
import (
"os"
"os/signal"
"regexp"
"strings"
"syscall"
"github.com/bwmarrin/discordgo"
_ "github.com/joho/godotenv/autoload"
"github.com/lampjaw/discordclient"
"github.com/roleypoly/roleypoly/src/common"
"github.com/roleypoly/roleypoly/src/common/bot"
"github.com/roleypoly/roleypoly/src/common/version"
"k8s.io/klog"
)
var (
botToken = os.Getenv("DISCORD_BOT_TOKEN")
botClientID = os.Getenv("DISCORD_CLIENT_ID")
rootUsers = strings.Split(os.Getenv("ROOT_USERS"), ",")
allowedBots = strings.Split(os.Getenv("ALLOWED_BOTS"), ",")
appURL = os.Getenv("PUBLIC_URL")
selfMention = regexp.MustCompile("<@!?" + botClientID + ">")
botToken = common.Getenv("DISCORD_BOT_TOKEN").String()
botClientID = common.Getenv("DISCORD_CLIENT_ID").String()
rootUsers = common.Getenv("ROOT_USERS").StringSlice()
allowedBots = common.Getenv("ALLOWED_BOTS").StringSlice()
appURL = common.Getenv("PUBLIC_URL").String()
selfMention = bot.MentionMatcher(botClientID)
)
func main() {
klog.Info(version.StartupInfo("discord-bot"))
discordClient := discordclient.NewDiscordClient(botToken, rootUsers[0], botClientID)
discordClient.GatewayIntents = discordgo.IntentsGuildMessages
messageChannel, err := discordClient.Listen(-1)
err := bot.ScaffoldBot(bot.BotScaffolding{
RootUsers: rootUsers,
AllowBots: true,
BotClientID: botClientID,
BotToken: botToken,
GatewayIntents: discordgo.IntentsGuildMessages,
Handler: handle,
})
if err != nil {
klog.Fatal(err)
}
defer awaitExit()
l := listener{
client: discordClient,
}
go l.processMessages(messageChannel)
}
func isBotAllowlisted(userID string) bool {
@ -53,15 +43,3 @@ func isBotAllowlisted(userID string) bool {
return false
}
func awaitExit() {
syscallExit := make(chan os.Signal, 1)
signal.Notify(
syscallExit,
syscall.SIGINT,
syscall.SIGTERM,
os.Interrupt,
os.Kill,
)
<-syscallExit
}

View file

@ -1,28 +1,16 @@
package main
import (
"context"
"github.com/lampjaw/discordclient"
"k8s.io/klog"
"github.com/roleypoly/roleypoly/src/common/bot"
"github.com/roleypoly/roleypoly/src/discord-bot/internal/strings"
)
type listener struct {
client *discordclient.DiscordClient
}
func (l *listener) processMessages(messageChannel <-chan discordclient.Message) {
for {
go l.handle(<-messageChannel)
}
}
func (l *listener) handle(message discordclient.Message) {
// Only if it's a message create
if message.Type() != discordclient.MessageTypeCreate {
return
}
func handle(ctx context.Context, message discordclient.Message) {
// Only if it's an allowed bot
if message.IsBot() && !isBotAllowlisted(message.UserID()) {
return
@ -33,21 +21,17 @@ func (l *listener) handle(message discordclient.Message) {
return
}
l.defaultResponse(message)
bot.ReplyToMessage(ctx, defaultResponse(message))
}
func (l *listener) defaultResponse(message discordclient.Message) {
channel := message.Channel()
func defaultResponse(message discordclient.Message) string {
guild, err := message.ResolveGuildID()
if err != nil {
klog.Warning("failed to fetch guild, ", err)
}
l.client.SendMessage(
channel,
strings.Render(
strings.MentionResponse,
strings.MentionResponseData{GuildID: guild, AppURL: appURL},
),
return strings.Render(
strings.MentionResponse,
strings.MentionResponseData{GuildID: guild, AppURL: appURL},
)
}

41
src/midori/BUILD.bazel Normal file
View file

@ -0,0 +1,41 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
load("@io_bazel_rules_docker//go:image.bzl", "go_image")
load("@io_bazel_rules_docker//container:container.bzl", "container_push")
go_library(
name = "midori_lib",
srcs = ["midori.go"],
importpath = "github.com/roleypoly/roleypoly/src/midori",
visibility = ["//visibility:private"],
deps = [
"//src/common/bot",
"//src/common/version",
"//src/midori/internal/commands/gh",
"//src/midori/internal/commands/tfc",
"//src/midori/internal/config",
"@com_github_bwmarrin_discordgo//:discordgo",
"@com_github_joho_godotenv//autoload",
"@io_k8s_klog//:klog",
],
)
go_binary(
name = "midori",
embed = [":midori_lib"],
visibility = ["//visibility:public"],
)
go_image(
name = "image",
embed = [":midori_lib"],
visibility = ["//visibility:private"],
)
container_push(
name = "+publish",
format = "Docker",
image = ":image",
registry = "docker.pkg.github.com",
repository = "roleypoly/roleypoly/midori",
tag = "{STABLE_GIT_BRANCH}",
)

5
src/midori/README.md Normal file
View file

@ -0,0 +1,5 @@
# Midori
Midori is a GitOps/GitHub Actions/Terraform Cloud helper bot. In it's simplest form, it is a hotline into GitHub Actions and Terraform Cloud to run and act upon the actual pipelines and such.
This is **not** a public bot for very obvious reasons. You may host it yourself, but it is not a required part of a Roleypoly deployment.

View file

@ -0,0 +1,16 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "gh",
srcs = ["gh.go"],
importpath = "github.com/roleypoly/roleypoly/src/midori/internal/commands/gh",
visibility = ["//src/midori:__subpackages__"],
deps = [
"//src/common/bot",
"//src/midori/internal/commands/helpers",
"//src/midori/internal/config",
"@com_github_google_go_github_v32//github:go_default_library",
"@com_github_lampjaw_discordclient//:discordclient",
"@org_golang_x_oauth2//:oauth2",
],
)

View file

@ -0,0 +1,51 @@
package gh
import (
"context"
"encoding/json"
"strings"
"github.com/google/go-github/v32/github"
"github.com/lampjaw/discordclient"
"github.com/roleypoly/roleypoly/src/common/bot"
"github.com/roleypoly/roleypoly/src/midori/internal/commands/helpers"
"github.com/roleypoly/roleypoly/src/midori/internal/config"
"golang.org/x/oauth2"
)
type GitHubCommands struct {
ghClient *github.Client
}
func NewGitHubCommands() GitHubCommands {
ctx := context.Background()
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: config.GitHubToken},
)
tc := oauth2.NewClient(ctx, ts)
ghClient := github.NewClient(tc)
return GitHubCommands{
ghClient: ghClient,
}
}
func (ghc GitHubCommands) CommandGroup() bot.CommandGroup {
return bot.CommandGroup{
{
CommandName: "dispatch",
Handler: helpers.MustHaveElevatedPermissions(ghc.dispatch),
},
}
}
func (ghc GitHubCommands) dispatch(ctx context.Context, message discordclient.Message) {
tokens := bot.Tokenize(message)
repo, webhookName := tokens[0], tokens[1]
payload := json.RawMessage(strings.Join(tokens[2:], " "))
ghc.ghClient.Repositories.Dispatch(ctx, config.GitHubOrg, repo, github.DispatchRequestOptions{
EventType: webhookName,
ClientPayload: &payload,
})
}

View file

@ -0,0 +1,14 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "helpers",
srcs = ["permissions.go"],
importpath = "github.com/roleypoly/roleypoly/src/midori/internal/commands/helpers",
visibility = ["//src/midori:__subpackages__"],
deps = [
"//src/common",
"//src/common/bot",
"//src/midori/internal/config",
"@com_github_lampjaw_discordclient//:discordclient",
],
)

View file

@ -0,0 +1,27 @@
package helpers
import (
"context"
"github.com/lampjaw/discordclient"
"github.com/roleypoly/roleypoly/src/common"
"github.com/roleypoly/roleypoly/src/common/bot"
"github.com/roleypoly/roleypoly/src/midori/internal/config"
)
// MustHaveElevatedPermissions ensures a command has either Developer or Root role conditions.
func MustHaveElevatedPermissions(next bot.HandlerFunc) bot.HandlerFunc {
return func(ctx context.Context, message discordclient.Message) {
if common.FindString(message.UserID(), config.RootUsers) || common.FindString(message.UserID(), config.AllowlistedUsers) {
next(ctx, message)
return
}
NoPermissionsResponse(ctx, message)
}
}
// NoPermissionsResponse responds with a simple message that shows why the command failed.
func NoPermissionsResponse(ctx context.Context, message discordclient.Message) {
bot.ReplyToMessage(ctx, "⛔ You do not have elevated permissions.")
}

View file

@ -0,0 +1,13 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "tfc",
srcs = ["tfc.go"],
importpath = "github.com/roleypoly/roleypoly/src/midori/internal/commands/tfc",
visibility = ["//src/midori:__subpackages__"],
deps = [
"//src/common/bot",
"//src/midori/internal/commands/helpers",
"@com_github_lampjaw_discordclient//:discordclient",
],
)

View file

@ -0,0 +1,25 @@
package tfc
import (
"context"
"github.com/lampjaw/discordclient"
"github.com/roleypoly/roleypoly/src/common/bot"
"github.com/roleypoly/roleypoly/src/midori/internal/commands/helpers"
)
type TerraformCloudCommands struct {
}
func (tfcc TerraformCloudCommands) CommandGroup() bot.CommandGroup {
return bot.CommandGroup{
{
CommandName: "dispatch",
Handler: helpers.MustHaveElevatedPermissions(tfcc.dispatch),
},
}
}
func (tfcc TerraformCloudCommands) dispatch(ctx context.Context, message discordclient.Message) {
bot.ReplyToMessage(ctx, "Ok!")
}

View file

@ -0,0 +1,9 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "config",
srcs = ["config.go"],
importpath = "github.com/roleypoly/roleypoly/src/midori/internal/config",
visibility = ["//src/midori:__subpackages__"],
deps = ["//src/common"],
)

View file

@ -0,0 +1,15 @@
package config
import (
"github.com/roleypoly/roleypoly/src/common"
)
var (
BotToken = common.Getenv("MIDORI_BOT_TOKEN").String()
ClientID = common.Getenv("MIDORI_CLIENT_ID").String()
AllowlistedUsers = common.Getenv("MIDORI_DEVELOPERS").StringSlice()
CommandPrefix = common.Getenv("MIDORI_PREFIX_OVERRIDE", "midori").String()
RootUsers = common.Getenv("ROOT_USERS").StringSlice()
GitHubOrg = common.Getenv("MIDORI_GITHUB_ORG").String()
GitHubToken = common.Getenv("MIDORI_GITHUB_TOKEN").String()
)

33
src/midori/midori.go Normal file
View file

@ -0,0 +1,33 @@
package main
import (
"github.com/bwmarrin/discordgo"
_ "github.com/joho/godotenv/autoload"
"k8s.io/klog"
"github.com/roleypoly/roleypoly/src/common/bot"
"github.com/roleypoly/roleypoly/src/common/version"
"github.com/roleypoly/roleypoly/src/midori/internal/commands/gh"
"github.com/roleypoly/roleypoly/src/midori/internal/commands/tfc"
"github.com/roleypoly/roleypoly/src/midori/internal/config"
)
func main() {
klog.Info(version.StartupInfo("midori"))
mux := bot.NewCommandMux(bot.MentionMatcher(config.ClientID))
mux.RegisterCommandGroup("gh", gh.GitHubCommands{}.CommandGroup())
mux.RegisterCommandGroup("tfc", tfc.TerraformCloudCommands{}.CommandGroup())
err := bot.ScaffoldBot(bot.BotScaffolding{
AllowBots: false,
BotToken: config.BotToken,
BotClientID: config.ClientID,
RootUsers: config.RootUsers,
GatewayIntents: discordgo.IntentsGuildMessages,
Handler: mux.Handler,
})
if err != nil {
klog.Fatal(err)
}
}