- create repo with discord bot;

This commit is contained in:
naudachu 2023-11-09 16:24:55 +05:00
parent 3a4b461cda
commit 092ba475a2
11 changed files with 460 additions and 214 deletions

View File

@ -53,11 +53,11 @@ func (h *router) CreateFolderHandler(nameMinLenght int) route {
optionMap[opt.Name] = opt
}
// Creating request:
var req controller.FolderRequest
name, insertedValueNotNil := optionMap[nameOption]
dchan, err := s.Channel(i.ChannelID)
// Creating request:
var req controller.FolderRequest
if err != nil {
log.Printf("error while identifying channel: %v", err)
} else {

View File

@ -0,0 +1,131 @@
package handler
import (
"context"
"fmt"
"log"
"strconv"
"ticket-pimp/internal/controller"
"github.com/bwmarrin/discordgo"
)
func (h *router) CreateRepoHandler(repoNameMinLength int) route {
const (
repoType = "repo_type"
projectRepo = "project_repo"
buildRepo = "build_repo"
nameOption = "repo_name"
)
return route{
Command: discordgo.ApplicationCommand{
Name: "repo",
Description: "Command for repository creation",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionString,
Name: repoType,
Description: "The type of repo",
Required: true,
Choices: []*discordgo.ApplicationCommandOptionChoice{
{
Name: "Unity project repo",
Value: projectRepo,
},
{
Name: "XCode build repo",
Value: buildRepo,
},
},
},
{
Type: discordgo.ApplicationCommandOptionString,
Name: nameOption,
Description: "Type the repository's name",
Required: false,
MinLength: &repoNameMinLength,
},
},
},
Handler: func(s *discordgo.Session, i *discordgo.InteractionCreate) {
// Моментальный ответ для избежания столкновения с протуханием токена
initialResponse := discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Flags: discordgo.MessageFlagsEphemeral,
Content: "Cooking your query..",
},
}
s.InteractionRespond(i.Interaction, &initialResponse)
// Определение переменной для ответа
var result string = "unexpected result"
// 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
}
// Creating request:
var req controller.GitRequest
name, insertedValueNotNil := optionMap[nameOption]
isBuild := optionMap[repoType]
switch isBuild.StringValue() {
case buildRepo:
req.IsBuildGit = true
case projectRepo:
req.IsBuildGit = false
}
dchan, err := s.Channel(i.ChannelID)
if err != nil {
log.Printf("error while identifying channel: %v", err)
} else {
if dchan.ParentID == strconv.Itoa(1150719794853716028) {
req.ChannelID = dchan.ID
if insertedValueNotNil {
req.InsertedName = name.StringValue()
}
} else {
req.ChannelID = ""
if insertedValueNotNil {
req.InsertedName = name.StringValue()
}
}
}
// Making request:
resp := h.controller.CreateGit(context.TODO(), req)
if resp.Project == nil {
result = resp.Message.Error()
} else {
result = fmt.Sprintf(
"## Project info:\n🔑 key: %s\n📂 folder: %s\n👾 project git: %s\n🚀 build git: %s\n\nErrors: %v",
resp.Project.ShortName,
resp.Project.Cloud,
resp.Project.ProjectGit,
resp.Project.BuildGit,
resp.Message,
)
}
// Sending result:
_, err = s.FollowupMessageCreate(i.Interaction, true, &discordgo.WebhookParams{
Content: result,
})
if err != nil {
s.FollowupMessageCreate(i.Interaction, true, &discordgo.WebhookParams{
Content: fmt.Sprintf("Something went wrong: %v", err),
})
return
}
},
}
}

View File

@ -1,109 +0,0 @@
package handler
import (
"context"
"fmt"
"github.com/bwmarrin/discordgo"
)
func (h *router) CreateRepoHandler(repoNameMinLength int) route {
const (
projectRepo = "project_repo"
buildRepo = "build_repo"
)
return route{
Command: discordgo.ApplicationCommand{
Name: "repo",
Description: "Command for repository creation",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionString,
Name: "repo_type",
Description: "The type of repo",
Required: true,
Choices: []*discordgo.ApplicationCommandOptionChoice{
{
Name: "Unity project repo",
Value: projectRepo,
},
{
Name: "XCode build repo",
Value: buildRepo,
},
},
},
{
Type: discordgo.ApplicationCommandOptionString,
Name: "repo_name",
Description: "Type the repository's name",
Required: false,
MinLength: &repoNameMinLength,
},
},
},
Handler: func(s *discordgo.Session, i *discordgo.InteractionCreate) {
var result string
// 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
}
var str string = ""
project, err := h.controller.GetProjectByChannelID(context.TODO(), i.ChannelID)
if err != nil {
result = fmt.Sprintf("unable to retrieve project from db, error: %v", err)
} else {
var suffix string
if option, ok := optionMap["repo_type"]; ok {
switch option.Value {
case projectRepo:
suffix = ""
case buildRepo:
suffix = "-build"
}
}
if project == nil {
if option, ok := optionMap["repo_name"]; ok {
str = option.StringValue()
} else {
str = ""
}
} else {
str = project.ShortName
}
if str == "" {
result = "Ты, либо в проекте репо создавай, либо имя напиши, блет!"
} else {
str = str + suffix
// var g *domain.Git
g, err := h.controller.IGit.CreateRepo(str)
if err != nil {
result = fmt.Sprintf("error while repo creation: %v", err)
} else {
result = "🚀 " + g.HtmlUrl + " was created"
}
}
}
resp := &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: result,
},
}
s.InteractionRespond(i.Interaction, resp)
},
}
}

View File

@ -17,11 +17,6 @@ type FolderRequest struct {
InsertedName string
}
type ProjectResponse struct {
Project *domain.Project
Message error
}
func (wc *WorkflowController) CreateFolder(ctx context.Context, req FolderRequest) *ProjectResponse {
project, err := wc.GetProjectByChannelID(ctx, req.ChannelID)
@ -96,5 +91,4 @@ func (wc *WorkflowController) CreateFolder(ctx context.Context, req FolderReques
}
return &result
}

View File

@ -0,0 +1,168 @@
package controller
import (
"context"
"errors"
"fmt"
"log"
"ticket-pimp/internal/domain"
"ticket-pimp/internal/storage/db"
"time"
"github.com/jackc/pgx/v5/pgtype"
)
type GitRequest struct {
ChannelID string
InsertedName string
IsBuildGit bool
}
func (wc *WorkflowController) createGitForExistingProject(ctx context.Context, req GitRequest, p *domain.Project) *ProjectResponse {
var (
name string = ""
dbticket db.Ticket
)
switch {
case p.ShortName != "":
name = p.ShortName
if req.IsBuildGit {
name += "-build"
}
case req.InsertedName != "":
name = req.InsertedName
if req.IsBuildGit {
name += "-build"
}
}
// response := wc.ICloud.CreateFolder(name)
git, err := wc.IGit.CreateRepo(name)
if err != nil {
return &ProjectResponse{
Project: p,
Message: fmt.Errorf("unable to create git w/ an error: %v", err),
}
}
if req.IsBuildGit {
dbticket, err = wc.q.UpdateTicketBuildGit(
ctx,
db.UpdateTicketBuildGitParams{
BuildGit: pgtype.Text{String: git.HtmlUrl, Valid: true},
UpdatedAt: pgtype.Timestamptz{Time: time.Now(), InfinityModifier: 0, Valid: true},
Channelid: pgtype.Text{String: req.ChannelID, Valid: true},
})
if err != nil {
log.Printf("unable to scan row from db: %v", err)
return &ProjectResponse{
Project: p,
Message: fmt.Errorf("unable to update project: %v", err),
}
}
} else {
dbticket, err = wc.q.UpdateTicketProjectGit(
ctx,
db.UpdateTicketProjectGitParams{
ProjectGit: pgtype.Text{String: git.HtmlUrl, Valid: true},
UpdatedAt: pgtype.Timestamptz{Time: time.Now(), InfinityModifier: 0, Valid: true},
Channelid: pgtype.Text{String: req.ChannelID, Valid: true},
},
)
if err != nil {
log.Printf("unable to scan row from db: %v", err)
return &ProjectResponse{
Project: p,
Message: fmt.Errorf("unable to update project: %v", err),
}
}
}
return &ProjectResponse{
Project: &domain.Project{
ID: string(dbticket.ID),
ShortName: dbticket.Key.String,
ChannelID: dbticket.Channelid.String,
ProjectGit: dbticket.ProjectGit.String,
BuildGit: dbticket.BuildGit.String,
Cloud: dbticket.Folder.String,
},
Message: err,
}
}
func (wc *WorkflowController) CreateGit(ctx context.Context, req GitRequest) *ProjectResponse {
// [ ] Валидация на пустой канал?
p, err := wc.GetProjectByChannelID(ctx, req.ChannelID)
if err != nil {
return &ProjectResponse{
Project: nil,
Message: fmt.Errorf("unable to retrieve project from db: %v", err),
}
}
// var (
// name string
// dbticket db.Ticket
// result ProjectResponse
// )
switch {
case p != nil && req.IsBuildGit:
if p.BuildGit != "" {
return &ProjectResponse{
Project: p,
Message: errors.New("build git already exists"),
}
} else {
// [x]
return wc.createGitForExistingProject(ctx, req, p)
}
case p != nil && !req.IsBuildGit:
if p.ProjectGit != "" {
return &ProjectResponse{
Project: p,
Message: errors.New("project git already exists"),
}
} else {
// [x]
return wc.createGitForExistingProject(ctx, req, p)
}
default:
if req.InsertedName != "" {
if req.IsBuildGit {
req.InsertedName += "-build"
}
git, err := wc.IGit.CreateRepo(req.InsertedName)
if err != nil || git == nil {
return &ProjectResponse{
Project: nil,
Message: err,
}
} else {
if req.IsBuildGit {
return &ProjectResponse{
Project: &domain.Project{
BuildGit: git.HtmlUrl,
},
Message: err,
}
}
return &ProjectResponse{
Project: &domain.Project{
ProjectGit: git.HtmlUrl,
},
Message: err,
}
}
} else {
return &ProjectResponse{
Project: nil,
Message: errors.New("передано пустое имя"),
}
}
}
}

View File

@ -0,0 +1,84 @@
package controller
import (
"context"
"fmt"
"log"
"strings"
"sync"
"ticket-pimp/internal/domain"
"ticket-pimp/internal/storage/db"
"github.com/jackc/pgx/v5/pgtype"
)
func (wc *WorkflowController) FullProjectInit(name, key, id string) (string, error) {
appKey := fmt.Sprintf("%s-%s", key, id)
var (
git, gitBuild *domain.Git
cloud *domain.Folder
)
var wg sync.WaitGroup
wg.Add(3)
go func(ref **domain.Git) {
defer wg.Done()
*ref, _ = wc.IGit.CreateRepo(appKey)
}(&git)
go func(ref **domain.Git) {
defer wg.Done()
*ref, _ = wc.IGit.CreateRepo(appKey + "-build")
}(&gitBuild)
go func(ref **domain.Folder) {
defer wg.Done()
*ref = wc.ICloud.CreateFolder(appKey).Folder
}(&cloud)
wg.Wait()
var gitResult, gitBuildResult, cloudResult string
if git == nil {
gitResult = "cannot create git"
} else {
gitResult = git.HtmlUrl
}
if gitBuild == nil {
gitBuildResult = "cannot create git"
} else {
gitBuildResult = fmt.Sprintf("ssh://%s/%s.git", gitBuild.SshUrl, gitBuild.FullName)
}
if cloud == nil {
cloudResult = "cannot create folder"
} else {
cloudResult = cloud.PrivateURL
}
ctx := context.TODO()
insertedTicket, err := wc.q.CreateTicket(ctx, db.CreateTicketParams{
Key: pgtype.Text{String: appKey, Valid: true},
Channelid: pgtype.Text{},
})
if err != nil {
log.Fatal(err)
}
log.Print(insertedTicket)
wc.ICoda.CreateApp(domain.CodaApplication{
ID: appKey,
Summary: strings.TrimSpace(name),
Git: gitResult,
GitBuild: gitBuildResult,
Folder: cloudResult,
})
return appKey, nil
}

View File

