Author SHA1 Message Date
Dustin Pianalto 68055b45ce Update actions
CI / build (push) Has been cancelled
2021-02-18 23:30:10 -09:00
Dustin Pianalto fabddd00a2 Add member join and remove logging
CI / build (push) Has been cancelled
2021-02-18 23:18:20 -09:00
Dustin Pianalto 33e1552ce1 Initial DO workflow test
CI / build (push) Has been cancelled
2021-01-13 01:02:53 -09:00
Dustin Pianalto d81af99e36 Add method to move links to link channel
CI / build (push) Has been cancelled
2020-12-12 00:43:23 -09:00
Dustin Pianalto 70cf457e6f Add method to move links to link channel
CI / build (push) Has been cancelled
2020-12-12 00:35:27 -09:00
Dustin Pianalto 311497086e Change name of event handler
CI / build (push) Has been cancelled
2020-11-18 23:05:05 -09:00
Dustin Pianalto f41bd63fcd Add case where there is a / after ref 2020-11-18 21:11:44 -09:00
Dustin Pianalto d3388aadc7 Fix bug related to www
CI / build (push) Has been cancelled
2020-11-14 01:24:28 -09:00
Dustin Pianalto 7e39589e09 Use user's nick if exists
CI / build (push) Has been cancelled
2020-11-14 01:14:34 -09:00
Dustin Pianalto 9a1f56b2f0 Add github actions
CI / build (push) Has been cancelled
2020-11-14 00:46:51 -09:00
Dustin Pianalto 7b63fbeaf6 Add base structure and url webhook logic 2020-11-14 00:42:37 -09:00
Dusty.P 98dfe5455a Initial commit 2020-11-13 15:00:42 -09:00
18 changed files with 84 additions and 314 deletions
-5
View File
@@ -1,5 +0,0 @@
# Service release contract
Butler resolves this repository's protected source revision to verified immutable images. The platform updates only image references in the existing production Compose file and restarts only the already running application services. It preserves current environment, storage, routes, and provider configuration. It retains previous application images and restores them if readiness fails.
Migration and maintenance images are pinned when declared, but this release operation does not run database migrations or maintenance jobs. A release requiring a schema change needs the corresponding explicit platform migration first. No homelab image-pin commit is required for an ordinary compatible application release.
-12
View File
@@ -1,12 +0,0 @@
{
"version": 1,
"deployment": "prepbot-release",
"environment": "production",
"images": {
"prepbot_release_prepbot_image": {
"name": "prepbot",
"tag": "sha-{revision}"
}
},
"revision_variable": "prepbot_release_revision"
}
-6
View File
@@ -1,6 +0,0 @@
.git
.github
.gitea
.env
.idea
prepbot
-88
View File
@@ -1,88 +0,0 @@
name: Build and Push Container
on:
push:
branches:
- main
tags:
- v*
workflow_dispatch: null
pull_request:
branches:
- main
env:
REGISTRY: gitea.wayfinderak.com
IMAGE_NAME: wayfinderak/prepbot
concurrency:
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number
|| github.run_id }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
docker:
runs-on: butler-ci
steps:
- name: Checkout
uses: https://github.com/actions/checkout@v4
- name: Select relevant delivery work
id: delivery
env:
DELIVERY_EVENT: ${{ github.event_name }}
DELIVERY_REF: ${{ github.ref }}
DELIVERY_SHA: ${{ github.sha }}
DELIVERY_BASE: ${{ github.event.pull_request.base.sha || github.event.before }}
run: |
cd .
bash scripts/ci-select.sh
- name: Set up QEMU
if: ${{ steps.delivery.outputs.run == 'true' }}
uses: https://github.com/docker/setup-qemu-action@v3
- name: Set up Docker Buildx
if: ${{ steps.delivery.outputs.run == 'true' }}
uses: https://github.com/docker/setup-buildx-action@v3
- name: Log in to Gitea registry
if: ${{ (steps.delivery.outputs.run == 'true') && github.event_name != 'pull_request' }}
uses: https://github.com/docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Prepare image tags
if: ${{ steps.delivery.outputs.run == 'true' }}
id: prep
shell: bash
run: |
short_sha="${GITHUB_SHA::7}"
tags="${REGISTRY}/${IMAGE_NAME}:sha-${short_sha}"
tags+=$'\n'"${REGISTRY}/${IMAGE_NAME}:sha-${GITHUB_SHA}"
if [[ "${GITHUB_REF_TYPE}" == "branch" && ("${GITHUB_REF_NAME}" == "master" || "${GITHUB_REF_NAME}" == "main") ]]; then
tags+=$'\n'"${REGISTRY}/${IMAGE_NAME}:latest"
fi
if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
version="${GITHUB_REF_NAME#v}"
tags+=$'\n'"${REGISTRY}/${IMAGE_NAME}:${version}"
fi
{
echo 'tags<<EOF'
echo "$tags"
echo 'EOF'
} >> "$GITHUB_OUTPUT"
- name: Build and push image
if: ${{ steps.delivery.outputs.run == 'true' }}
uses: https://github.com/docker/build-push-action@v6
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
platforms: linux/amd64,linux/arm64
tags: ${{ steps.prep.outputs.tags }}
labels: org.opencontainers.image.revision=${{ github.sha }}
+37 -49
View File
@@ -1,64 +1,52 @@
name: Build and Push Container
name: CI
# Controls when the action will run. Triggers the workflow on push to master or development
# with a tag like v1.0.0 or v1.0.0-dev
on:
push:
branches:
- master
- main
tags:
- v*
workflow_dispatch:
env:
REGISTRY: gitea.wayfinderak.com
IMAGE_NAME: wayfinderak/prepbot
tags:
- v[0-9]+.[0-9]+.[0-9]+
- v[0-9]+.[0-9]+.[0-9]+-[a-zA-Z]+
jobs:
docker:
build:
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
- name: Checkout
uses: actions/checkout@v4
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
- name: Get Version
id: get_version
uses: battila7/get-version-action@v2.0.0
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Build container image
env:
IMAGE_TAG: ${{ steps.get_version.outputs.version-without-v }}
run: docker build -t registry.digitalocean.com/djpianalto/prepbot:$IMAGE_TAG .
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Gitea registry
uses: docker/login-action@v3
- name: Install doctl
uses: digitalocean/action-doctl@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
- name: Prepare image tags
id: prep
shell: bash
run: |
short_sha="${GITHUB_SHA::7}"
tags="${REGISTRY}/${IMAGE_NAME}:sha-${short_sha}"
- name: Login to DigitalOcean Container Registry with short-lived credentials
run: doctl registry login --expiry-seconds 600
if [[ "${GITHUB_REF_TYPE}" == "branch" && ("${GITHUB_REF_NAME}" == "master" || "${GITHUB_REF_NAME}" == "main") ]]; then
tags+=$'\n'"${REGISTRY}/${IMAGE_NAME}:latest"
fi
- name: Push image to DigitalOcean Container Registry
env:
IMAGE_TAG: ${{ steps.get_version.outputs.version-without-v }}
run: docker push registry.digitalocean.com/djpianalto/prepbot:$IMAGE_TAG
if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
version="${GITHUB_REF_NAME#v}"
tags+=$'\n'"${REGISTRY}/${IMAGE_NAME}:${version}"
fi
- name: Update deployment file
run: TAG=${{ steps.get_version.outputs.version-without-v }} && sed -i 's|<IMAGE>|registry.digitalocean.com/djpianalto/prepbot:'${TAG}'|' $GITHUB_WORKSPACE/deployment.yml
{
echo 'tags<<EOF'
echo "$tags"
echo 'EOF'
} >> "$GITHUB_OUTPUT"
- name: Save DigitalOcean kubeconfig with short-lived credentials
run: doctl kubernetes cluster kubeconfig save --expiry-seconds 600 discord-bots
- name: Build and push image
uses: docker/build-push-action@v6
with:
context: .
push: true
platforms: linux/amd64,linux/arm64
tags: ${{ steps.prep.outputs.tags }}
- name: Deploy to DigitalOcean Kubernetes
run: kubectl apply -f $GITHUB_WORKSPACE/deployment.yml
- name: Verify deployment
run: kubectl rollout status deployment/prepbot
-2
View File
@@ -15,5 +15,3 @@
# vendor/
.env
portainer-app.env
+12 -10
View File
@@ -1,18 +1,20 @@
FROM golang:1.22-alpine AS builder
FROM golang:1.15-alpine as dev
WORKDIR /src
RUN apk add --no-cache ca-certificates git tzdata
WORKDIR /go/src/prepbot
COPY ./go.mod .
COPY ./go.sum .
COPY go.mod go.sum ./
RUN go mod download
COPY . .
ARG TARGETARCH=amd64
RUN CGO_ENABLED=0 GOOS=linux GOARCH=$TARGETARCH go build -o /out/prepbot ./cmd/prepbot
RUN go install github.com/dustinpianalto/prepbot/...
FROM alpine:3.20
RUN apk add --no-cache ca-certificates tzdata
CMD [ "go", "run", "cmd/prepbot/main.go"]
COPY --from=builder /out/prepbot /usr/local/bin/prepbot
from alpine
ENTRYPOINT ["/usr/local/bin/prepbot"]
WORKDIR /bin
COPY --from=dev /go/bin/prepbot ./prepbot
CMD [ "prepbot" ]
-21
View File
@@ -1,21 +0,0 @@
# Portainer deployment notes
Generated from the current Kubernetes deployment in namespace `discord-bots`. Secret values are in the local `portainer-*.env` files.
## Kubernetes source
- Deployment: `prepbot`
- Replicas: `1`
- Rolling update: maxSurge `1`, maxUnavailable `1`
- minReadySeconds: `120`
- Labels/selectors: `app=prepbot`
- Image pull secrets: `none required for Portainer stack`
## Containers
- `prepbot`: image `gitea.wayfinderak.com/wayfinderak/prepbot:latest`; env: DISCORD_TOKEN, LINK_CHANNEL, CHAT_CHANNEL; ports: none; requests: {'cpu': '1', 'memory': '512Mi'}; limits: {'cpu': '2', 'memory': '1Gi'}
## Portainer files
- `portainer-stack.yml` - Docker Compose stack to paste/use in Portainer.
- `portainer-app.env` - bot runtime secrets/env.
+4 -6
View File
@@ -6,10 +6,10 @@ import (
"os/signal"
"syscall"
"github.com/dustinpianalto/discordgo"
"github.com/bwmarrin/discordgo"
"github.com/dustinpianalto/disgoman"
"gitea.wayfinderak.com/wayfinderak/prepbot/internal/exts/members"
"gitea.wayfinderak.com/wayfinderak/prepbot/internal/exts/messages"
"github.com/dustinpianalto/prepbot/internal/exts/members"
"github.com/dustinpianalto/prepbot/internal/exts/messages"
)
func main() {
@@ -21,9 +21,7 @@ func main() {
}
dg.State.MaxMessageCount = 100
dg.StateEnabled = true
dg.LogLevel = 3
dg.Debug = false
dg.Identify = discordgo.Identify{
Intents: discordgo.MakeIntent(discordgo.IntentsAll),
}
+1 -20
View File
@@ -2,7 +2,7 @@ apiVersion: apps/v1
kind: Deployment
metadata:
name: prepbot
namespace: discord-bots
namespace: default
labels:
app: prepbot
spec:
@@ -23,28 +23,9 @@ spec:
containers:
- name: prepbot
image: <IMAGE>
resources:
requests:
memory: "512Mi"
cpu: "1"
limits:
memory: "1Gi"
cpu: "2"
env:
- name: DISCORD_TOKEN
valueFrom:
secretKeyRef:
name: prepbot
key: discord_token
- name: LINK_CHANNEL
valueFrom:
secretKeyRef:
name: prepbot
key: link_channel
- name: CHAT_CHANNEL
valueFrom:
secretKeyRef:
name: prepbot
key: chat_channel
imagePullSecrets:
- name: registry-1
-9
View File
@@ -1,9 +0,0 @@
services:
prepbot:
image: ${IMAGE:-gitea.wayfinderak.com/wayfinderak/prepbot:${IMAGE_TAG:-latest}}
container_name: prepbot
restart: unless-stopped
environment:
DISCORD_TOKEN: ${DISCORD_TOKEN}
LINK_CHANNEL: ${LINK_CHANNEL}
CHAT_CHANNEL: ${CHAT_CHANNEL}
+3 -4
View File
@@ -1,9 +1,8 @@
module gitea.wayfinderak.com/wayfinderak/prepbot
module github.com/dustinpianalto/prepbot
go 1.14
require (
github.com/bwmarrin/discordgo v0.29.0 // indirect
github.com/dustinpianalto/discordgo v0.0.4
github.com/dustinpianalto/disgoman v0.0.26
github.com/bwmarrin/discordgo v0.22.0
github.com/dustinpianalto/disgoman v0.0.15
)
+9 -16
View File
@@ -1,17 +1,10 @@
github.com/bwmarrin/discordgo v0.29.0 h1:FmWeXFaKUwrcL3Cx65c20bTRW+vOb6k8AnaP+EgjDno=
github.com/bwmarrin/discordgo v0.29.0/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
github.com/dustinpianalto/discordgo v0.0.4 h1:KlIkMzDH4jKRbs5IxeqeIXtNTDVcDi/sHV1gaKYEnPg=
github.com/dustinpianalto/discordgo v0.0.4/go.mod h1:LKY7UDCPJMChgrowLagHjDSj1gWbt3Hx+6bRFjpaVg8=
github.com/dustinpianalto/disgoman v0.0.26 h1:7p6hDbNgEehUgOHigY/lHDY4P2VklJiZmOn674ka1h0=
github.com/dustinpianalto/disgoman v0.0.26/go.mod h1:WsDb+7XIm2MJ6xhxRAiXlzSPuSYIGSr4rWRmACeoing=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/bwmarrin/discordgo v0.20.2/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q=
github.com/bwmarrin/discordgo v0.22.0 h1:uBxY1HmlVCsW1IuaPjpCGT6A2DBwRn0nvOguQIxDdFM=
github.com/bwmarrin/discordgo v0.22.0/go.mod h1:c1WtWUGN6nREDmzIpyTp/iD3VYt4Fpx+bVyfBG7JE+M=
github.com/dustinpianalto/disgoman v0.0.15 h1:kdIw6jhC82WBut7+4BarqxBw06dozU+Hu47LQzkkoGM=
github.com/dustinpianalto/disgoman v0.0.15/go.mod h1:v3FM6n+4dH9XlvO+IDx6MN3DUnGq6YVDBvy1A1k202g=
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/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
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=
+7 -5
View File
@@ -6,8 +6,8 @@ import (
"strconv"
"time"
"github.com/dustinpianalto/discordgo"
"gitea.wayfinderak.com/wayfinderak/prepbot/internal/discord_utils"
"github.com/bwmarrin/discordgo"
"github.com/dustinpianalto/prepbot/internal/discord_utils"
)
var joinChannelID = "768571410133418037"
@@ -44,6 +44,8 @@ func OnGuildMemberAddLogging(s *discordgo.Session, member *discordgo.GuildMember
Inline: false,
}
joinTime, _ := member.JoinedAt.Parse()
embed := &discordgo.MessageEmbed{
Title: title,
Description: fmt.Sprintf("%v (%v) Has Joined the Server", member.User.Mention(), member.User.ID),
@@ -51,9 +53,9 @@ func OnGuildMemberAddLogging(s *discordgo.Session, member *discordgo.GuildMember
Thumbnail: thumb,
Footer: &discordgo.MessageEmbedFooter{
Text: fmt.Sprintf("Current Member Count: %v", guild.MemberCount),
IconURL: guild.IconURL("1024"),
IconURL: guild.IconURL(),
},
Timestamp: member.JoinedAt.Format(time.RFC3339),
Timestamp: joinTime.Format(time.RFC3339),
Fields: []*discordgo.MessageEmbedField{field},
}
s.ChannelMessageSendEmbed(joinChannelID, embed)
@@ -115,7 +117,7 @@ func OnGuildMemberRemoveLogging(s *discordgo.Session, member *discordgo.GuildMem
Thumbnail: thumb,
Footer: &discordgo.MessageEmbedFooter{
Text: fmt.Sprintf("Current Member Count: %v", guild.MemberCount),
IconURL: guild.IconURL("1024"),
IconURL: guild.IconURL(),
},
Timestamp: timeNow.Format(time.RFC3339),
}
+11 -10
View File
@@ -2,12 +2,10 @@ package messages
import (
"log"
"os"
"regexp"
"strings"
neturl "net/url"
"github.com/dustinpianalto/discordgo"
"github.com/bwmarrin/discordgo"
)
func CleanAmazonURLs(s *discordgo.Session, message *discordgo.MessageCreate) {
@@ -26,11 +24,14 @@ func CleanAmazonURLs(s *discordgo.Session, message *discordgo.MessageCreate) {
if len(urls) != 0 {
for _, url := range urls {
u, _ := neturl.Parse(url)
u.RawQuery = ""
u.Fragment = ""
if ( url != u.String() ) {
content = strings.ReplaceAll(content, url, u.String())
if strings.Contains(url, "ref=") || strings.Contains(url, "?") {
parts := strings.Split(url, "/")
new := strings.Join(parts[:len(parts)-1], "/")
if strings.Contains(new, "ref=") {
parts = strings.Split(new, "ref=")
new = parts[0]
}
content = strings.ReplaceAll(content, url, new)
}
}
_, err := sendWebhook(s, message, message.ChannelID, content)
@@ -48,8 +49,8 @@ func CleanAmazonURLs(s *discordgo.Session, message *discordgo.MessageCreate) {
}
func moveNewsLinks(s *discordgo.Session, message *discordgo.MessageCreate) {
linkChannel := os.Getenv("LINK_CHANNEL")
chatChannel := os.Getenv("CHAT_CHANNEL")
linkChannel := "784855106239332352"
chatChannel := "777679317878177804"
if message.ChannelID == chatChannel {
_, err := sendWebhook(s, message, linkChannel, message.Content)
if err != nil {
-3
View File
@@ -1,3 +0,0 @@
DISCORD_TOKEN=replace-me
LINK_CHANNEL=replace-me
CHAT_CHANNEL=replace-me
-9
View File
@@ -1,9 +0,0 @@
services:
prepbot:
image: gitea.wayfinderak.com/wayfinderak/prepbot:latest
container_name: prepbot
restart: unless-stopped
env_file:
- ./portainer-app.env
mem_limit: 1g
cpus: "2.0"
-39
View File
@@ -1,39 +0,0 @@
#!/usr/bin/env bash
# Keep required jobs alive; only skip reviewed non-runtime documentation paths.
set -euo pipefail
base="${DELIVERY_BASE:-}"
head="$(git rev-parse HEAD)"
run=true
if [[ "${DELIVERY_REF:-}" != refs/tags/* && "$head" == "${DELIVERY_SHA:-}" && "${DELIVERY_EVENT:-}" =~ ^(push|pull_request)$ && "$base" =~ ^[0-9a-f]{40}$ && "$base" != 0000000000000000000000000000000000000000 ]]; then
if ! git cat-file -e "$base^{commit}" 2>/dev/null; then
if [[ -n "${DELIVERY_FETCH_TOKEN:-}" ]]; then
git -c "http.extraHeader=Authorization: token ${DELIVERY_FETCH_TOKEN}" fetch --quiet --depth=1 origin "$base" >/dev/null 2>&1 || true
else
git fetch --quiet --depth=1 origin "$base" >/dev/null 2>&1 || true
fi
fi
if git cat-file -e "$base^{commit}" 2>/dev/null; then
paths="$(mktemp)"
trap 'rm -f -- "$paths"' EXIT
# Snapshot comparison is conservative when main advanced during a PR.
# Both rename sides remain visible, including names containing newlines.
if git diff --no-renames --name-only -z "$base" "$head" > "$paths"; then
run=false
while IFS= read -r -d '' path; do
case "$path" in
README.md|CHANGELOG.md|LICENSE|LICENSE.md) ;;
*) run=true; break ;;
esac
done < "$paths"
fi
fi
fi
if [[ "$run" == false ]]; then
echo 'Only reviewed non-runtime documentation changed; build and validation are not applicable.'
else
echo 'Runtime, unknown inputs, or unavailable event history: run required validation.'
fi
if [[ -n "${GITHUB_OUTPUT:-}" ]]; then
echo "run=$run" >> "$GITHUB_OUTPUT"
fi
printf '%s\n' "$run"