Skip to content

Commit e3e7dbc

Browse files
author
Andy Ford
committed
dev: devcontainer
1 parent bbb3518 commit e3e7dbc

File tree

14 files changed

+162
-80
lines changed

14 files changed

+162
-80
lines changed

.devcontainer/devcontainer.json

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
2+
// README at: https://github.com/devcontainers/templates/tree/main/src/docker-existing-docker-compose
3+
{
4+
"name": "ECFMP Discord Docker Compose",
5+
// Update the 'dockerComposeFile' list if you have more compose files or use different names.
6+
// The .devcontainer/docker-compose.yml file contains any overrides you need/want to make.
7+
"dockerComposeFile": [
8+
"../docker-compose.yml",
9+
],
10+
// The 'service' property is the name of the service for the container that VS Code should
11+
// use. Update this value and .devcontainer/docker-compose.yml to the real service name.
12+
"service": "discord",
13+
// The optional 'workspaceFolder' property is the path VS Code should open by default when
14+
// connected. This is typically a file mount in .devcontainer/docker-compose.yml
15+
"workspaceFolder": "/app",
16+
// Features to add to the dev container. More info: https://containers.dev/features.
17+
// Use 'forwardPorts' to make a list of ports inside the container available locally.
18+
"forwardPorts": [
19+
3000,
20+
8080
21+
],
22+
// Features
23+
"features": {
24+
// git
25+
"ghcr.io/devcontainers/features/git:1": {},
26+
"ghcr.io/itsmechlark/features/1password:1": {}
27+
},
28+
// Uncomment the next line if you want start specific services in your Docker Compose config.
29+
// "runServices": [],
30+
// Uncomment the next line if you want to keep your containers running after VS Code shuts down.
31+
// "shutdownAction": "none",
32+
// Uncomment the next line to run commands after the container is created.
33+
"onCreateCommand": "go install -v golang.org/x/tools/gopls@latest",
34+
// Configure tool-specific properties.
35+
"customizations": {
36+
"vscode": {
37+
"settings": {
38+
"editor.formatOnSave": true,
39+
"files.insertFinalNewline": true,
40+
"go.useLanguageServer": true,
41+
"go.languageServerExperimentalFeatures": {
42+
"documentLink": true
43+
}
44+
},
45+
"extensions": [
46+
"ms-azuretools.vscode-docker",
47+
"golang.go",
48+
"GitHub.copilot",
49+
"ms-vscode.makefile-tools",
50+
"github.vscode-github-actions"
51+
]
52+
}
53+
}
54+
// Uncomment to connect as an existing user other than the container default. More info: https://aka.ms/dev-containers-non-root.
55+
// "remoteUser": "devcontainer"
56+
}

.dockerignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.build
2+
.devcontainer
3+
.github
4+
.vscode

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
run: make protobuf
2121

2222
- name: Start containers
23-
run: docker compose up -d --build --wait go_testing mongodb
23+
run: docker compose up -d --build --wait discord mongodb
2424

2525
- name: Run Tests
2626
run: make test

Dockerfile

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,40 @@
1-
# This stage copies all the files we need into
1+
# Base stage, sets up the GRPC Health Probe, we use a ubuntu image because no devcontainer features work on alpine
22
ARG GO_VERSION
3-
FROM golang:${GO_VERSION}-alpine AS builder
3+
FROM golang:${GO_VERSION} AS builder_base
44

55
WORKDIR /app
66

77
# Install gRPC Health Probe
88
RUN set -ex \
9-
&& apk add --no-cache curl \
109
&& curl -fSL https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/v0.4.19/grpc_health_probe-linux-amd64 -o /usr/local/bin/grpc_health_probe \
1110
&& chmod +x /usr/local/bin/grpc_health_probe
1211

12+
#######################################################
13+
# Builds the development container
14+
FROM builder_base AS development
15+
16+
# We listen on port 80 in development
17+
EXPOSE 80
18+
19+
# Health check
20+
HEALTHCHECK --interval=5s --timeout=3s --start-period=5s --retries=3 CMD [ "grpc_health_probe", "-addr", "localhost:80", "-connect-timeout", "250ms", "-rpc-timeout", "100ms" ]
21+
22+
# Create the user
23+
RUN adduser --uid 1000 appuser
24+
25+
USER appuser
26+
27+
# Install Air for live reloading
28+
RUN go install github.com/cosmtrek/air@latest
29+
30+
ENTRYPOINT ["./docker/dev-container.sh"]
31+
32+
#######################################################
33+
# Builds the production binary
34+
FROM golang:${GO_VERSION}-alpine AS builder_production
35+
36+
WORKDIR /app
37+
1338
# Go dependencies
1439
COPY go.mod go.sum ./
1540
RUN go mod download
@@ -18,22 +43,26 @@ COPY internal ./internal
1843
COPY proto ./proto
1944

