Pulls from git and posts to discord

This commit is contained in:
Daniel Mason 2021-09-01 21:22:09 +12:00
parent d63f121871
commit b37a425589
Signed by: idanoo
GPG key ID: 387387CDBC02F132
12 changed files with 611 additions and 5 deletions

View file

@ -0,0 +1,99 @@
package nzcovidbot
import (
"encoding/csv"
"fmt"
"strings"
)
// Slice of updated located
type UpdatedLocations struct {
Locations []UpdatedRow
}
// Updated data
type UpdatedRow struct {
ChangeType string // ADDED, REMOVED, MODIFIED
DiscordData string // Formatted Row data
TwitterData string // Formatted Row data
}
// Struct of updated locations
var updatedLocations UpdatedLocations
// parseCsvRow Build into struct for output later
func parseCsvRow(changeType string, data string) {
newRow := UpdatedRow{
ChangeType: changeType,
DiscordData: formatCsvDiscordRow(data),
TwitterData: formatCsvTwitterRow(data),
}
updatedLocations.Locations = append(updatedLocations.Locations, newRow)
}
// formatCsvDiscordRow Format the string to a tidy string for the interwebs
func formatCsvDiscordRow(data string) string {
// Split string
r := csv.NewReader(strings.NewReader(data))
r.Comma = ','
fields, err := r.Read()
if err != nil {
fmt.Println(err)
return ""
}
c := make([]string, 0)
c = append(c, fields...)
return fmt.Sprintf("**%s** %s on _%s_ - _%s_", c[1], c[2], c[4], c[5])
}
// formatCsvTwitterRow Format the string to a tidy string for the interwebs
func formatCsvTwitterRow(data string) string {
// Split string
r := csv.NewReader(strings.NewReader(data))
r.Comma = ','
fields, err := r.Read()
if err != nil {
fmt.Println(err)
return ""
}
c := make([]string, 0)
c = append(c, fields...)
return fmt.Sprintf("**%s** - %s\n_%s_ - _%s_", c[1], c[2], c[4], c[5])
}
func getPostableDiscordData() string {
if len(updatedLocations.Locations) == 0 {
return ""
}
rows := make([]string, 0)
for _, location := range updatedLocations.Locations {
if location.ChangeType == "REMOVED" {
rows = append(rows, fmt.Sprintf("REMOVED: %s", location.DiscordData))
} else {
rows = append(rows, location.DiscordData)
}
}
return strings.Join(rows, "\n\n")
}
func getPostableTwitterData() string {
if len(updatedLocations.Locations) == 0 {
return ""
}
rows := make([]string, 0)
for _, location := range updatedLocations.Locations {
if location.ChangeType == "REMOVED" {
rows = append(rows, fmt.Sprintf("REMOVED: %s", location.TwitterData))
} else {
rows = append(rows, location.TwitterData)
}
}
return strings.Join(rows, "\n\n")
}

View file

@ -0,0 +1,48 @@
package nzcovidbot
import (
"log"
"strings"
"github.com/DisgoOrg/disgohook"
"github.com/DisgoOrg/disgohook/api"
)
var (
// Slice of discord webhooks
DiscordWebhooks []string
)
func postToDiscord(webhookString string, msg string) {
tokenParts := strings.Split(webhookString, "/")
len := len(tokenParts)
webhook, err := disgohook.NewWebhookClientByToken(nil, nil, tokenParts[len-2]+"/"+tokenParts[len-1])
if err != nil {
log.Print(err)
return
}
// message, err := webhook.SendContent(msg)
// if err != nil {
// log.Print(err)
// return
// }
// // message, err = webhook.SendEmbeds(api.NewEmbedBuilder().
// // SetDescription(msg).
// // Build(),
// // )
// if err != nil {
// log.Print(err)
// return
// }
_, err = webhook.SendMessage(api.NewWebhookMessageCreateBuilder().
SetContent(msg).
Build(),
)
if err != nil {
log.Print(err)
}
}

165
internal/nzcovidbot/git.go Normal file
View file

