2024-02-20 21:13:34 +00:00
package main
import (
2024-03-08 10:56:17 +00:00
"code.gitea.io/sdk/gitea"
2024-03-07 23:37:15 +00:00
"errors"
2024-02-20 21:13:34 +00:00
"fmt"
2024-03-07 23:37:15 +00:00
"github.com/sethvargo/go-githubactions"
2024-03-08 11:13:40 +00:00
"os"
2024-03-08 10:56:17 +00:00
"slices"
2024-03-07 23:37:15 +00:00
"strconv"
2024-02-20 21:13:34 +00:00
"strings"
)
2024-03-08 11:13:40 +00:00
func ParseActionConfig ( ctx githubactions . GitHubContext ) ( * CreatePrConfig , error ) {
2024-03-07 23:37:15 +00:00
base := githubactions . GetInput ( "base" )
if base == "" {
return nil , errors . New ( "base branch name cannot be empty" )
}
2024-02-20 21:13:34 +00:00
2024-03-08 11:22:27 +00:00
repo := strings . Split ( ctx . Repository , "/" ) [ 1 ]
2024-03-08 11:19:33 +00:00
fmt . Printf ( "The repository is %v\n" , repo )
2024-02-20 21:13:34 +00:00
2024-03-07 23:37:15 +00:00
title := githubactions . GetInput ( "title" )
if title == "" {
return nil , errors . New ( "title cannot be empty" )
2024-02-20 21:13:34 +00:00
}
2024-03-07 23:37:15 +00:00
body := githubactions . GetInput ( "body" )
2024-02-20 21:13:34 +00:00
2024-03-07 23:37:15 +00:00
assigneesRaw := githubactions . GetInput ( "assignees" )
assignees := [ ] string { }
for _ , a := range strings . Split ( assigneesRaw , "," ) {
assignees = append ( assignees , strings . TrimSpace ( a ) )
2024-02-20 21:13:34 +00:00
}
2024-03-07 23:37:15 +00:00
labelsRaw := githubactions . GetInput ( "labels" )
labels := [ ] string { }
for _ , l := range strings . Split ( labelsRaw , "," ) {
labels = append ( labels , strings . TrimSpace ( l ) )
2024-02-20 21:13:34 +00:00
}
2024-03-08 11:04:05 +00:00
var head string
headRaw := githubactions . GetInput ( "head" )
if headRaw == "" {
2024-03-08 11:13:40 +00:00
if os . Getenv ( "GITHUB_REF_TYPE" ) != "branch" {
2024-03-08 11:04:05 +00:00
return nil , fmt . Errorf ( "set the \"head\" parameter or work from a branch: only branch can create a pull request: %v given as parameter GITHUB_REF_TYPE" , githubactions . GetInput ( "GITHUB_REF_TYPE" ) )
}
2024-03-08 11:13:40 +00:00
head = os . Getenv ( "GITHUB_REF_NAME" )
2024-03-08 11:04:05 +00:00
} else {
head = headRaw
2024-02-20 21:13:34 +00:00
}
2024-03-07 23:37:15 +00:00
return & CreatePrConfig {
2024-03-08 10:56:17 +00:00
Org : ctx . RepositoryOwner ,
2024-03-08 11:13:40 +00:00
Repo : repo ,
2024-03-08 11:04:05 +00:00
HeadBranch : head ,
2024-03-07 23:37:15 +00:00
BaseBranch : base ,
Title : title ,
Body : body ,
Assignees : assignees ,
Labels : labels ,
} , nil
}
func main ( ) {
2024-03-10 15:25:48 +00:00
fmt . Println ( "Starting result CreatePullRequest, main" )
2024-03-08 11:13:40 +00:00
ctx , err := githubactions . Context ( )
if err != nil {
githubactions . Fatalf ( "could not get context: %v" , err . Error ( ) )
}
2024-03-07 23:37:15 +00:00
2024-03-08 11:13:40 +00:00
token := os . Getenv ( "GITHUB_TOKEN" )
fmt . Printf ( "Api url is %v\n" , ctx . ServerURL )
2024-03-07 23:37:15 +00:00
2024-03-08 11:13:40 +00:00
config , err := ParseActionConfig ( * ctx )
2024-03-07 23:37:15 +00:00
if err != nil {
githubactions . Fatalf ( "%v" , err . Error ( ) )
}
2024-03-10 15:25:48 +00:00
pr , result , err := createPullRequest ( ctx . ServerURL , token , * config )
2024-03-07 23:37:15 +00:00
if err != nil {
githubactions . Fatalf ( "Error while creating pr: %v" , err . Error ( ) )
}
2024-03-08 11:54:52 +00:00
fmt . Printf ( "Created PR with id %d\n" , pr . ID )
2024-03-07 23:37:15 +00:00
githubactions . SetOutput ( "pull-request-number" , strconv . FormatInt ( pr . Index , 10 ) )
2024-03-10 15:25:48 +00:00
githubactions . SetOutput ( "pull-request-result" , result )
2024-03-07 23:37:15 +00:00
githubactions . SetOutput ( "pull-request-url" , pr . URL )
2024-03-10 15:25:48 +00:00
fmt . Println ( "Ending result CreatePullRequest, main" )
2024-02-20 21:13:34 +00:00
}
2024-03-08 10:56:17 +00:00
// Agent which will perform changes on gitea
type Agent struct {
client * gitea . Client
}
// CreatePrConfig represents the configuration for creating a pull request
type CreatePrConfig struct {
// the organization where the PR is created
Org string
// the repository where the PR is created
Repo string
// the branch where the changes are made
HeadBranch string
// the branch where the changes will be added
BaseBranch string
// the title of the pull requests
Title string
// the body of the pull requests
Body string
// the list of assignees
Assignees [ ] string
// the list of requested labels
Labels [ ] string
}
2024-03-10 15:25:48 +00:00
// ExistingOpenPullRequest checks if there is an existing pull request for the same head branch and return it
func ( a * Agent ) ExistingOpenPullRequest ( config CreatePrConfig ) ( bool , * gitea . PullRequest , error ) {
2024-03-08 10:56:17 +00:00
currentPage := 1
for currentPage != 0 {
pulls , response , err := a . client . ListRepoPullRequests ( config . Org , config . Repo ,
gitea . ListPullRequestsOptions { State : gitea . StateOpen , ListOptions : gitea . ListOptions { Page : currentPage } } )
if err != nil {
2024-03-10 15:25:48 +00:00
return false , nil , err
2024-03-08 10:56:17 +00:00
}
2024-03-10 15:25:48 +00:00
for _ , pull := range pulls {
if pull . Head . Name == config . HeadBranch {
return true , pull , nil
2024-03-08 10:56:17 +00:00
}
}
currentPage = response . NextPage
}
2024-03-10 15:25:48 +00:00
return false , nil , nil
2024-03-08 10:56:17 +00:00
}
// labelsFromString retrieves a list of labels from a repository based on the provided configuration.
// It uses the Gitea client to list all labels in the repository and filters them based on the provided label names.
// The method takes a CreatePrConfig struct as a parameter which contains the organization, repository, and label details.
// It returns a slice of gitea.Label that matches the provided label names and an error if any occurred.
func ( a * Agent ) labelsFromString ( config CreatePrConfig ) ( [ ] gitea . Label , error ) {
foundLabels := [ ] gitea . Label { }
currentPage := 1
for currentPage != 0 {
labels , response , err := a . client . ListRepoLabels ( config . Org , config . Repo , gitea . ListLabelsOptions { ListOptions : gitea . ListOptions { Page : currentPage } } )
if err != nil {
return nil , err
}
for _ , label := range labels {
if slices . Contains ( config . Labels , label . Name ) {
foundLabels = append ( foundLabels , * label )
}
}
currentPage = response . NextPage
}
return foundLabels , nil
}
// createPullRequestGitea creates a pull request in a Gitea repository based on the provided configuration.
// It retrieves the label IDs for the given labels and uses them when creating the pull request.
// The method takes a CreatePrConfig struct as a parameter which contains the organization, repository, and pull request details.
// It returns the created pull request and any error encountered during the process.
func ( a * Agent ) createPullRequestGitea ( config CreatePrConfig ) ( * gitea . PullRequest , error ) {
labelIds := [ ] int64 { }
labels , err := a . labelsFromString ( config )
if err != nil {
return nil , err
}
for _ , label := range labels {
labelIds = append ( labelIds , label . ID )
}
if err != nil {
return nil , err
}
pr , _ , err := a . client . CreatePullRequest ( config . Org , config . Repo , gitea . CreatePullRequestOption {
Head : config . HeadBranch ,
Base : config . BaseBranch ,
Title : config . Title ,
Body : config . Body ,
Assignees : config . Assignees ,
Labels : labelIds ,
Deadline : nil ,
} )
if err != nil {
return nil , err
}
return pr , nil
}
// createPullRequest takes in the API URL, access token, and configuration for creating a pull request.
// It initializes a Gitea client using the API URL and access token.
// It creates an instance of the Agent struct using the Gitea client.
2024-03-10 15:25:48 +00:00
// It checks if there is an open pull request with the given branch name in the repository using the ExistingOpenPullRequest method of Agent.
2024-03-08 10:56:17 +00:00
// If an open pull request already exists, it returns nil as the pull request and nil error.
// If no open pull request exists, it creates a new pull request using the createPullRequestGitea method of Agent.
// It returns the created pull request and nil error if successful.
// If there is an error while checking for existing pull requests or creating a new pull request, it returns nil as the pull request and the error.
// The function takes in the following parameters:
// - apiUrl: The URL of the Gitea API.
// - token: The access token for authenticating with the Gitea API.
// - config: The configuration for creating the pull request, including the organization, repository, branch details, title, body, assignees, and labels.
// It returns a pointer to the created pull request and an error.
2024-03-10 15:25:48 +00:00
func createPullRequest ( apiUrl string , token string , config CreatePrConfig ) ( * gitea . PullRequest , string , error ) {
2024-03-08 10:56:17 +00:00
client , _ := gitea . NewClient ( apiUrl , gitea . SetToken ( token ) )
agent := & Agent { client : client }
2024-03-10 15:25:48 +00:00
has , pull , err := agent . ExistingOpenPullRequest ( config )
2024-03-08 10:56:17 +00:00
if err != nil {
2024-03-10 15:25:48 +00:00
return nil , "error" , err
2024-03-08 10:56:17 +00:00
}
if has {
2024-03-10 15:25:48 +00:00
return pull , "existing" , nil
2024-03-08 10:56:17 +00:00
}
pr , err := agent . createPullRequestGitea ( config )
if err != nil {
2024-03-10 15:25:48 +00:00
return nil , "error" , err
2024-03-08 10:56:17 +00:00
}
2024-03-10 15:25:48 +00:00
return pr , "created" , nil
2024-03-08 10:56:17 +00:00
}