@ -1,16 +1,10 @@
package controller
import (
"context"
"fmt"
"log"
"strings"
"sync"
"ticket-pimp/internal/domain"
"ticket-pimp/internal/services"
"ticket-pimp/internal/storage/db"
"github.com/jackc/pgx/v5/pgtype"
"github.com/jackc/pgx/v5/pgxpool"
)
@ -37,73 +31,7 @@ func NewWorkflowController(
}
}
func (wc *WorkflowController) FullProjectInit(name, key, id string) (string, error) {
appKey := fmt.Sprintf("%s-%s", key, id)
var (
git, gitBuild *domain.Git
cloud *domain.Folder
)
var wg sync.WaitGroup
wg.Add(3)
go func(ref **domain.Git) {
defer wg.Done()
*ref, _ = wc.IGit.CreateRepo(appKey)
}(&git)
go func(ref **domain.Git) {
defer wg.Done()
*ref, _ = wc.IGit.CreateRepo(appKey + "-build")
}(&gitBuild)
go func(ref **domain.Folder) {
defer wg.Done()
*ref = wc.ICloud.CreateFolder(appKey).Folder
}(&cloud)
wg.Wait()
var gitResult, gitBuildResult, cloudResult string
if git == nil {
gitResult = "cannot create git"
} else {
gitResult = git.HtmlUrl
}
if gitBuild == nil {
gitBuildResult = "cannot create git"
} else {
gitBuildResult = fmt.Sprintf("ssh://%s/%s.git", gitBuild.SshUrl, gitBuild.FullName)
}
if cloud == nil {
cloudResult = "cannot create folder"
} else {
cloudResult = cloud.PrivateURL
}
ctx := context.TODO()
insertedTicket, err := wc.q.CreateTicket(ctx, db.CreateTicketParams{
Key: pgtype.Text{String: appKey, Valid: true},
Channelid: pgtype.Text{},
})
if err != nil {
log.Fatal(err)
}
log.Print(insertedTicket)
wc.ICoda.CreateApp(domain.CodaApplication{
ID: appKey,
Summary: strings.TrimSpace(name),
Git: gitResult,
GitBuild: gitBuildResult,
Folder: cloudResult,
})
return appKey, nil
type ProjectResponse struct {
Project *domain.Project
Message error
}

View File

@ -1,22 +0,0 @@
package controller
import (
"context"
"ticket-pimp/internal/domain"
db "ticket-pimp/internal/storage/db"
)
type IConfigController interface {
Get(context.Context) (domain.ApplicationConfig, error)
Update(context.Context) (domain.ApplicationConfig, error)
}
type AppConfig struct {
db *db.Queries
}
func NewAppConfig(db *db.Queries) AppConfig {
return AppConfig{
db: db,
}
}

View File

@ -195,6 +195,36 @@ func (q *Queries) SetNewConfig(ctx context.Context) (Appconfig, error) {
return i, err
}
const updateTicketBuildGit = `-- name: UpdateTicketBuildGit :one
UPDATE tickets
SET build_git = $1, updated_at = $2
WHERE channelID = $3
RETURNING id, key, channelid, project_git, build_git, folder, created_at, deleted_at, updated_at
`
type UpdateTicketBuildGitParams struct {
BuildGit pgtype.Text
UpdatedAt pgtype.Timestamptz
Channelid pgtype.Text
}
func (q *Queries) UpdateTicketBuildGit(ctx context.Context, arg UpdateTicketBuildGitParams) (Ticket, error) {
row := q.db.QueryRow(ctx, updateTicketBuildGit, arg.BuildGit, arg.UpdatedAt, arg.Channelid)
var i Ticket
err := row.Scan(
&i.ID,
&i.Key,
&i.Channelid,
&i.ProjectGit,
&i.BuildGit,
&i.Folder,
&i.CreatedAt,
&i.DeletedAt,
&i.UpdatedAt,
)
return i, err
}
const updateTicketByID = `-- name: UpdateTicketByID :exec
UPDATE tickets SET project_git = $1, build_git = $2, folder = $3 WHERE id = $4
`
@ -245,3 +275,33 @@ func (q *Queries) UpdateTicketFolder(ctx context.Context, arg UpdateTicketFolder
)
return i, err
}
const updateTicketProjectGit = `-- name: UpdateTicketProjectGit :one
UPDATE tickets
SET project_git = $1, updated_at = $2
WHERE channelID = $3
RETURNING id, key, channelid, project_git, build_git, folder, created_at, deleted_at, updated_at
`
type UpdateTicketProjectGitParams struct {
ProjectGit pgtype.Text
UpdatedAt pgtype.Timestamptz
Channelid pgtype.Text
}
func (q *Queries) UpdateTicketProjectGit(ctx context.Context, arg UpdateTicketProjectGitParams) (Ticket, error) {
row := q.db.QueryRow(ctx, updateTicketProjectGit, arg.ProjectGit, arg.UpdatedAt, arg.Channelid)
var i Ticket
err := row.Scan(
&i.ID,
&i.Key,
&i.Channelid,
&i.ProjectGit,
&i.BuildGit,
&i.Folder,
&i.CreatedAt,
&i.DeletedAt,
&i.UpdatedAt,
)
return i, err
}

View File

@ -21,6 +21,18 @@ SET folder = $1, updated_at = $2
WHERE channelID = $3
RETURNING *;
-- name: UpdateTicketProjectGit :one
UPDATE tickets
SET project_git = $1, updated_at = $2
WHERE channelID = $3
RETURNING *;
-- name: UpdateTicketBuildGit :one
UPDATE tickets
SET build_git = $1, updated_at = $2
WHERE channelID = $3
RETURNING *;
-- name: ListTickets :many
SELECT * FROM tickets WHERE deleted_at IS NULL;