2045
# Do the build
21-
RUN go build -o /cmd/ecfmp-discord ./cmd/ecfmp-discord
46+
RUN go build -o ecfmp-discord ./cmd/ecfmp-discord
2247

23-
#######################################################
48+
# Make sure the binary is executable
49+
RUN chmod +x ecfmp-discord
2450

51+
#######################################################
2552
# This container runs the actual binary in production
26-
FROM alpine:3.14 as production
53+
FROM alpine:3.18 as production
2754

28-
COPY --from=builder /cmd/ecfmp-discord /ecfmp-discord
55+
# Create the user
56+
RUN adduser -u1000 -D appuser
57+
58+
COPY --from=builder_production --chown=appuser:appuser ./app/ecfmp-discord /ecfmp-discord
59+
COPY --from=builder_base /usr/local/bin/grpc_health_probe /usr/local/bin/grpc_health_probe
2960

3061
EXPOSE 80
3162

3263
# Health check
3364
HEALTHCHECK --interval=5s --timeout=3s --start-period=5s --retries=3 CMD [ "grpc_health_probe", "-addr", "localhost:80", "-connect-timeout", "250ms", "-rpc-timeout", "100ms" ]
3465

35-
# Create the user
36-
RUN adduser -u1000 -D appuser
3766
USER appuser
3867

39-
CMD [ "/ecfmp-discord" ]
68+
ENTRYPOINT [ "/ecfmp-discord" ]

Dockerfile-dev

Lines changed: 0 additions & 31 deletions
This file was deleted.

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
GO_VERSION = 1.21
22

33
test:
4-
docker compose exec go_testing go test -v ./...
4+
docker compose exec discord go test -v ./...
55

66
protobuf:
77
cd proto && make discord_proto && make health_proto

docker-compose.yml

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ services:
33
discord:
44
build:
55
context: .
6-
dockerfile: Dockerfile-dev
6+
dockerfile: Dockerfile
77
target: development
88
args:
99
- GO_VERSION=1.21
@@ -26,30 +26,6 @@ services:
2626
networks:
2727
- default
2828

29-
go_testing:
30-
build:
31-
context: .
32-
dockerfile: Dockerfile-dev
33-
target: testing
34-
args:
35-
- GO_VERSION=1.21
36-
depends_on:
37-
- mongodb
38-
environment:
39-
MONGO_USERNAME: root
40-
MONGO_PASSWORD: example_password
41-
MONGO_DB: ecfmp_test
42-
MONGO_HOST: mongodb
43-
MONGO_PORT: 27017
44-
AUTH_JWT_PUBLIC_KEY_FILE: "./docker/dev_public_key.pub"
45-
AUTH_JWT_PRIVATE_KEY_FILE: "./docker/dev_private_key.pem"
46-
AUTH_JWT_AUDIENCE: "ecfmp-discord-dev"
47-
LOG_LEVEL: "FATAL"
48-
volumes:
49-
- .:/app
50-
networks:
51-
- default
52-
5329
mongodb:
5430
image: mongo:6.0
5531
container_name: mongodb

docker/test-container.sh

Lines changed: 0 additions & 3 deletions
This file was deleted.

go.mod

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,21 @@ require (
1111
google.golang.org/protobuf v1.31.0
1212
)
1313

