Compare commits
2 Commits
cde3aa9ed6
...
f802f2b6eb
Author | SHA1 | Date |
---|---|---|
Julien Fastré | f802f2b6eb | |
Julien Fastré | 358b8d696b |
|
@ -18,8 +18,11 @@ inputs:
|
||||||
description: 'A comma or newline separated list of assignees (GitHub usernames).'
|
description: 'A comma or newline separated list of assignees (GitHub usernames).'
|
||||||
base:
|
base:
|
||||||
description: >
|
description: >
|
||||||
The pull request base branch.
|
The pull request base branch (the one into which the new code will be pushed).
|
||||||
required: true
|
required: true
|
||||||
|
head:
|
||||||
|
description: >
|
||||||
|
The pull request head branch (the one within the new code is developed).
|
||||||
outputs:
|
outputs:
|
||||||
pull-request-number:
|
pull-request-number:
|
||||||
description: 'The pull request number'
|
description: 'The pull request number'
|
||||||
|
|
|
@ -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
174
main.go
|
@ -1,14 +1,20 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"code.gitea.io/sdk/gitea"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/sethvargo/go-githubactions"
|
"github.com/sethvargo/go-githubactions"
|
||||||
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ParseActionConfig() (*CreatePrConfig, error) {
|
func ParseActionConfig() (*CreatePrConfig, error) {
|
||||||
|
ctx, err := githubactions.Context()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
base := githubactions.GetInput("base")
|
base := githubactions.GetInput("base")
|
||||||
if base == "" {
|
if base == "" {
|
||||||
return nil, errors.New("base branch name cannot be empty")
|
return nil, errors.New("base branch name cannot be empty")
|
||||||
|
@ -38,14 +44,21 @@ func ParseActionConfig() (*CreatePrConfig, error) {
|
||||||
labels = append(labels, strings.TrimSpace(l))
|
labels = append(labels, strings.TrimSpace(l))
|
||||||
}
|
}
|
||||||
|
|
||||||
if githubactions.GetInput("GITHUB_REF_TYPE") != "branch" {
|
var head string
|
||||||
return nil, fmt.Errorf("only branch can create a pull request: %v given", githubactions.GetInput("GITHUB_REF_TYPE"))
|
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{
|
return &CreatePrConfig{
|
||||||
Org: rawRepo[0],
|
Org: ctx.RepositoryOwner,
|
||||||
Repo: rawRepo[1],
|
Repo: rawRepo[1],
|
||||||
HeadBranch: githubactions.GetInput("GITHUB_REF_NAME"),
|
HeadBranch: head,
|
||||||
BaseBranch: base,
|
BaseBranch: base,
|
||||||
Title: title,
|
Title: title,
|
||||||
Body: body,
|
Body: body,
|
||||||
|
@ -77,3 +90,156 @@ func main() {
|
||||||
githubactions.SetOutput("pull-request-url", pr.URL)
|
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
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue