Compare commits

...

2 Commits

Author SHA1 Message Date
Julien Fastré f802f2b6eb
Improve handling of head branch in pull requests
This revision modifies the functionality to handle the head branch in pull requests. It allows for the head branch to be input manually, and provides clearer error messaging when working from a non-branch. Additionally, it updates the description for the base and head parameters in 'action.yml' for better understanding.
2024-03-08 12:04:05 +01:00
Julien Fastré 358b8d696b
Refactor code by merging create-pull-request.go into main.go
The create-pull-request.go has been deleted and its functionalities have been incorporated into main.go. This refactor improves the code structure, by eliminating the file separation which was unnecessary. It maintains all original functionalities, including managing pull requests and labels on Gitea repositories.
2024-03-08 11:56:17 +01:00
3 changed files with 174 additions and 134 deletions

View File

@ -18,8 +18,11 @@ inputs:
description: 'A comma or newline separated list of assignees (GitHub usernames).'
base:
description: >
The pull request base branch.
The pull request base branch (the one into which the new code will be pushed).
required: true
head:
description: >
The pull request head branch (the one within the new code is developed).
outputs:
pull-request-number:
description: 'The pull request number'

View File

@ -1,129 +0,0 @@
package main
import (
"code.gitea.io/sdk/gitea"
"slices"
)
type Agent struct {
client *gitea.Client
}
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
}
func (a *Agent) branchHasOpenPullRequest(config CreatePrConfig) (bool, 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 {
return true, err
}
for _, p := range pulls {
if p.Head.Name == config.HeadBranch {
return true, nil
}
}
currentPage = response.NextPage
}
return false, nil
}
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
}
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
}
func createPullRequest(apiUrl string, token string, config CreatePrConfig) (*gitea.PullRequest, error) {
client, _ := gitea.NewClient(apiUrl, gitea.SetToken(token))
agent := &Agent{client: client}
has, err := agent.branchHasOpenPullRequest(config)
if err != nil {
return nil, err
}
if has {
return nil, nil
}
pr, err := agent.createPullRequestGitea(config)
if err != nil {
return nil, err
}
return pr, nil
}

174
main.go
View File

@ -1,14 +1,20 @@
package main
import (
"code.gitea.io/sdk/gitea"
"errors"
"fmt"
"github.com/sethvargo/go-githubactions"
"slices"
"strconv"
"strings"
)
func ParseActionConfig() (*CreatePrConfig, error) {
ctx, err := githubactions.Context()
if err != nil {
return nil, nil
}
base := githubactions.GetInput("base")
if base == "" {
return nil, errors.New("base branch name cannot be empty")
@ -38,14 +44,21 @@ func ParseActionConfig() (*CreatePrConfig, error) {
labels = append(labels, strings.TrimSpace(l))
}
if githubactions.GetInput("GITHUB_REF_TYPE") != "branch" {
return nil, fmt.Errorf("only branch can create a pull request: %v given", githubactions.GetInput("GITHUB_REF_TYPE"))
var head string
headRaw := githubactions.GetInput("head")
if headRaw == "" {
if githubactions.GetInput("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 = githubactions.GetInput("GITHUB_REF_NAME")
} else {
head = headRaw
}
return &CreatePrConfig{
Org: rawRepo[0],
Org: ctx.RepositoryOwner,
Repo: rawRepo[1],
HeadBranch: githubactions.GetInput("GITHUB_REF_NAME"),
HeadBranch: head,
BaseBranch: base,
Title: title,
Body: body,
@ -77,3 +90,156 @@ func main() {
githubactions.SetOutput("pull-request-url", pr.URL)
}
// 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
}
// branchHasOpenPullRequest checks if there is an open pull request with the given branch name in a repository.
// It uses the Gitea client to list all open pull requests in the repository and checks if the branch name matches any of them.
// If a match is found, it returns true indicating that the branch has an open pull request.
// If there is an error listing the pull requests, it returns true along with the error.
// If there are no open pull requests with the branch name, it returns false.
// The method takes a CreatePrConfig struct as a parameter which contains the organization, repository, and branch details.
// It returns a boolean indicating if there is an open pull request and an error if any occurred.
func (a *Agent) branchHasOpenPullRequest(config CreatePrConfig) (bool, 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 {
return true, err
}
for _, p := range pulls {
if p.Head.Name == config.HeadBranch {
return true, nil
}
}
currentPage = response.NextPage
}
return false, 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 branchHasOpenPullRequest 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, error) {
client, _ := gitea.NewClient(apiUrl, gitea.SetToken(token))
agent := &Agent{client: client}
has, err := agent.branchHasOpenPullRequest(config)
if err != nil {
return nil, err
}
if has {
return nil, nil
}
pr, err := agent.createPullRequestGitea(config)
if err != nil {
return nil, err
}
return pr, nil
}