14-
require github.com/gorilla/websocket v1.4.2 // indirect
14+
require (
15+
github.com/BurntSushi/toml v1.2.1 // indirect
16+
github.com/google/go-cmp v0.5.9 // indirect
17+
github.com/gorilla/websocket v1.4.2 // indirect
18+
github.com/sergi/go-diff v1.1.0 // indirect
19+
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
20+
golang.org/x/exp/typeparams v0.0.0-20221212164502-fae10dda9338 // indirect
21+
golang.org/x/mod v0.12.0 // indirect
22+
golang.org/x/tools v0.11.2-0.20230810185051-cc6b5804b8cf // indirect
23+
golang.org/x/tools/gopls v0.13.2 // indirect
24+
golang.org/x/vuln v0.0.0-20230110180137-6ad3e3d07815 // indirect
25+
honnef.co/go/tools v0.4.2 // indirect
26+
mvdan.cc/gofumpt v0.4.0 // indirect
27+
mvdan.cc/xurls/v2 v2.4.0 // indirect
28+
)
1529

1630
require (
1731
github.com/bwmarrin/discordgo v0.27.1

go.sum

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
2+
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
13
github.com/bwmarrin/discordgo v0.27.1 h1:ib9AIc/dom1E/fSIulrBwnez0CToJE113ZGt4HoliGY=
24
github.com/bwmarrin/discordgo v0.27.1/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
35
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -20,13 +22,21 @@ github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
2022
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
2123
github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
2224
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
25+
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
26+
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
27+
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
2328
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0=
2429
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
30+
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
2531
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
2632
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
33+
github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
34+
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
35+
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
2736
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
2837
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
2938
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
39+
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
3040
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
3141
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
3242
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
@@ -47,14 +57,21 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
4757
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
4858
golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
4959
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
60+
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
61+
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
62+
golang.org/x/exp/typeparams v0.0.0-20221212164502-fae10dda9338 h1:2O2DON6y3XMJiQRAS1UWU+54aec2uopH3x7MAiqGW6Y=
63+
golang.org/x/exp/typeparams v0.0.0-20221212164502-fae10dda9338/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
5064
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
65+
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
66+
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
5167
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
5268
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
5369
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
5470
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
5571
golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
5672
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
5773
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
74+
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
5875
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
5976
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
6077
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
@@ -80,6 +97,12 @@ golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
8097
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
8198
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
8299
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
100+
golang.org/x/tools v0.11.2-0.20230810185051-cc6b5804b8cf h1:Oush7UwPamr2/iNeNFBuNFj89YyHn0YY69EKDdvANnk=
101+
golang.org/x/tools v0.11.2-0.20230810185051-cc6b5804b8cf/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8=
102+
golang.org/x/tools/gopls v0.13.2 h1:Pyvx6MKvatbX3zzZmdGiFRfQZl0ohPlt2sFxO/5j6Ro=
103+
golang.org/x/tools/gopls v0.13.2/go.mod h1:oX62MpkeKkpDdUDJNgcjAvXQ5bs+QgH+L/QMkLQPgQs=
104+
golang.org/x/vuln v0.0.0-20230110180137-6ad3e3d07815 h1:A9kONVi4+AnuOr1dopsibH6hLi1Huy54cbeJxnq4vmU=
105+
golang.org/x/vuln v0.0.0-20230110180137-6ad3e3d07815/go.mod h1:XJiVExZgoZfrrxoTeVsFYrSSk1snhfpOEC95JL+A4T0=
83106
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
84107
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
85108
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U=
@@ -92,6 +115,17 @@ google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs
92115
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
93116
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
94117
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
118+
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
119+
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
120+
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
121+
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
122+
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
95123
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
96124
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
97125
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
126+
honnef.co/go/tools v0.4.2 h1:6qXr+R5w+ktL5UkwEbPp+fEvfyoMPche6GkOpGHZcLc=
127+
honnef.co/go/tools v0.4.2/go.mod h1:36ZgoUOrqOk1GxwHhyryEkq8FQWkUO2xGuSMhUCcdvA=
128+
mvdan.cc/gofumpt v0.4.0 h1:JVf4NN1mIpHogBj7ABpgOyZc65/UUOkKQFkoURsz4MM=
129+
mvdan.cc/gofumpt v0.4.0/go.mod h1:PljLOHDeZqgS8opHRKLzp2It2VBuSdteAgqUfzMTxlQ=
130+
mvdan.cc/xurls/v2 v2.4.0 h1:tzxjVAj+wSBmDcF6zBB7/myTy3gX9xvi8Tyr28AuQgc=
131+
mvdan.cc/xurls/v2 v2.4.0/go.mod h1:+GEjq9uNjqs8LQfM9nVnM8rff0OQ5Iash5rzX+N1CSg=

0 commit comments

Comments
 (0)