- write to db new ticket;
- fixed telegram bot init function with telegram options;
This commit is contained in:
parent
0785ebf4df
commit
310a3d9f55
|
|
@ -1,2 +1,3 @@
|
||||||
.vscode/
|
.vscode/
|
||||||
**/**/*.env
|
**/**/*.env
|
||||||
|
docker/**
|
||||||
|
|
@ -1,29 +1,37 @@
|
||||||
package controller
|
package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"ticket-pimp/internal/domain"
|
"ticket-pimp/internal/domain"
|
||||||
"ticket-pimp/internal/services"
|
"ticket-pimp/internal/services"
|
||||||
|
db "ticket-pimp/internal/storage/db/tickets"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WorkflowController struct {
|
type WorkflowController struct {
|
||||||
iGit services.IGit
|
iGit services.IGit
|
||||||
iCloud services.ICloud
|
iCloud services.ICloud
|
||||||
iCoda services.ICoda
|
iCoda services.ICoda
|
||||||
|
db *db.Queries
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWorkflowController(
|
func NewWorkflowController(
|
||||||
git services.IGit,
|
git services.IGit,
|
||||||
cloud services.ICloud,
|
cloud services.ICloud,
|
||||||
coda services.ICoda,
|
coda services.ICoda,
|
||||||
|
db *db.Queries,
|
||||||
) *WorkflowController {
|
) *WorkflowController {
|
||||||
return &WorkflowController{
|
return &WorkflowController{
|
||||||
iGit: git,
|
iGit: git,
|
||||||
iCloud: cloud,
|
iCloud: cloud,
|
||||||
|
iCoda: coda,
|
||||||
iCoda: coda,
|
db: db,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -79,6 +87,19 @@ func (wc *WorkflowController) Workflow(name, key, id string) (string, error) {
|
||||||
} else {
|
} else {
|
||||||
cloudResult = cloud.PrivateURL
|
cloudResult = cloud.PrivateURL
|
||||||
}
|
}
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
|
insertedTicket, err := wc.db.CreateTicket(ctx, db.CreateTicketParams{
|
||||||
|
Key: pgtype.Text{String: appKey, Valid: true},
|
||||||
|
ProjectGit: pgtype.Text{String: gitResult, Valid: true},
|
||||||
|
BuildGit: pgtype.Text{String: gitBuildResult, Valid: true},
|
||||||
|
Folder: pgtype.Text{String: cloudResult, Valid: true},
|
||||||
|
CreatedAt: pgtype.Timestamptz{Time: time.Now(), InfinityModifier: 0, Valid: true},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
log.Print(insertedTicket)
|
||||||
|
|
||||||
wc.iCoda.CreateApp(domain.CodaApplication{
|
wc.iCoda.CreateApp(domain.CodaApplication{
|
||||||
ID: appKey,
|
ID: appKey,
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package handler
|
||||||
import (
|
import (
|
||||||
"ticket-pimp/bot/controller"
|
"ticket-pimp/bot/controller"
|
||||||
"ticket-pimp/internal/services"
|
"ticket-pimp/internal/services"
|
||||||
|
db "ticket-pimp/internal/storage/db/tickets"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Handler struct {
|
type Handler struct {
|
||||||
|
|
@ -12,18 +13,21 @@ type Handler struct {
|
||||||
coda services.ICoda
|
coda services.ICoda
|
||||||
key string
|
key string
|
||||||
id string
|
id string
|
||||||
|
db *db.Queries
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHandler(
|
func NewHandler(
|
||||||
git services.IGit,
|
git services.IGit,
|
||||||
cloud services.ICloud,
|
cloud services.ICloud,
|
||||||
coda services.ICoda,
|
coda services.ICoda,
|
||||||
|
db *db.Queries,
|
||||||
) *Handler {
|
) *Handler {
|
||||||
|
|
||||||
return &Handler{
|
return &Handler{
|
||||||
workflow: controller.NewWorkflowController(git, cloud, coda),
|
workflow: controller.NewWorkflowController(git, cloud, coda, db),
|
||||||
git: git,
|
git: git,
|
||||||
cloud: cloud,
|
cloud: cloud,
|
||||||
coda: coda,
|
coda: coda,
|
||||||
|
db: db,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
122
cmd/main.go
122
cmd/main.go
|
|
@ -9,8 +9,11 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
"ticket-pimp/bot/handler"
|
"ticket-pimp/bot/handler"
|
||||||
discordbot "ticket-pimp/discord-bot"
|
discordbot "ticket-pimp/discord-bot"
|
||||||
|
"ticket-pimp/internal/domain"
|
||||||
"ticket-pimp/internal/services"
|
"ticket-pimp/internal/services"
|
||||||
|
db "ticket-pimp/internal/storage/db/tickets"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5"
|
||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
"github.com/mr-linch/go-tg"
|
"github.com/mr-linch/go-tg"
|
||||||
"github.com/mr-linch/go-tg/tgb"
|
"github.com/mr-linch/go-tg/tgb"
|
||||||
|
|
@ -18,34 +21,92 @@ import (
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
log.Print("started")
|
log.Print("started")
|
||||||
env("develop.env")
|
config := env("develop.env")
|
||||||
|
run(config)
|
||||||
|
}
|
||||||
|
|
||||||
if err := runDiscrodBot(); err != nil {
|
func run(conf domain.Config) {
|
||||||
log.Fatal(fmt.Errorf("discord bot cannot be runned: %v", err))
|
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill, syscall.SIGTERM)
|
||||||
}
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
ctx, cancel := signal.NotifyContext(ctx, os.Interrupt, os.Kill, syscall.SIGTERM)
|
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := runTgBot(ctx); err != nil {
|
conn, err := pgx.Connect(
|
||||||
fmt.Println(err)
|
ctx,
|
||||||
|
fmt.Sprintf(
|
||||||
|
"postgresql://%s:%s@%s:%s/%s",
|
||||||
|
conf.DB.User,
|
||||||
|
conf.DB.Pass,
|
||||||
|
conf.DB.Host,
|
||||||
|
conf.DB.Port,
|
||||||
|
conf.DB.Name,
|
||||||
|
))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("DB connection failed: %v", err)
|
||||||
|
}
|
||||||
|
defer conn.Close(ctx)
|
||||||
|
|
||||||
|
opts := TelegramOptions{
|
||||||
|
ticketsRepo: db.New(conn),
|
||||||
|
gitService: services.NewGit(conf.Git),
|
||||||
|
cloudService: services.NewCloud(conf.Cloud),
|
||||||
|
coda: services.NewCodaClient(conf.Coda),
|
||||||
|
appConfig: &conf,
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
if err := runDiscrodBot(conf); err != nil {
|
||||||
|
log.Fatalf("discord bot cannot be runned: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if err := runTgBot(ctx, opts); err != nil {
|
||||||
|
log.Fatalf("telegram bot cannot be runned: %v", err)
|
||||||
defer os.Exit(1)
|
defer os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// env
|
// env
|
||||||
// env function reads provided file and setup envirmental variables;
|
// env function reads provided file and setup envirmental variables;
|
||||||
func env(envFilePath string) {
|
func env(envFilePath string) domain.Config {
|
||||||
err := godotenv.Load(envFilePath)
|
err := godotenv.Load(envFilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Error while loading env file")
|
log.Fatal("Error while loading env file")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return domain.Config{
|
||||||
|
Git: domain.GitConfig{
|
||||||
|
BaseUrl: os.Getenv("GIT_BASE_URL"),
|
||||||
|
Token: os.Getenv("GIT_TOKEN"),
|
||||||
|
User: os.Getenv("GIT_USER"),
|
||||||
|
},
|
||||||
|
Cloud: domain.CloudConfig{
|
||||||
|
BaseUrl: os.Getenv("CLOUD_BASE_URL"),
|
||||||
|
User: os.Getenv("CLOUD_USER"),
|
||||||
|
Pass: os.Getenv("CLOUD_PASS"),
|
||||||
|
RootDir: os.Getenv("ROOTDIR"),
|
||||||
|
},
|
||||||
|
Coda: domain.CodaConfig{
|
||||||
|
Farm: os.Getenv("CODA_TOKEN1"),
|
||||||
|
Develop: os.Getenv("CODA_TOKEN2"),
|
||||||
|
},
|
||||||
|
DB: domain.DBConfig{
|
||||||
|
Host: os.Getenv("DB_HOST"),
|
||||||
|
Port: os.Getenv("DB_PORT"),
|
||||||
|
Name: os.Getenv("DB_NAME"),
|
||||||
|
User: os.Getenv("DB_USER"),
|
||||||
|
Pass: os.Getenv("DB_PASS"),
|
||||||
|
SslMode: os.Getenv("SSLMODE"),
|
||||||
|
},
|
||||||
|
Telegram: domain.TelegramConfig{
|
||||||
|
Token: os.Getenv("TG_API"),
|
||||||
|
},
|
||||||
|
Discord: domain.DiscordConfig{
|
||||||
|
Token: os.Getenv("DISCORD_TOKEN"),
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDiscrodBot() error {
|
func runDiscrodBot(conf domain.Config) error {
|
||||||
token := os.Getenv("DISCORD_TOKEN")
|
token := conf.Discord.Token
|
||||||
|
|
||||||
dbot, err := discordbot.NewDiscordBot(token)
|
dbot, err := discordbot.NewDiscordBot(token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -81,34 +142,29 @@ func runDiscrodBot() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TelegramOptions struct {
|
||||||
|
ticketsRepo *db.Queries
|
||||||
|
gitService *services.Git
|
||||||
|
cloudService *services.Cloud
|
||||||
|
coda *services.Coda
|
||||||
|
appConfig *domain.Config
|
||||||
|
}
|
||||||
|
|
||||||
// runTgBot ...
|
// runTgBot ...
|
||||||
// ..function creates new Telegram BOT instance
|
// ..function creates new Telegram BOT instance
|
||||||
// ..throw env variables through bot's handlers
|
// ..throw env variables through bot's handlers
|
||||||
// ..setup tg bot router;
|
// ..setup tg bot router;
|
||||||
// and finally returns tgb.Poller
|
// and finally returns tgb.Poller
|
||||||
func runTgBot(ctx context.Context) error {
|
func runTgBot(ctx context.Context, opts TelegramOptions) error {
|
||||||
|
|
||||||
client := tg.New(os.Getenv("TG_API"))
|
log.Print("Start telegram bot init..")
|
||||||
|
client := tg.New(opts.appConfig.Telegram.Token)
|
||||||
gitService := services.NewGit(
|
|
||||||
os.Getenv("GIT_BASE_URL"),
|
|
||||||
os.Getenv("GIT_TOKEN"),
|
|
||||||
)
|
|
||||||
|
|
||||||
cloudService := services.NewCloud(
|
|
||||||
os.Getenv("CLOUD_BASE_URL"),
|
|
||||||
os.Getenv("CLOUD_USER"),
|
|
||||||
os.Getenv("CLOUD_PASS"),
|
|
||||||
)
|
|
||||||
|
|
||||||
coda := services.NewCodaClient(
|
|
||||||
os.Getenv("CODA_TOKEN1"),
|
|
||||||
)
|
|
||||||
|
|
||||||
h := handler.NewHandler(
|
h := handler.NewHandler(
|
||||||
gitService,
|
opts.gitService,
|
||||||
cloudService,
|
opts.cloudService,
|
||||||
coda,
|
opts.coda,
|
||||||
|
opts.ticketsRepo,
|
||||||
)
|
)
|
||||||
|
|
||||||
router := tgb.NewRouter().
|
router := tgb.NewRouter().
|
||||||
|
|
|
||||||
|
|
@ -98,3 +98,61 @@ func CreateRepoHandler(repoNameMinLength int) CommandHandler {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CreateTicketHandler(repoNameMinLength int) CommandHandler {
|
||||||
|
return CommandHandler{
|
||||||
|
Command: discordgo.ApplicationCommand{
|
||||||
|
Name: "new",
|
||||||
|
Description: "Create new development ticket",
|
||||||
|
Options: []*discordgo.ApplicationCommandOption{
|
||||||
|
{
|
||||||
|
Type: discordgo.ApplicationCommandOptionString,
|
||||||
|
Name: "project_name",
|
||||||
|
Description: "Temporary project name",
|
||||||
|
Required: true,
|
||||||
|
MinLength: &repoNameMinLength,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Handler: func(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
||||||
|
// Access options in the order provided by the user.
|
||||||
|
options := i.ApplicationCommandData().Options
|
||||||
|
|
||||||
|
// Or convert the slice into a map
|
||||||
|
optionMap := make(map[string]*discordgo.ApplicationCommandInteractionDataOption, len(options))
|
||||||
|
for _, opt := range options {
|
||||||
|
optionMap[opt.Name] = opt
|
||||||
|
}
|
||||||
|
|
||||||
|
// This example stores the provided arguments in an []interface{}
|
||||||
|
// which will be used to format the bot's response
|
||||||
|
margs := make([]interface{}, 0, len(options))
|
||||||
|
msgformat := "You learned how to use command options! " +
|
||||||
|
"Take a look at the value(s) you entered:\n"
|
||||||
|
|
||||||
|
if option, ok := optionMap["repo_type"]; ok {
|
||||||
|
// Option values must be type asserted from interface{}.
|
||||||
|
// Discordgo provides utility functions to make this simple.
|
||||||
|
margs = append(margs, option.StringValue())
|
||||||
|
msgformat += "> string-option: %s\n"
|
||||||
|
}
|
||||||
|
if option, ok := optionMap["repo_name"]; ok {
|
||||||
|
// Option values must be type asserted from interface{}.
|
||||||
|
// Discordgo provides utility functions to make this simple.
|
||||||
|
margs = append(margs, option.StringValue())
|
||||||
|
msgformat += "> string-option: %s\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
||||||
|
// Ignore type for now, they will be discussed in "responses"
|
||||||
|
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
||||||
|
Data: &discordgo.InteractionResponseData{
|
||||||
|
Content: fmt.Sprintf(
|
||||||
|
msgformat,
|
||||||
|
margs...,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
3
go.mod
3
go.mod
|
|
@ -5,6 +5,7 @@ go 1.20
|
||||||
require (
|
require (
|
||||||
github.com/bwmarrin/discordgo v0.27.1
|
github.com/bwmarrin/discordgo v0.27.1
|
||||||
github.com/imroc/req/v3 v3.35.2
|
github.com/imroc/req/v3 v3.35.2
|
||||||
|
github.com/jackc/pgx v3.6.2+incompatible
|
||||||
github.com/jackc/pgx/v5 v5.4.3
|
github.com/jackc/pgx/v5 v5.4.3
|
||||||
github.com/joho/godotenv v1.5.1
|
github.com/joho/godotenv v1.5.1
|
||||||
github.com/mr-linch/go-tg v0.9.1
|
github.com/mr-linch/go-tg v0.9.1
|
||||||
|
|
@ -19,7 +20,9 @@ require (
|
||||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
||||||
|
github.com/lib/pq v1.10.9 // indirect
|
||||||
github.com/onsi/ginkgo/v2 v2.10.0 // indirect
|
github.com/onsi/ginkgo/v2 v2.10.0 // indirect
|
||||||
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/quic-go/qpack v0.4.0 // indirect
|
github.com/quic-go/qpack v0.4.0 // indirect
|
||||||
github.com/quic-go/qtls-go1-19 v0.3.2 // indirect
|
github.com/quic-go/qtls-go1-19 v0.3.2 // indirect
|
||||||
github.com/quic-go/qtls-go1-20 v0.2.2 // indirect
|
github.com/quic-go/qtls-go1-20 v0.2.2 // indirect
|
||||||
|
|
|
||||||
8
go.sum
8
go.sum
|
|
@ -27,15 +27,21 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI
|
||||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
||||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||||
|
github.com/jackc/pgx v3.6.2+incompatible h1:2zP5OD7kiyR3xzRYMhOcXVvkDZsImVXfj+yIyTQf3/o=
|
||||||
|
github.com/jackc/pgx v3.6.2+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
|
||||||
github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY=
|
github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY=
|
||||||
github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA=
|
github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA=
|
||||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||||
|
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||||
|
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
github.com/mr-linch/go-tg v0.9.1 h1:4KNe7zwFG6svgM9w6pIcH3R7QWa6hIK8tCisQiFRCpU=
|
github.com/mr-linch/go-tg v0.9.1 h1:4KNe7zwFG6svgM9w6pIcH3R7QWa6hIK8tCisQiFRCpU=
|
||||||
github.com/mr-linch/go-tg v0.9.1/go.mod h1:276w69YW4pEo3ZYta+LQe4v/ut2w2h1ksP4ziBWkK98=
|
github.com/mr-linch/go-tg v0.9.1/go.mod h1:276w69YW4pEo3ZYta+LQe4v/ut2w2h1ksP4ziBWkK98=
|
||||||
github.com/onsi/ginkgo/v2 v2.10.0 h1:sfUl4qgLdvkChZrWCYndY2EAu9BRIw1YphNAzy1VNWs=
|
github.com/onsi/ginkgo/v2 v2.10.0 h1:sfUl4qgLdvkChZrWCYndY2EAu9BRIw1YphNAzy1VNWs=
|
||||||
github.com/onsi/ginkgo/v2 v2.10.0/go.mod h1:UDQOh5wbQUlMnkLfVaIUMtQ1Vus92oM+P2JX1aulgcE=
|
github.com/onsi/ginkgo/v2 v2.10.0/go.mod h1:UDQOh5wbQUlMnkLfVaIUMtQ1Vus92oM+P2JX1aulgcE=
|
||||||
github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU=
|
github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
|
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
|
||||||
|
|
@ -48,6 +54,7 @@ github.com/quic-go/quic-go v0.35.1 h1:b0kzj6b/cQAf05cT0CkQubHM31wiA+xH3IBkxP62po
|
||||||
github.com/quic-go/quic-go v0.35.1/go.mod h1:+4CVgVppm0FNjpG3UcX8Joi/frKOH7/ciD5yGcwOO1g=
|
github.com/quic-go/quic-go v0.35.1/go.mod h1:+4CVgVppm0FNjpG3UcX8Joi/frKOH7/ciD5yGcwOO1g=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
||||||
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
|
@ -101,3 +108,4 @@ google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
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 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
package domain
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Git GitConfig
|
||||||
|
Cloud CloudConfig
|
||||||
|
Coda CodaConfig
|
||||||
|
DB DBConfig
|
||||||
|
Telegram TelegramConfig
|
||||||
|
Discord DiscordConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
type GitConfig struct {
|
||||||
|
BaseUrl string
|
||||||
|
Token string
|
||||||
|
User string
|
||||||
|
}
|
||||||
|
|
||||||
|
type CloudConfig struct {
|
||||||
|
BaseUrl string
|
||||||
|
User string
|
||||||
|
Pass string
|
||||||
|
RootDir string
|
||||||
|
}
|
||||||
|
|
||||||
|
type CodaConfig struct {
|
||||||
|
Farm string
|
||||||
|
Develop string
|
||||||
|
}
|
||||||
|
|
||||||
|
type DBConfig struct {
|
||||||
|
Host string
|
||||||
|
Port string
|
||||||
|
Name string
|
||||||
|
User string
|
||||||
|
Pass string
|
||||||
|
SslMode string
|
||||||
|
}
|
||||||
|
|
||||||
|
type TelegramConfig struct {
|
||||||
|
Token string
|
||||||
|
}
|
||||||
|
|
||||||
|
type DiscordConfig struct {
|
||||||
|
Token string
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,6 @@ package services
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"ticket-pimp/internal/domain"
|
"ticket-pimp/internal/domain"
|
||||||
"ticket-pimp/internal/helpers"
|
"ticket-pimp/internal/helpers"
|
||||||
|
|
@ -11,29 +10,31 @@ import (
|
||||||
|
|
||||||
type Cloud struct {
|
type Cloud struct {
|
||||||
*CommonClient
|
*CommonClient
|
||||||
|
Config domain.CloudConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
type ICloud interface {
|
type ICloud interface {
|
||||||
CreateFolder(name string) (*domain.Folder, error)
|
CreateFolder(name string) (*domain.Folder, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCloud(base, user, pass string) *Cloud {
|
func NewCloud(conf domain.CloudConfig) *Cloud {
|
||||||
|
|
||||||
client := NewClient().
|
client := NewClient().
|
||||||
SetTimeout(5*time.Second).
|
SetTimeout(5*time.Second).
|
||||||
SetCommonBasicAuth(user, pass).
|
SetCommonBasicAuth(conf.User, conf.Pass).
|
||||||
SetBaseURL(base)
|
SetBaseURL(conf.BaseUrl)
|
||||||
|
|
||||||
return &Cloud{
|
return &Cloud{
|
||||||
CommonClient: &CommonClient{
|
CommonClient: &CommonClient{
|
||||||
client,
|
client,
|
||||||
},
|
},
|
||||||
|
Config: conf,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cloud) CreateFolder(name string) (*domain.Folder, error) {
|
func (c *Cloud) CreateFolder(name string) (*domain.Folder, error) {
|
||||||
rootDir := os.Getenv("ROOTDIR")
|
rootDir := c.Config.RootDir
|
||||||
user := os.Getenv("CLOUD_USER")
|
user := c.Config.User
|
||||||
|
|
||||||
davPath := "/remote.php/dav/files/"
|
davPath := "/remote.php/dav/files/"
|
||||||
parentPath := "/apps/files/?dir="
|
parentPath := "/apps/files/?dir="
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ package services
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
|
||||||
"ticket-pimp/internal/domain"
|
"ticket-pimp/internal/domain"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -12,6 +11,7 @@ import (
|
||||||
|
|
||||||
type Coda struct {
|
type Coda struct {
|
||||||
*CommonClient
|
*CommonClient
|
||||||
|
Config domain.CodaConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
type ICoda interface {
|
type ICoda interface {
|
||||||
|
|
@ -21,17 +21,18 @@ type ICoda interface {
|
||||||
GetRowLink(id string) (string, error)
|
GetRowLink(id string) (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCodaClient(token string) *Coda {
|
func NewCodaClient(conf domain.CodaConfig) *Coda {
|
||||||
|
|
||||||
client := NewClient().
|
client := NewClient().
|
||||||
SetTimeout(15 * time.Second).
|
SetTimeout(15 * time.Second).
|
||||||
SetCommonBearerAuthToken(token).
|
SetCommonBearerAuthToken(conf.Farm).
|
||||||
SetBaseURL("https://coda.io/apis/v1")
|
SetBaseURL("https://coda.io/apis/v1")
|
||||||
|
|
||||||
return &Coda{
|
return &Coda{
|
||||||
CommonClient: &CommonClient{
|
CommonClient: &CommonClient{
|
||||||
client,
|
client,
|
||||||
},
|
},
|
||||||
|
Config: conf,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -57,7 +58,7 @@ func (c *Coda) CreateApp(task domain.CodaApplication) {
|
||||||
resp, _ := c.R().
|
resp, _ := c.R().
|
||||||
SetBody(task).
|
SetBody(task).
|
||||||
SetContentType("application/json").
|
SetContentType("application/json").
|
||||||
SetBearerAuthToken(os.Getenv("CODA_TOKEN2")).
|
SetBearerAuthToken(c.Config.Develop).
|
||||||
Post("/docs/Ic3IZpQ3Wk/hooks/automation/grid-auto-NlUwM7F7Cr")
|
Post("/docs/Ic3IZpQ3Wk/hooks/automation/grid-auto-NlUwM7F7Cr")
|
||||||
|
|
||||||
fmt.Print(resp)
|
fmt.Print(resp)
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,10 @@ type IGit interface {
|
||||||
CreateRepo(name string) (*domain.Git, error)
|
CreateRepo(name string) (*domain.Git, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGit(base, token string) *Git {
|
func NewGit(conf domain.GitConfig) *Git {
|
||||||
headers := map[string]string{
|
headers := map[string]string{
|
||||||
"Accept": "application/vnd.github+json",
|
"Accept": "application/vnd.github+json",
|
||||||
"Authorization": "Token " + token,
|
"Authorization": "Token " + conf.Token,
|
||||||
"X-GitHub-Api-Version": "2022-11-28",
|
"X-GitHub-Api-Version": "2022-11-28",
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
}
|
}
|
||||||
|
|
@ -26,7 +26,7 @@ func NewGit(base, token string) *Git {
|
||||||
client := NewClient().
|
client := NewClient().
|
||||||
SetTimeout(5 * time.Second).
|
SetTimeout(5 * time.Second).
|
||||||
SetCommonHeaders(headers).
|
SetCommonHeaders(headers).
|
||||||
SetBaseURL(base)
|
SetBaseURL(conf.BaseUrl)
|
||||||
|
|
||||||
return &Git{
|
return &Git{
|
||||||
CommonClient: &CommonClient{client},
|
CommonClient: &CommonClient{client},
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.23.0
|
// sqlc v1.23.0
|
||||||
|
|
||||||
package store_tickets
|
package db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.23.0
|
// sqlc v1.23.0
|
||||||
|
|
||||||
package store_tickets
|
package db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/jackc/pgx/v5/pgtype"
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
// sqlc v1.23.0
|
// sqlc v1.23.0
|
||||||
// source: tickets.sql
|
// source: tickets.sql
|
||||||
|
|
||||||
package store_tickets
|
package db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -11,6 +11,45 @@ import (
|
||||||
"github.com/jackc/pgx/v5/pgtype"
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const createTicket = `-- name: CreateTicket :one
|
||||||
|
INSERT INTO tickets (
|
||||||
|
key, project_git, build_git, folder, created_at
|
||||||
|
) VALUES (
|
||||||
|
$1, $2, $3, $4, $5
|
||||||
|
)
|
||||||
|
RETURNING id, key, project_git, build_git, folder, created_at, deleted_at, updated_at
|
||||||
|
`
|
||||||
|
|
||||||
|
type CreateTicketParams struct {
|
||||||
|
Key pgtype.Text
|
||||||
|
ProjectGit pgtype.Text
|
||||||
|
BuildGit pgtype.Text
|
||||||
|
Folder pgtype.Text
|
||||||
|
CreatedAt pgtype.Timestamptz
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CreateTicket(ctx context.Context, arg CreateTicketParams) (Ticket, error) {
|
||||||
|
row := q.db.QueryRow(ctx, createTicket,
|
||||||
|
arg.Key,
|
||||||
|
arg.ProjectGit,
|
||||||
|
arg.BuildGit,
|
||||||
|
arg.Folder,
|
||||||
|
arg.CreatedAt,
|
||||||
|
)
|
||||||
|
var i Ticket
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Key,
|
||||||
|
&i.ProjectGit,
|
||||||
|
&i.BuildGit,
|
||||||
|
&i.Folder,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.DeletedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
const deleteTicketByID = `-- name: DeleteTicketByID :exec
|
const deleteTicketByID = `-- name: DeleteTicketByID :exec
|
||||||
UPDATE tickets SET deleted_at = current_timestamp WHERE id = $1
|
UPDATE tickets SET deleted_at = current_timestamp WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
@ -5,6 +5,6 @@ sql:
|
||||||
schema: "migrate"
|
schema: "migrate"
|
||||||
gen:
|
gen:
|
||||||
go:
|
go:
|
||||||
package: "store_tickets"
|
package: "db"
|
||||||
sql_package: "pgx/v5"
|
sql_package: "pgx/v5"
|
||||||
out: "store_tickets"
|
out: "db/tickets"
|
||||||
|
|
@ -1,3 +1,11 @@
|
||||||
|
-- name: CreateTicket :one
|
||||||
|
INSERT INTO tickets (
|
||||||
|
key, project_git, build_git, folder, created_at
|
||||||
|
) VALUES (
|
||||||
|
$1, $2, $3, $4, $5
|
||||||
|
)
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
-- name: ListTickets :many
|
-- name: ListTickets :many
|
||||||
SELECT * FROM tickets WHERE deleted_at IS NULL;
|
SELECT * FROM tickets WHERE deleted_at IS NULL;
|
||||||
|
|
||||||
|
|
|
||||||
17
readme.md
17
readme.md
|
|
@ -25,14 +25,13 @@ sql-migrate up
|
||||||
|
|
||||||
|
|
||||||
# To-do P1:
|
# To-do P1:
|
||||||
- [x] Выбирать проект в YouTrack по имени во время flow, а не по ID
|
- [ ] Сделать нормальный Gracefull ShutDown с потоками и всей хернёй
|
||||||
- [x] Делать запросы в Git, ownCloud параллельно;
|
|
||||||
- [x] Сохранять правильную ссылку на Git;
|
|
||||||
- [x] Сохранять правильную ссылку на GitBuild;
|
|
||||||
- [x] Сделать бота в Telegram;
|
|
||||||
|
|
||||||
|
|
||||||
# To-do P2*:
|
# To-do P2*:
|
||||||
|
- [ ] Нормальное сообщение об ошибке с созданием репо с уже существующим именем;
|
||||||
|
- [ ] Отказ от инициализации бота (автоинкремент ключа по данным базы?)
|
||||||
- [ ] В уведомлении об успешном создании сообщать всю инфу:
|
- [ ] В уведомлении об успешном создании сообщать всю инфу:
|
||||||
- git;
|
- git;
|
||||||
- git-build url + ssh url;
|
- git-build url + ssh url;
|
||||||
|
|
@ -44,5 +43,13 @@ sql-migrate up
|
||||||
- [ ] Складывать в описание репозитория ссылку на тикет;
|
- [ ] Складывать в описание репозитория ссылку на тикет;
|
||||||
- [ ] Сделать базулю с достойными пользователями;
|
- [ ] Сделать базулю с достойными пользователями;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Готово:
|
||||||
|
- [x] Выбирать проект в YouTrack по имени во время flow, а не по ID
|
||||||
|
- [x] Делать запросы в Git, ownCloud параллельно;
|
||||||
|
- [x] Сохранять правильную ссылку на Git;
|
||||||
|
- [x] Сохранять правильную ссылку на GitBuild;
|
||||||
|
- [x] Сделать бота в Telegram;
|
||||||
- [x] Run bot on docker scratch: https://github.com/jeremyhuiskamp/golang-docker-scratch/blob/main/README.mdа
|
- [x] Run bot on docker scratch: https://github.com/jeremyhuiskamp/golang-docker-scratch/blob/main/README.mdа
|
||||||
- [x] Сохранять короткую ссылку на графику;
|
- [x] Сохранять короткую ссылку на графику;
|
||||||
Loading…
Reference in New Issue