@ -0,0 +1,165 @@
package nzcovidbot
import (
"io/ioutil"
"log"
"os"
"strings"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"github.com/waigani/diffparser"
)
// Repo URL
var gitRepo *git.Repository
// Current hash we have parsed
var commitHash string
// Location to store tmp data
var tmpDirectory = "./tmp"
func loadRepo(repository string) {
r, err := git.PlainOpen(tmpDirectory + "/repo")
if err != nil {
if err.Error() == "repository does not exist" {
r = cloneRepo(repository)
} else {
log.Fatal(err)
}
}
commitHash := getCommitHash()
log.Printf("Last reported hash: %s", commitHash)
gitRepo = r
}
func cloneRepo(repository string) *git.Repository {
if _, err := os.Stat(tmpDirectory); os.IsNotExist(err) {
err = os.Mkdir(tmpDirectory, 0755)
if err != nil {
log.Fatal(err)
}
}
r, err := git.PlainClone(tmpDirectory+"/repo", false, &git.CloneOptions{
URL: repository,
Progress: os.Stdout,
})
if err != nil {
log.Fatal(err)
}
ref, err := r.Head()
if err != nil {
log.Fatal(err)
}
setCommitHash(ref.Hash().String())
log.Println("Succesfully cloned repo")
return r
}
// Set it in memory + write to disk
func setCommitHash(hash string) error {
log.Printf("Update hash to: %s", hash)
commitHash = hash
return os.WriteFile(tmpDirectory+"/commithash", []byte(hash), 0644)
}
// Read from memory, or disk
func getCommitHash() string {
if commitHash != "" {
return commitHash
}
hash, err := ioutil.ReadFile(tmpDirectory + "/commithash")
if err != nil {
log.Fatal(err)
}
commitHash = string(hash)
return commitHash
}
func checkForUpdates() {
// Fetch updates from remote
pullOptions := git.PullOptions{
RemoteName: "origin",
}
// Pull latest changes if exist
worktree, err := gitRepo.Worktree()
if err != nil {
log.Fatal(err)
}
err = worktree.Pull(&pullOptions)
if err != nil {
if err == git.NoErrAlreadyUpToDate {
log.Println("No updates")
return
} else {
log.Fatal(err)
}
}
// Get current commit hash
head, err := gitRepo.Head()
if err != nil {
log.Fatal(err)
}
// Get latest commit
latestCommit, err := gitRepo.CommitObject(head.Hash())
if err != nil {
log.Fatal(err)
}
// Get current commit
currentCommit, err := gitRepo.CommitObject(plumbing.NewHash(getCommitHash()))
if err != nil {
log.Fatal(err)
}
// Get patch of changes
patch, err := currentCommit.Patch(latestCommit)
if err != nil {
log.Fatal(err)
}
// Parse git diff
diff, err := diffparser.Parse(patch.String())
if err != nil {
log.Fatal(err)
}
// Loop through file changes
for _, file := range diff.Files {
if strings.HasSuffix(file.NewName, ".csv") {
for _, hunk := range file.Hunks {
newRange := hunk.WholeRange
for _, line := range newRange.Lines {
if line.Mode == diffparser.ADDED {
parseCsvRow("ADDED", line.Content)
}
// switch changeType := line.Mode; changeType {
// case diffparser.UNCHANGED:
// continue
// case diffparser.ADDED:
// parseCsvRow("ADDED", line.Content)
// case diffparser.REMOVED:
// continue
// // To re-add in future?
// // parseCsvRow("REMOVED", line.Content)
// }
}
}
}
}
setCommitHash(head.Hash().String())
postTheUpdates()
}

View file

@ -0,0 +1,60 @@
package nzcovidbot
import (
"fmt"
"time"
)
var Repository string
func Lesgoooo() {
// Setup repo stuff
loadRepo(Repository)
// Create chan to end timer
endTicker := make(chan bool)
// Timer to run every minute
minuteTicker := time.NewTicker(time.Duration(15) * time.Second)
// Initial check on load
go checkForUpdates()
for {
select {
case <-endTicker:
fmt.Println("Stopping background workers")
return
case <-minuteTicker.C:
// Check for updates
go checkForUpdates()
}
}
}
func postTheUpdates() {
// Discord
postableDiscordData := getPostableDiscordData()
if postableDiscordData == "" {
return
}
for _, discordWebhook := range DiscordWebhooks {
postToDiscord(discordWebhook, postableDiscordData)
}
// Twitter
// postableTwitterData := getPostableTwitterData()
// if postableTwitterData == "" {
// return
// }
// for _, discordWebhook := range DiscordWebhooks {
// postToTwitter(discordWebhook, postableTwitterData)
// }
// Clear out posted data!
updatedLocations = UpdatedLocations{}
}

View file

@ -0,0 +1,48 @@
package nzcovidbot
import (
"log"
"github.com/dghubble/go-twitter/twitter"
"github.com/dghubble/oauth1"
)
type TwitterCredentials struct {
ConsumerKey string
ConsumerSecret string
AccessToken string
AccessTokenSecret string
}
var TwitterCreds TwitterCredentials
// getClient is a helper function that will return a twitter client
// that we can subsequently use to send tweets, or to stream new tweets
// this will take in a pointer to a Credential struct which will contain
// everything needed to authenticate and return a pointer to a twitter Client
// or an error
func getClient(creds *TwitterCredentials) (*twitter.Client, error) {
// Pass in your consumer key (API Key) and your Consumer Secret (API Secret)
config := oauth1.NewConfig(creds.ConsumerKey, creds.ConsumerSecret)
// Pass in your Access Token and your Access Token Secret
token := oauth1.NewToken(creds.AccessToken, creds.AccessTokenSecret)
httpClient := config.Client(oauth1.NoContext, token)
client := twitter.NewClient(httpClient)
// Verify Credentials
verifyParams := &twitter.AccountVerifyParams{
SkipStatus: twitter.Bool(true),
IncludeEmail: twitter.Bool(true),
}
// we can retrieve the user and verify if the credentials
// we have used successfully allow us to log in!
user, _, err := client.Accounts.VerifyCredentials(verifyParams)
if err != nil {
return nil, err
}
log.Printf("User's ACCOUNT:\n%+v\n", user)
return client, nil
}