From 310a3d9f55594198e3cdaf3c4c4632ccb88a4dab Mon Sep 17 00:00:00 2001 From: naudachu Date: Wed, 1 Nov 2023 14:03:01 +0500 Subject: [PATCH] - write to db new ticket; - fixed telegram bot init function with telegram options; --- .gitignore | 3 +- bot/controller/controller.go | 25 +++- bot/handler/handler.go | 6 +- cmd/main.go | 122 +++++++++++++----- discord-bot/discord-bot.go | 58 +++++++++ go.mod | 3 + go.sum | 8 ++ internal/domain/config.go | 45 +++++++ internal/services/cloud.go | 13 +- internal/services/coda.go | 9 +- internal/services/git.go | 6 +- .../{store_tickets => db/tickets}/db.go | 2 +- .../{store_tickets => db/tickets}/models.go | 2 +- .../tickets}/tickets.sql.go | 41 +++++- internal/storage/sqlc.yaml | 4 +- internal/storage/sqlc/tickets.sql | 8 ++ readme.md | 17 ++- 17 files changed, 312 insertions(+), 60 deletions(-) create mode 100644 internal/domain/config.go rename internal/storage/{store_tickets => db/tickets}/db.go (96%) rename internal/storage/{store_tickets => db/tickets}/models.go (94%) rename internal/storage/{store_tickets => db/tickets}/tickets.sql.go (78%) diff --git a/.gitignore b/.gitignore index 8d60935..22ed4fe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .vscode/ -**/**/*.env \ No newline at end of file +**/**/*.env +docker/** \ No newline at end of file diff --git a/bot/controller/controller.go b/bot/controller/controller.go index cb02d23..12c7dbb 100644 --- a/bot/controller/controller.go +++ b/bot/controller/controller.go @@ -1,29 +1,37 @@ package controller import ( + "context" "fmt" + "log" "strings" "sync" "ticket-pimp/internal/domain" "ticket-pimp/internal/services" + db "ticket-pimp/internal/storage/db/tickets" + "time" + + "github.com/jackc/pgx/v5/pgtype" ) type WorkflowController struct { iGit services.IGit iCloud services.ICloud iCoda services.ICoda + db *db.Queries } func NewWorkflowController( git services.IGit, cloud services.ICloud, coda services.ICoda, + db *db.Queries, ) *WorkflowController { return &WorkflowController{ iGit: git, iCloud: cloud, - - iCoda: coda, + iCoda: coda, + db: db, } } @@ -79,6 +87,19 @@ func (wc *WorkflowController) Workflow(name, key, id string) (string, error) { } else { 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{ ID: appKey, diff --git a/bot/handler/handler.go b/bot/handler/handler.go index d6c74aa..7e9ce31 100644 --- a/bot/handler/handler.go +++ b/bot/handler/handler.go @@ -3,6 +3,7 @@ package handler import ( "ticket-pimp/bot/controller" "ticket-pimp/internal/services" + db "ticket-pimp/internal/storage/db/tickets" ) type Handler struct { @@ -12,18 +13,21 @@ type Handler struct { coda services.ICoda key string id string + db *db.Queries } func NewHandler( git services.IGit, cloud services.ICloud, coda services.ICoda, + db *db.Queries, ) *Handler { return &Handler{ - workflow: controller.NewWorkflowController(git, cloud, coda), + workflow: controller.NewWorkflowController(git, cloud, coda, db), git: git, cloud: cloud, coda: coda, + db: db, } } diff --git a/cmd/main.go b/cmd/main.go index 5d5e69c..6ff0c67 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -9,8 +9,11 @@ import ( "syscall" "ticket-pimp/bot/handler" discordbot "ticket-pimp/discord-bot" + "ticket-pimp/internal/domain" "ticket-pimp/internal/services" + db "ticket-pimp/internal/storage/db/tickets" + "github.com/jackc/pgx/v5" "github.com/joho/godotenv" "github.com/mr-linch/go-tg" "github.com/mr-linch/go-tg/tgb" @@ -18,34 +21,92 @@ import ( func main() { log.Print("started") - env("develop.env") + config := env("develop.env") + run(config) +} - if err := runDiscrodBot(); err != nil { - log.Fatal(fmt.Errorf("discord bot cannot be runned: %v", err)) - } - - ctx := context.Background() - - ctx, cancel := signal.NotifyContext(ctx, os.Interrupt, os.Kill, syscall.SIGTERM) +func run(conf domain.Config) { + ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill, syscall.SIGTERM) defer cancel() - if err := runTgBot(ctx); err != nil { - fmt.Println(err) + conn, err := pgx.Connect( + 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) } } // env // env function reads provided file and setup envirmental variables; -func env(envFilePath string) { +func env(envFilePath string) domain.Config { err := godotenv.Load(envFilePath) if err != nil { 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 { - token := os.Getenv("DISCORD_TOKEN") +func runDiscrodBot(conf domain.Config) error { + token := conf.Discord.Token dbot, err := discordbot.NewDiscordBot(token) if err != nil { @@ -81,34 +142,29 @@ func runDiscrodBot() error { return nil } +type TelegramOptions struct { + ticketsRepo *db.Queries + gitService *services.Git + cloudService *services.Cloud + coda *services.Coda + appConfig *domain.Config +} + // runTgBot ... // ..function creates new Telegram BOT instance // ..throw env variables through bot's handlers // ..setup tg bot router; // 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")) - - 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"), - ) + log.Print("Start telegram bot init..") + client := tg.New(opts.appConfig.Telegram.Token) h := handler.NewHandler( - gitService, - cloudService, - coda, + opts.gitService, + opts.cloudService, + opts.coda, + opts.ticketsRepo, ) router := tgb.NewRouter(). diff --git a/discord-bot/discord-bot.go b/discord-bot/discord-bot.go index 3ab2beb..d82598e 100644 --- a/discord-bot/discord-bot.go +++ b/discord-bot/discord-bot.go @@ -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..., + ), + }, + }) + }, + } +} diff --git a/go.mod b/go.mod index 73a0d41..ec33b16 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.20 require ( github.com/bwmarrin/discordgo v0.27.1 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/joho/godotenv v1.5.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/jackc/pgpassfile v1.0.0 // 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/pkg/errors v0.9.1 // 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-20 v0.2.2 // indirect diff --git a/go.sum b/go.sum index d371fe0..7ce9bea 100644 --- a/go.sum +++ b/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/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/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/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= 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/go.mod h1:276w69YW4pEo3ZYta+LQe4v/ut2w2h1ksP4ziBWkK98= 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/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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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/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/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 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.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/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/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/domain/config.go b/internal/domain/config.go new file mode 100644 index 0000000..18739a5 --- /dev/null +++ b/internal/domain/config.go @@ -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 +} diff --git a/internal/services/cloud.go b/internal/services/cloud.go index 517c7c2..8c61a6f 100644 --- a/internal/services/cloud.go +++ b/internal/services/cloud.go @@ -2,7 +2,6 @@ package services import ( "fmt" - "os" "strconv" "ticket-pimp/internal/domain" "ticket-pimp/internal/helpers" @@ -11,29 +10,31 @@ import ( type Cloud struct { *CommonClient + Config domain.CloudConfig } type ICloud interface { CreateFolder(name string) (*domain.Folder, error) } -func NewCloud(base, user, pass string) *Cloud { +func NewCloud(conf domain.CloudConfig) *Cloud { client := NewClient(). SetTimeout(5*time.Second). - SetCommonBasicAuth(user, pass). - SetBaseURL(base) + SetCommonBasicAuth(conf.User, conf.Pass). + SetBaseURL(conf.BaseUrl) return &Cloud{ CommonClient: &CommonClient{ client, }, + Config: conf, } } func (c *Cloud) CreateFolder(name string) (*domain.Folder, error) { - rootDir := os.Getenv("ROOTDIR") - user := os.Getenv("CLOUD_USER") + rootDir := c.Config.RootDir + user := c.Config.User davPath := "/remote.php/dav/files/" parentPath := "/apps/files/?dir=" diff --git a/internal/services/coda.go b/internal/services/coda.go index b62b8cb..9c10b61 100644 --- a/internal/services/coda.go +++ b/internal/services/coda.go @@ -3,7 +3,6 @@ package services import ( "fmt" "log" - "os" "ticket-pimp/internal/domain" "time" @@ -12,6 +11,7 @@ import ( type Coda struct { *CommonClient + Config domain.CodaConfig } type ICoda interface { @@ -21,17 +21,18 @@ type ICoda interface { GetRowLink(id string) (string, error) } -func NewCodaClient(token string) *Coda { +func NewCodaClient(conf domain.CodaConfig) *Coda { client := NewClient(). SetTimeout(15 * time.Second). - SetCommonBearerAuthToken(token). + SetCommonBearerAuthToken(conf.Farm). SetBaseURL("https://coda.io/apis/v1") return &Coda{ CommonClient: &CommonClient{ client, }, + Config: conf, } } @@ -57,7 +58,7 @@ func (c *Coda) CreateApp(task domain.CodaApplication) { resp, _ := c.R(). SetBody(task). SetContentType("application/json"). - SetBearerAuthToken(os.Getenv("CODA_TOKEN2")). + SetBearerAuthToken(c.Config.Develop). Post("/docs/Ic3IZpQ3Wk/hooks/automation/grid-auto-NlUwM7F7Cr") fmt.Print(resp) diff --git a/internal/services/git.go b/internal/services/git.go index 657ab34..6aea8c4 100644 --- a/internal/services/git.go +++ b/internal/services/git.go @@ -15,10 +15,10 @@ type IGit interface { CreateRepo(name string) (*domain.Git, error) } -func NewGit(base, token string) *Git { +func NewGit(conf domain.GitConfig) *Git { headers := map[string]string{ "Accept": "application/vnd.github+json", - "Authorization": "Token " + token, + "Authorization": "Token " + conf.Token, "X-GitHub-Api-Version": "2022-11-28", "Content-Type": "application/json", } @@ -26,7 +26,7 @@ func NewGit(base, token string) *Git { client := NewClient(). SetTimeout(5 * time.Second). SetCommonHeaders(headers). - SetBaseURL(base) + SetBaseURL(conf.BaseUrl) return &Git{ CommonClient: &CommonClient{client}, diff --git a/internal/storage/store_tickets/db.go b/internal/storage/db/tickets/db.go similarity index 96% rename from internal/storage/store_tickets/db.go rename to internal/storage/db/tickets/db.go index 94d6618..7d918df 100644 --- a/internal/storage/store_tickets/db.go +++ b/internal/storage/db/tickets/db.go @@ -2,7 +2,7 @@ // versions: // sqlc v1.23.0 -package store_tickets +package db import ( "context" diff --git a/internal/storage/store_tickets/models.go b/internal/storage/db/tickets/models.go similarity index 94% rename from internal/storage/store_tickets/models.go rename to internal/storage/db/tickets/models.go index ffa7547..3a16316 100644 --- a/internal/storage/store_tickets/models.go +++ b/internal/storage/db/tickets/models.go @@ -2,7 +2,7 @@ // versions: // sqlc v1.23.0 -package store_tickets +package db import ( "github.com/jackc/pgx/v5/pgtype" diff --git a/internal/storage/store_tickets/tickets.sql.go b/internal/storage/db/tickets/tickets.sql.go similarity index 78% rename from internal/storage/store_tickets/tickets.sql.go rename to internal/storage/db/tickets/tickets.sql.go index 5e2af8b..1776bd2 100644 --- a/internal/storage/store_tickets/tickets.sql.go +++ b/internal/storage/db/tickets/tickets.sql.go @@ -3,7 +3,7 @@ // sqlc v1.23.0 // source: tickets.sql -package store_tickets +package db import ( "context" @@ -11,6 +11,45 @@ import ( "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 UPDATE tickets SET deleted_at = current_timestamp WHERE id = $1 ` diff --git a/internal/storage/sqlc.yaml b/internal/storage/sqlc.yaml index d07f4c0..7ad84aa 100644 --- a/internal/storage/sqlc.yaml +++ b/internal/storage/sqlc.yaml @@ -5,6 +5,6 @@ sql: schema: "migrate" gen: go: - package: "store_tickets" + package: "db" sql_package: "pgx/v5" - out: "store_tickets" \ No newline at end of file + out: "db/tickets" \ No newline at end of file diff --git a/internal/storage/sqlc/tickets.sql b/internal/storage/sqlc/tickets.sql index 0ed1650..dafe59d 100644 --- a/internal/storage/sqlc/tickets.sql +++ b/internal/storage/sqlc/tickets.sql @@ -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 SELECT * FROM tickets WHERE deleted_at IS NULL; diff --git a/readme.md b/readme.md index 0f9d99e..62e4d8f 100644 --- a/readme.md +++ b/readme.md @@ -25,14 +25,13 @@ sql-migrate up # To-do P1: -- [x] Выбирать проект в YouTrack по имени во время flow, а не по ID -- [x] Делать запросы в Git, ownCloud параллельно; -- [x] Сохранять правильную ссылку на Git; -- [x] Сохранять правильную ссылку на GitBuild; -- [x] Сделать бота в Telegram; +- [ ] Сделать нормальный Gracefull ShutDown с потоками и всей хернёй + # To-do P2*: +- [ ] Нормальное сообщение об ошибке с созданием репо с уже существующим именем; +- [ ] Отказ от инициализации бота (автоинкремент ключа по данным базы?) - [ ] В уведомлении об успешном создании сообщать всю инфу: - git; - 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] Сохранять короткую ссылку на графику; \ No newline at end of file