2024-02-20 22:13:34 +01:00
package main
import (
"code.gitea.io/sdk/gitea"
2024-03-08 00:37:15 +01:00
"errors"
2024-02-20 22:13:34 +01:00
"fmt"
2024-03-08 00:37:15 +01:00
"github.com/sethvargo/go-githubactions"
2024-02-20 22:13:34 +01:00
"os"
2024-03-08 00:37:15 +01:00
"slices"
"strconv"
2024-02-20 22:13:34 +01:00
"strings"
)
2024-03-08 00:37:15 +01:00
func ParseActionConfig ( ctx githubactions . GitHubContext ) ( * CreatePrConfig , error ) {
base := githubactions . GetInput ( "base" )
if base == "" {
return nil , errors . New ( "base branch name cannot be empty" )
2024-02-20 22:13:34 +01:00
}
2024-03-08 00:37:15 +01:00
repo := strings . Split ( ctx . Repository , "/" )[ 1 ]
fmt . Printf ( "The repository is %v\n" , repo )
2024-02-20 22:13:34 +01:00
2024-03-08 00:37:15 +01:00
title := githubactions . GetInput ( "title" )
if title == "" {
return nil , errors . New ( "title cannot be empty" )
2024-02-20 22:13:34 +01:00
}
2024-03-08 00:37:15 +01:00
body := githubactions . GetInput ( "body" )
assigneesRaw := githubactions . GetInput ( "assignees" )
assignees := [] string {}
for _ , a := range strings . Split ( assigneesRaw , "," ) {
assignees = append ( assignees , strings . TrimSpace ( a ))
2024-02-20 22:13:34 +01:00
}
2024-03-08 00:37:15 +01:00
labelsRaw := githubactions . GetInput ( "labels" )
labels := [] string {}
for _ , l := range strings . Split ( labelsRaw , "," ) {
labels = append ( labels , strings . TrimSpace ( l ))
2024-02-20 22:13:34 +01:00
}
2024-03-08 00:37:15 +01:00
var head string
headRaw := githubactions . GetInput ( "head" )
if headRaw == "" {
if os . Getenv ( "GITHUB_REF_TYPE" ) != "branch" {
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" ))
}
head = os . Getenv ( "GITHUB_REF_NAME" )
} else {
head = headRaw
}
return & CreatePrConfig {
Org : ctx . RepositoryOwner ,
Repo : repo ,
HeadBranch : head ,
BaseBranch : base ,
Title : title ,
Body : body ,
Assignees : assignees ,
Labels : labels ,
}, nil
}
func main () {
fmt . Println ( "Starting result CreatePullRequest, main" )
ctx , err := githubactions . Context ()
if err != nil {
githubactions . Fatalf ( "could not get context: %v" , err . Error ())
}
2024-03-11 11:26:05 +00:00
token := githubactions . GetInput ( "token" )
2024-03-08 00:37:15 +01:00
fmt . Printf ( "Api url is %v\n" , ctx . ServerURL )
2024-03-11 11:26:05 +00:00
fmt . Printf ( "Debug: token length is %d characters\n" , len ( token ))
2024-03-08 00:37:15 +01:00
config , err := ParseActionConfig ( * ctx )
if err != nil {
githubactions . Fatalf ( "%v" , err . Error ())
}
pr , result , err := createPullRequest ( ctx . ServerURL , token , * config )
if err != nil {
githubactions . Fatalf ( "Error while creating pr: %v" , err . Error ())
}
fmt . Printf ( "Created PR with id %d\n" , pr . ID )
githubactions . SetOutput ( "pull-request-number" , strconv . FormatInt ( pr . Index , 10 ))
githubactions . SetOutput ( "pull-request-result" , result )
githubactions . SetOutput ( "pull-request-url" , pr . URL )
fmt . Println ( "Ending result CreatePullRequest, main" )
}
// 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
}
// 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 ) {
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-11 11:26:05 +00:00
return false , nil , fmt . Errorf ( "error while listing all exisiting open pull requests: %v" , err . Error ())
2024-03-08 00:37:15 +01:00
}
for _ , pull := range pulls {
if pull . Head . Name == config . HeadBranch {
return true , pull , nil
}
}
currentPage = response . NextPage
}
return false , nil , nil
}
// 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.
// It checks if there is an open pull request with the given branch name in the repository using the ExistingOpenPullRequest method of Agent.
// 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.
func createPullRequest ( apiUrl string , token string , config CreatePrConfig ) ( * gitea . PullRequest , string , error ) {
client , _ := gitea . NewClient ( apiUrl , gitea . SetToken ( token ))
agent := & Agent { client : client }
has , pull , err := agent . ExistingOpenPullRequest ( config )
if err != nil {
return nil , "error" , err
}
if has {
return pull , "existing" , nil
}
pr , err := agent . createPullRequestGitea ( config )
if err != nil {
return nil , "error" , err
}
return pr , "created" , nil
2024-02-20 22:13:34 +01:00
}