2
1
forked from adamm/autogits

146 Commits

Author SHA256 Message Date
ec5ac4fca3 Don't fail on project git pull request creation. 2025-07-11 10:53:38 +02:00
d7132727a7 Create Pull Requests to specified branches
instead of always using DefaultBranch. This means that target needs
always gets specified now.
2025-07-11 10:52:00 +02:00
74f40f536a message typo 2025-07-11 09:40:36 +02:00
cde46e85f3 Enable code stream publishing 2025-07-11 09:40:36 +02:00
4378568953 Fix logic in crash protection
We must not access review.User object if it is nil
2025-07-11 09:40:36 +02:00
c286e12b67 Try to use Staging Master Project as default build target if available
This allows us to set custom build configuration or repository sets for
pull request projects.
2025-07-11 09:40:36 +02:00
cc9ad1703d Don't crash when new packages got added
The build result request of the base project is failing in this
situation, since the requested package does not exist.

Therefore we need to have seperate lists for proper handling.
2025-07-11 09:40:36 +02:00
2f8b6b4ade Temporary hack to include also changed directories
Need to be clean'd up via proper subdir handling
2025-07-11 09:40:36 +02:00
c11def6005 handle build results different when request with lastbuild=1
In that case we need to

 * ignore repo state as it is the current one. There is no last state
 * handle "unkown" state as finished as the package was never attempted,
   but we don't know the reason (eg. broken source or unresolvable)
2025-07-11 09:40:36 +02:00
0bee48472d Implementing cleanup of closed requests 2025-07-11 09:40:36 +02:00
f9021d08b9 PR: fix case where submodule cannot be initialized
Sometimes the commit is already cleaned up and Project Git cannot
be initialized. This should not be an error. Only fatal error
is if we can't update the PR to current state.
2025-07-10 18:28:09 +02:00
7a0394e51b PR: use "open" not "opened" as state 2025-07-10 16:54:28 +02:00
518bc15696 PR: close empty prjgit PRs 2025-07-09 20:39:38 +02:00
51873eb048 PR: log prjgit PrjGit creator 2025-07-09 20:06:13 +02:00
4f33ce979c PR: use MergeBase as ref. branch for prjgit
The target branch can be moving target, so not appropriate
2025-07-09 19:42:26 +02:00
7cc4db2283 common: prune removed remote branches
During a repository update, we need to remove branches that
no longer exist on remote from local cache.
2025-07-09 18:28:37 +02:00
4d9e2f8cab PR: update PrjGit PR when package PRs are removed or added 2025-07-09 18:05:05 +02:00
ed4f27a19e PR: refactor 2025-07-09 17:33:44 +02:00
e438b5b064 common: fix parsing of submodule commit id from tree object 2025-06-26 14:25:20 +02:00
885bb7e537 forward: fix logic
* fix approval/request changes string
* use common.DevelProject fetcher code
* fix parsing of Requests meta
2025-06-26 14:24:21 +02:00
977d75f6e9 reviews: only react to comment
also, reviews are reverse sorted.
fixed some bugs
2025-06-25 16:13:08 +02:00
42a9ee48e0 import: update config files 2025-06-24 16:03:33 +02:00
9333e5c3da PR: fix README quoting 2025-06-24 14:33:06 +02:00
5e29c88dc8 PR: fix README quoting 2025-06-24 14:32:23 +02:00
4f0f101620 importer: handle case of devel project in git 2025-06-23 18:48:09 +02:00
253f009da3 common: Add devel project query 2025-06-23 18:47:12 +02:00
5e66a14fa9 forward-bot: finish initial braindump 2025-06-17 23:39:47 +02:00
e79122e494 forward-bot: additional first code 2025-06-17 19:27:00 +02:00
0b4b1a4e21 common: Add basic OBS request APIs 2025-06-17 19:24:13 +02:00
0019546e30 forward-bot: initial skeleton 2025-06-17 00:46:26 +02:00
6438a8625a Replace PrjGit creation logic 2025-06-16 14:22:21 +02:00
3928fa6429 PR: use config project git branch, not default 2025-06-13 00:06:02 +02:00
e92ac4a592 PR: refactor 2025-06-12 23:51:04 +02:00
a1520ebfb0 PR: PRSet consistency check 2025-06-12 18:44:16 +02:00
c8d65a3ae5 PR: refactor
Move AssociatedPR fetching
2025-06-11 16:28:02 +02:00
b849a72f31 PR: request optional reviews
Ignore these reviews in approval, for otherwise they can be used
to fetch optional review information
2025-06-10 18:48:42 +02:00
568a2f3df8 PR: Add ability to parse optional reviewers
Document reviewer syntax in the Readme.md
2025-06-10 17:20:33 +02:00
30c8b2fe57 PR: require PRs to be in opened state
PR's that are not opened (eg. closed, or merged) cannot be part of
a consistent PRset. Either everything is merged, or everything should
be opened.
2025-06-10 16:31:44 +02:00
69b0f9a5ed PR: fix error logging 2025-06-10 15:59:07 +02:00
a283d4f26f PR: no submitter reviews needed 2025-06-07 21:52:47 +02:00
af898a6b8d pr: manual project only merge ok is manual merge ok 2025-06-07 21:42:11 +02:00
b89cdb7664 PR: fix parsing comments from timeline 2025-06-05 19:15:53 +02:00
d37bfaa9d3 common: workaround case when user do not have gitea accounts and cannot get reviews assigned 2025-06-04 14:59:46 +02:00
90cca05b31 common: fix maintainership parsing when no maintienrs explicitly set 2025-06-04 13:56:04 +02:00
7c229500c1 common: debug logging 2025-06-03 23:46:53 +02:00
290424c4a7 common: sort timeline in desc order 2025-06-03 23:42:02 +02:00
703fa101a4 group-review: fix crash in notification handling when no config 2025-06-03 17:48:09 +02:00
66e4982e2d group-review: fix build 2025-06-03 16:59:46 +02:00
09b1c415dd PR: fix deadlock in verification routines via git/org locking 2025-06-03 16:18:00 +02:00
629b941558 PR: use correct path for local repo cache 2025-06-03 14:13:58 +02:00
aa50481c00 PR: add test for unauthorized merge reviews 2025-06-03 10:48:17 +02:00
bc714ee22d PR: fix build 2025-06-03 10:40:49 +02:00
b8cc0357a7 PR: limit manual merge to Projects
Add "ManualMergeProject" to require "merge ok" sign-offs on
project level only
2025-06-03 00:07:34 +02:00
aed0ac3ee9 PR: allow maintainers to approve merges by default 2025-06-02 23:54:05 +02:00
cca3575596 PR: add "merge ok" manual merge option 2025-06-02 16:22:50 +02:00
69dcebcf74 common: use Timeline for reviews
Gitea doesn't keep track of Stale reviews well. We should parse
Timeline of a PR *always* and apply our own logic to this instead
2025-05-30 16:51:30 +02:00
7da9daddd5 direct: fix error formatting element 2025-05-27 12:33:51 +02:00
cd0c3bc759 common: fix tests 2025-05-27 12:11:21 +02:00
af096af507 pr: require manual merge options for repositories 2025-05-26 18:10:25 +02:00
d150c66427 common: update gitea APIs 2025-05-26 16:55:15 +02:00
3bef967023 wip 2025-05-16 17:57:02 +02:00
9c3658b33e pr: remove pending requests
Remove all pending review requests when we merge
2025-05-13 18:34:56 +02:00
6968cbc942 group-review: use URL and not hardcode amqps for rabbit 2025-05-13 16:43:16 +02:00
2cb7a065a9 common: extract timeline fetcher to common code 2025-05-13 15:32:38 +02:00
35058623a7 group-review: logic fixes
* Only look at reviews after last update or review request
* Re-request reviews if they are needed
* Use timeline to filter reviews
* Ignore reviews not associated with the group name

Issue: adamm/autogits#28
2025-05-13 14:53:10 +02:00
24fe165c46 reviews: use timeline and ignore reviews prior to last push 2025-05-12 19:44:10 +02:00
1498438fee pr: fix fetching for merging 2025-05-10 16:48:06 +02:00
4653904ded pr: merge - preliminary fixes 2025-05-09 17:28:35 +02:00
bd87bf8ce3 staging: reviewer can be nil
If a user is requested reviewer, but is then deleted in Gitea,
it is still there but as "nil" user that doesn't resolve.
2025-05-09 16:55:16 +02:00
364c3f4ab7 staging: fix logging and cache stale, cleaned up repos 2025-05-08 15:55:27 +02:00
fd8b7f1bee staging: add cleaned up notification cache 2025-05-08 14:49:46 +02:00
da32adb16b staging: cleanup logic
Add cleanup logic for finished requests

Merged PRs are immediatelly removed along with any QA subprojects
Unmerged closed PRs are removed after a day, default 48 hours
since closing.
2025-05-08 13:56:31 +02:00
1b5a0ad0c8 common: default cleanup delay is 48 for unmerged PRs 2025-05-08 13:56:13 +02:00
e78fdf4a09 common: set cookies when availalbe, not just 200 res code 2025-05-08 13:55:31 +02:00
0564a50fb5 remove debug code in OBS client 2025-05-08 13:24:20 +02:00
4f7db36123 handle build results different when request with lastbuild=1
In that case we need to

 * ignore repo state as it is the current one. There is no last state
 * handle "unkown" state as finished as the package was never attempted,
   but we don't know the reason (eg. broken source or unresolvable)
2025-05-08 10:49:09 +02:00
41d536ea1b common: fix parsing commit messages 2025-05-08 10:42:33 +02:00
91d915cc28 Drop release targets in pull request projects 2025-05-08 10:42:03 +02:00
c7a300119e Fix QA project setup handling 2025-05-08 10:41:30 +02:00
c5c3e1c115 Implement detection for local repositories
Repositories which build against another repo in the same project need
to do so also in the forked project. This is eg for consuming rpms
from one repo in an image build from same project.
2025-05-08 10:28:38 +02:00
c93788d0ee pr: fixes 2025-05-07 16:10:16 +02:00
1e46f8d0ab common: fix tests 2025-05-07 13:41:59 +02:00
9963ae90ef common: fix tests 2025-05-07 12:45:26 +02:00
a9225bbd76 Merge branch 'refactor' into wip 2025-05-07 12:38:19 +02:00
801fff6e22 common: fix parsing commit messages 2025-05-07 12:31:11 +02:00
b4b0d075be staging: only mark as read when processing is done 2025-05-07 01:08:32 +02:00
16c2eb7090 staging fixes 2025-05-07 00:25:44 +02:00
3264ad1589 staging: status line requires write repo access 2025-05-07 00:05:57 +02:00
cb64635aea pr: use correct prjgit repo name 2025-05-06 23:59:51 +02:00
aeb4c20744 pr: reset submodules if they not agreed 2025-05-06 23:15:27 +02:00
da1df24666 wip 2025-05-06 18:06:04 +02:00
6b3c613f14 wip 2025-05-05 18:57:05 +02:00
eb997e1ae9 common: fix dynamic listening for events 2025-05-05 15:33:20 +02:00
f52d72e04a staging: use status line in PRs 2025-05-05 13:52:46 +02:00
23e2566843 Fix git path compare of meta to pull request
.git is optional, but doesn't matter, so trimming it away
2025-05-05 10:54:31 +02:00
0d0fcef7ac staging: fixes 2025-05-04 20:45:33 +02:00
62a597718b fix parsing test 2025-05-03 14:34:33 +02:00
327cb4ceaf fixes if git cat-file has error 2025-05-02 22:46:31 +02:00
aac475ad16 wip 2025-05-02 16:57:13 +02:00
046a60a6ed move staging config to its own config file 2025-05-02 11:18:23 +02:00
dcf964bf7a wip 2025-04-30 17:26:31 +02:00
bff5f1cab7 common: handle case of missing remote
If repo present, but remote not setup, just set it up
2025-04-30 12:29:32 +02:00
6d1ef184e0 workflow-pr: logging 2025-04-29 19:08:37 +02:00
e30d366f2f workflow-pr: logging updates 2025-04-29 18:00:37 +02:00
4a2fe06f05 staging: refactor 2025-04-28 23:47:05 +02:00
210e7588f1 common: actually remove items we process 2025-04-28 22:05:50 +02:00
72b100124d staging: list notification correctly in logging 2025-04-28 19:51:32 +02:00
996d36aaa8 staging: more refactor 2025-04-28 19:47:05 +02:00
82b5b105b1 staging: refactor 2025-04-28 19:44:32 +02:00
248ec4d03c staging: get last results for reference project 2025-04-28 17:34:54 +02:00
faa21f5453 staging: logging adjustments 2025-04-28 16:57:05 +02:00
21c4a7c1e0 wip 2025-04-28 14:23:59 +02:00
f3f76e7d5b Merge commit '96e1c26600f02a81299d4c121a2239c2a28e3184ef306cb0ac2cf00f0f97202e' into refactor 2025-04-28 12:37:38 +02:00
e341b630a2 wip 2025-04-27 22:53:19 +02:00
58532b9b60 wip 2025-04-25 17:40:44 +02:00
a697ccd0ca sync 2025-04-25 16:55:24 +02:00
4bafe0b4ef Merge branch 'refactor' of c3:gitea_test/autogits into refactor 2025-04-25 16:55:09 +02:00
7af2092ae1 wip 2025-04-24 23:51:46 +02:00
32374f76c1 status 2025-04-23 17:51:59 +02:00
9403b563f6 wip 2025-04-22 23:42:41 +02:00
bd492f8d92 no branch if default 2025-04-17 18:40:20 +02:00
fbc84d551d workflow-direct: use correct remote name instead of origin 2025-04-17 18:21:23 +02:00
874a120f88 we are using master for project git .. this may change 2025-04-17 17:58:18 +02:00
199396c210 Use HuJSON
for the comments and glory
2025-04-17 15:33:18 +02:00
f0de3ad54a workflow-direct: no panic if no changes 2025-04-17 15:12:51 +02:00
bfeac63c57 update repo parsing 2025-04-17 13:34:11 +02:00
d65f37739c fixes 2025-04-17 00:38:53 +02:00
5895e3d02c workflow-direct: add no-op mode, for debugging 2025-04-16 23:49:31 +02:00
0e036b5ec6 workflow-direct: move away from prjgit repo being just repo 2025-04-16 18:07:37 +02:00
1d1602852c direct: GitClone instead of running clone directly 2025-04-15 23:38:41 +02:00
9b5013ee45 git clone lock fixes 2025-04-15 18:15:35 +02:00
ed815c3ad1 unique org_repo remote names 2025-04-15 14:55:19 +02:00
8645063e8d git utils 2025-04-15 13:51:08 +02:00
2d044d5664 git: one generator per app, multiple instances
this allows locking for access for each org
2025-04-14 18:33:18 +02:00
51ba81f257 Merge branch 'main' into refactor 2025-04-11 14:00:00 +02:00
bb7a247f66 common: commit status api 2025-04-11 13:58:20 +02:00
c1f71253a4 devel_update: dead code removal 2025-04-11 13:57:56 +02:00
e257b113b9 devel-importer: helpful scripts 2025-04-09 18:48:30 +02:00
11e0bbaed1 devel-importer: remove remote branches 2025-04-09 16:47:19 +02:00
fb430d8c76 group-review: don't use regex for matching group name 2025-04-09 12:21:55 +02:00
7ed2a7082d Fix notification parsing regex 2025-04-09 11:43:54 +02:00
ba7686189e add GitClone for persistent git clones 2025-04-09 00:03:22 +02:00
9dcd25b69a wip 2025-04-08 19:03:33 +02:00
d89c77e22d common: use hostname:port instead of just hostname for API calls 2025-04-08 16:48:25 +02:00
f91c61cd20 tests 2025-04-08 00:23:24 +02:00
06aef50047 start refactoring PR bot 2025-04-07 19:03:02 +02:00
120 changed files with 13337 additions and 2506 deletions

View File

@@ -1,13 +1,15 @@
all: build
api.json:
api.json::
curl -o api.json https://src.opensuse.org/swagger.v1.json
gitea-generated/client/gitea_api_client.go:: api.json
gitea-generated/client/gitea_api_client.go: api.json
[ -d gitea-generated ] || mkdir gitea-generated
podman run --rm -v $$(pwd):/api ghcr.io/go-swagger/go-swagger generate client -f /api/api.json -t /api/gitea-generated
podman run --rm -v $$(pwd)/..:/api ghcr.io/go-swagger/go-swagger generate client -f /api/common/api.json -t /api/common/gitea-generated
api: gitea-generated/client/gitea_api_client.go mock_gitea_utils.go
swagger: gitea-generated/client/gitea_api_client.go
api:
go generate
build: api

File diff suppressed because it is too large Load Diff

View File

@@ -18,7 +18,7 @@ type BasicPR struct {
Num int64
}
var validOrgAndRepoRx *regexp.Regexp = regexp.MustCompile("^[A-Za-z0-9_-]+$")
var validOrgAndRepoRx *regexp.Regexp = regexp.MustCompile("^[A-Za-z0-9_\\.-]+$")
func parsePrLine(line string) (BasicPR, error) {
var ret BasicPR

View File

@@ -26,12 +26,19 @@ import (
"log"
"os"
"strings"
"github.com/tailscale/hujson"
)
//go:generate mockgen -source=config.go -destination=mock/config.go -typed
const (
ProjectConfigFile = "workflow.config"
StagingConfigFile = "staging.config"
)
type ConfigFile struct {
GitProjectName []string
GitProjectNames []string
}
type ReviewGroup struct {
@@ -39,6 +46,11 @@ type ReviewGroup struct {
Reviewers []string
}
type QAConfig struct {
Name string
Origin string
}
type AutogitConfig struct {
Workflows []string // [pr, direct, test]
Organization string
@@ -46,6 +58,10 @@ type AutogitConfig struct {
Branch string // branch name of PkgGit that aligns with PrjGit submodules
Reviewers []string // only used by `pr` workflow
ReviewGroups []ReviewGroup
Committers []string // group in addition to Reviewers and Maintainers that can order the bot around, mostly as helper for factory-maintainers
ManualMergeOnly bool // only merge with "Merge OK" comment by Project Maintainers and/or Package Maintainers and/or reviewers
ManualMergeProject bool // require merge of ProjectGit PRs with "Merge OK" by ProjectMaintainers and/or reviewers
}
type AutogitConfigs []*AutogitConfig
@@ -57,7 +73,11 @@ func ReadConfig(reader io.Reader) (*ConfigFile, error) {
}
config := ConfigFile{}
if err := json.Unmarshal(data, &config.GitProjectName); err != nil {
data, err = hujson.Standardize(data)
if err != nil {
return nil, fmt.Errorf("Failed to parse json: %w", err)
}
if err := json.Unmarshal(data, &config.GitProjectNames); err != nil {
return nil, fmt.Errorf("Error parsing Git Project paths: %w", err)
}
@@ -79,6 +99,19 @@ type GiteaFileContentAndRepoFetcher interface {
GiteaRepoFetcher
}
func UnmarshalWorkflowConfig(data []byte) (*AutogitConfig, error) {
var config AutogitConfig
data, err := hujson.Standardize(data)
if err != nil {
return nil, fmt.Errorf("Failed to parse json: %w", err)
}
if err := json.Unmarshal(data, &config); err != nil {
return nil, fmt.Errorf("Error parsing workflow config file: %s: %w", string(data), err)
}
return &config, nil
}
func ReadWorkflowConfig(gitea GiteaFileContentAndRepoFetcher, git_project string) (*AutogitConfig, error) {
hash := strings.Split(git_project, "#")
branch := ""
@@ -96,14 +129,14 @@ func ReadWorkflowConfig(gitea GiteaFileContentAndRepoFetcher, git_project string
return nil, fmt.Errorf("Missing org/repo in projectgit: %s", git_project)
}
data, _, err := gitea.GetRepositoryFileContent(a[0], prjGitRepo, branch, "workflow.config")
data, _, err := gitea.GetRepositoryFileContent(a[0], prjGitRepo, branch, ProjectConfigFile)
if err != nil {
return nil, fmt.Errorf("Error fetching 'workflow.config' for %s/%s#%s: %w", a[0], prjGitRepo, branch, err)
}
var config AutogitConfig
if err := json.Unmarshal(data, &config); err != nil {
return nil, fmt.Errorf("Error parsing workflow config file: %s: %w", string(data), err)
config, err := UnmarshalWorkflowConfig(data)
if err != nil {
return nil, err
}
if len(config.Organization) < 1 {
@@ -118,12 +151,12 @@ func ReadWorkflowConfig(gitea GiteaFileContentAndRepoFetcher, git_project string
}
}
config.GitProjectName = config.GitProjectName + "#" + branch
return &config, nil
return config, nil
}
func ResolveWorkflowConfigs(gitea GiteaFileContentAndRepoFetcher, config *ConfigFile) (AutogitConfigs, error) {
configs := make([]*AutogitConfig, 0, len(config.GitProjectName))
for _, git_project := range config.GitProjectName {
configs := make([]*AutogitConfig, 0, len(config.GitProjectNames))
for _, git_project := range config.GitProjectNames {
c, err := ReadWorkflowConfig(gitea, git_project)
if err != nil {
// can't sync, so ignore for now
@@ -159,3 +192,61 @@ func (config *AutogitConfig) GetReviewGroupMembers(reviewer string) ([]string, e
return nil, errors.New("User " + reviewer + " not found as group reviewer for " + config.GitProjectName)
}
func (config *AutogitConfig) GetPrjGit() (string, string, string) {
org := config.Organization
repo := DefaultGitPrj
branch := "master"
a := strings.Split(config.GitProjectName, "/")
if len(a[0]) > 0 {
repo = strings.TrimSpace(a[0])
}
if len(a) == 2 {
if a[0] = strings.TrimSpace(a[0]); len(a[0]) > 0 {
org = a[0]
}
repo = strings.TrimSpace(a[1])
}
b := strings.Split(repo, "#")
if len(b) == 2 {
if b[0] = strings.TrimSpace(b[0]); len(b[0]) > 0 {
repo = b[0]
} else {
repo = DefaultGitPrj
}
if b[1] = strings.TrimSpace(b[1]); len(b[1]) > 0 {
branch = strings.TrimSpace(b[1])
}
}
return org, repo, branch
}
func (config *AutogitConfig) GetRemoteBranch() string {
return "origin_" + config.Branch
}
type StagingConfig struct {
ObsProject string
RebuildAll bool
CleanupDelay int // cleanup delay, in hours, for unmerged closed PRs (def: 48)
// if set, then only use pull request numbers as unique identifiers
StagingProject string
QA []QAConfig
}
func ParseStagingConfig(data []byte) (*StagingConfig, error) {
var staging StagingConfig
data, err := hujson.Standardize(data)
if err != nil {
return nil, err
}
staging.CleanupDelay = 48
if err := json.Unmarshal(data, &staging); err != nil {
return nil, err
}
return &staging, nil
}

View File

@@ -1,14 +1,71 @@
package common_test
import (
"slices"
"testing"
"go.uber.org/mock/gomock"
mock_common "src.opensuse.org/autogits/common/mock"
"src.opensuse.org/autogits/common"
"src.opensuse.org/autogits/common/gitea-generated/models"
mock_common "src.opensuse.org/autogits/common/mock"
)
func TestProjectConfigMatcher(t *testing.T) {
configs := common.AutogitConfigs{
{
Organization: "test",
GitProjectName: "test/prjgit#main",
},
{
Organization: "test",
Branch: "main",
GitProjectName: "test/prjgit#main",
},
}
tests := []struct {
name string
org string
repo string
branch string
config int
}{
{
name: "invalid match",
org: "foo",
repo: "bar",
config: -1,
},
{
name: "default branch",
org: "test",
repo: "foo",
branch: "",
config: 0,
},
{
name: "main branch",
org: "test",
repo: "foo",
branch: "main",
config: 1,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
c := configs.GetPrjGitConfig(test.org, test.repo, test.branch)
if test.config < 0 {
if c != nil {
t.Fatal("Expected nil. Got:", *c)
}
} else if config := configs[test.config]; c != config {
t.Fatal("Expected", *config, "got", *c)
}
})
}
}
func TestConfigWorkflowParser(t *testing.T) {
tests := []struct {
name string
@@ -40,10 +97,94 @@ func TestConfigWorkflowParser(t *testing.T) {
gitea.EXPECT().GetRepositoryFileContent("foo", "bar", "", "workflow.config").Return([]byte(test.config_json), "abc", nil)
gitea.EXPECT().GetRepository("foo", "bar").Return(&test.repo, nil)
_, err := common.ReadWorkflowConfig(gitea, "foo/bar")
config, err := common.ReadWorkflowConfig(gitea, "foo/bar")
if err != nil {
t.Fatal(err)
}
if config.ManualMergeOnly != false {
t.Fatal("This should be false")
}
})
}
}
func TestProjectGitParser(t *testing.T) {
tests := []struct {
name string
prjgit string
org string
branch string
res [3]string
}{
{
name: "repo only",
prjgit: "repo.git",
org: "org",
branch: "br",
res: [3]string{"org", "repo.git", "master"},
},
{
name: "default",
org: "org",
res: [3]string{"org", common.DefaultGitPrj, "master"},
},
{
name: "repo with branch",
org: "org2",
prjgit: "repo.git#somebranch",
res: [3]string{"org2", "repo.git", "somebranch"},
},
{
name: "repo org and branch",
org: "org3",
prjgit: "oorg/foo.bar#point",
res: [3]string{"oorg", "foo.bar", "point"},
},
{
name: "whitespace shouldn't matter",
prjgit: " oorg / \nfoo.bar\t # point ",
res: [3]string{"oorg", "foo.bar", "point"},
},
{
name: "repo org and empty branch",
org: "org3",
prjgit: "oorg/foo.bar#",
res: [3]string{"oorg", "foo.bar", "master"},
},
{
name: "only branch defined",
org: "org3",
prjgit: "#mybranch",
res: [3]string{"org3", "_ObsPrj", "mybranch"},
},
{
name: "only org and branch defined",
org: "org3",
prjgit: "org1/#mybranch",
res: [3]string{"org1", "_ObsPrj", "mybranch"},
},
{
name: "empty org and repo",
org: "org3",
prjgit: "/repo#",
res: [3]string{"org3", "repo", "master"},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
c := &common.AutogitConfig{
Organization: test.org,
Branch: test.branch,
GitProjectName: test.prjgit,
}
i, j, k := c.GetPrjGit()
res := []string{i, j, k}
if !slices.Equal(res, test.res[:]) {
t.Error("Expected", test.res, "but received", res)
}
})
}
}

View File

@@ -33,3 +33,6 @@ const (
TopicApp = "src"
)
// when set, pushing to remote does not happen, and other remote side-effects should also not happen
var IsDryRun bool

View File

@@ -24,10 +24,11 @@ import (
"errors"
"fmt"
"io"
"log"
"os"
"os/exec"
"path"
"path/filepath"
"slices"
"strings"
"sync"
)
@@ -43,12 +44,20 @@ type GitStatusLister interface {
GitStatus(cwd string) ([]GitStatusData, error)
}
type GitDiffLister interface {
GitDiff(cwd, base, head string) (string, error)
}
type Git interface {
// error if git, but wrong remote
GitClone(repo, branch, remoteUrl string) (string, error) // clone, or check if path is already checked out remote and force pulls, error otherwise. Return remotename, errror
GitParseCommits(cwd string, commitIDs []string) (parsedCommits []GitCommit, err error)
GitCatFile(cwd, commitId, filename string) (data []byte, err error)
GetPath() string
GitBranchHead(gitDir, branchName string) (string, error)
GitRemoteHead(gitDir, remoteName, branchName string) (string, error)
io.Closer
GitSubmoduleLister
@@ -58,14 +67,16 @@ type Git interface {
GitExecOrPanic(cwd string, params ...string)
GitExec(cwd string, params ...string) error
GitExecWithOutput(cwd string, params ...string) (string, error)
GitDiffLister
}
type GitHandlerImpl struct {
DebugLogger bool
GitPath string
GitCommiter string
GitEmail string
lock *sync.Mutex
}
func (s *GitHandlerImpl) GetPath() string {
@@ -73,34 +84,88 @@ func (s *GitHandlerImpl) GetPath() string {
}
type GitHandlerGenerator interface {
CreateGitHandler(git_author, email, prjName string) (Git, error)
ReadExistingPath(git_author, email, gitPath string) (Git, error)
CreateGitHandler(org string) (Git, error)
ReadExistingPath(org string) (Git, error)
ReleaseLock(path string)
}
type GitHandlerGeneratorImpl struct{}
type gitHandlerGeneratorImpl struct {
path string
git_author string
email string
func (s *GitHandlerGeneratorImpl) CreateGitHandler(git_author, email, prj_name string) (Git, error) {
gitPath, err := os.MkdirTemp("", prj_name)
if err != nil {
return nil, fmt.Errorf("Cannot create temp dir: %w", err)
}
if err = os.Chmod(gitPath, 0700); err != nil {
return nil, fmt.Errorf("Cannot fix permissions of temp dir: %w", err)
}
return s.ReadExistingPath(git_author, email, gitPath)
lock_lock sync.Mutex
lock map[string]*sync.Mutex // per org
}
func (*GitHandlerGeneratorImpl) ReadExistingPath(git_author, email, gitPath string) (Git, error) {
func AllocateGitWorkTree(basePath, gitAuthor, email string) (*gitHandlerGeneratorImpl, error) {
if fi, err := os.Stat(basePath); err != nil || !fi.IsDir() {
return nil, fmt.Errorf("Git basepath not a valid directory: %s %w", basePath, err)
}
if fi, err := os.Stat(basePath); err != nil {
if os.IsNotExist(err) {
if err = os.MkdirAll(basePath, 0o700); err != nil {
return nil, fmt.Errorf("Cannot create git directory structure: %s: %w", basePath, err)
}
} else {
return nil, fmt.Errorf("Error checking git directory strcture: %s: %w", basePath, err)
}
} else if !fi.IsDir() {
return nil, fmt.Errorf("Invalid git directory structure: %s != directory", basePath)
}
return &gitHandlerGeneratorImpl{
path: basePath,
git_author: gitAuthor,
email: email,
lock: make(map[string]*sync.Mutex),
}, nil
}
func (s *gitHandlerGeneratorImpl) CreateGitHandler(org string) (Git, error) {
path := path.Join(s.path, org)
if fs, err := os.Stat(path); (err != nil && !os.IsNotExist(err)) || (err == nil && !fs.IsDir()) {
return nil, err
} else if err != nil && os.IsNotExist(err) {
if err := os.MkdirAll(path, 0o777); err != nil && !os.IsExist(err) {
return nil, err
}
}
return s.ReadExistingPath(org)
}
func (s *gitHandlerGeneratorImpl) ReadExistingPath(org string) (Git, error) {
LogDebug("Locking git org:", org)
s.lock_lock.Lock()
defer s.lock_lock.Unlock()
if _, ok := s.lock[org]; !ok {
s.lock[org] = &sync.Mutex{}
}
s.lock[org].Lock()
git := &GitHandlerImpl{
GitCommiter: git_author,
GitPath: gitPath,
GitCommiter: s.git_author,
GitEmail: s.email,
GitPath: path.Join(s.path, org),
lock: s.lock[org],
}
return git, nil
}
func (s *gitHandlerGeneratorImpl) ReleaseLock(org string) {
m, ok := s.lock[org]
if ok {
LogDebug("Unlocking git org:", org)
m.Unlock()
}
}
//func (h *GitHandler) ProcessBranchList() []string {
// if h.HasError() {
// return make([]string, 0)
@@ -139,20 +204,96 @@ func (refs *GitReferences) addReference(id, branch string) {
refs.refs = append(refs.refs, GitReference{Branch: branch, Id: id})
}
func (e *GitHandlerImpl) GitBranchHead(gitDir, branchName string) (string, error) {
id, err := e.GitExecWithOutput(gitDir, "rev-list", "-1", branchName)
func (e *GitHandlerImpl) GitClone(repo, branch, remoteUrl string) (string, error) {
LogDebug("Cloning", remoteUrl, " repo:", repo, " branch:", branch)
remoteUrlComp, err := ParseGitRemoteUrl(remoteUrl)
if err != nil {
return "", fmt.Errorf("Can't find default remote branch: %s", branchName)
return "", fmt.Errorf("Cannot parse remote URL: %w", err)
}
remoteBranch := "HEAD"
if len(branch) == 0 && remoteUrlComp != nil {
branch = remoteUrlComp.Commit
remoteBranch = branch
} else if len(branch) > 0 {
remoteBranch = branch
}
remoteName := remoteUrlComp.RemoteName()
if remoteUrlComp != nil {
LogDebug("Clone", *remoteUrlComp, " -> ", remoteName)
} else {
LogDebug("Clone", "[default] -> ", remoteName)
}
remoteRef := remoteName + "/" + remoteBranch
if fi, err := os.Stat(path.Join(e.GitPath, repo)); os.IsNotExist(err) {
if err = e.GitExec("", "clone", "--origin", remoteName, remoteUrl, repo); err != nil {
return remoteName, err
}
} else if err != nil || !fi.IsDir() {
return remoteName, fmt.Errorf("Clone location not a directory or Stat error: %w", err)
} else {
if u, err := e.GitExecWithOutput(repo, "remote", "get-url", remoteName); err != nil {
e.GitExecOrPanic(repo, "remote", "add", remoteName, remoteUrl)
} else if clonedRemote := strings.TrimSpace(u); clonedRemote != remoteUrl {
e.GitExecOrPanic(repo, "remote", "set-url", remoteName, remoteUrl)
}
// check if we have submodule to deinit
if list, _ := e.GitSubmoduleList(repo, "HEAD"); len(list) > 0 {
e.GitExecOrPanic(repo, "submodule", "deinit", "--all", "--force")
}
e.GitExecOrPanic(repo, "fetch", "--prune", remoteName, remoteBranch)
}
refsBytes, err := os.ReadFile(path.Join(e.GitPath, repo, ".git/refs/remotes", remoteName, "HEAD"))
if err != nil {
LogError("Cannot read HEAD of remote", remoteName)
return remoteName, fmt.Errorf("Cannot read HEAD of remote %s", remoteName)
}
refs := string(refsBytes)
if refs[0:5] != "ref: " {
LogError("Unexpected format of remote HEAD ref:", refs)
return remoteName, fmt.Errorf("Unexpected format of remote HEAD ref: %s", refs)
}
if len(branch) == 0 || branch == "HEAD" {
remoteRef = strings.TrimSpace(refs[5:])
branch = remoteRef[strings.LastIndex(remoteRef, "/")+1:]
LogDebug("remoteRef", remoteRef)
LogDebug("branch", branch)
}
args := []string{"fetch", "--prune", remoteName, branch}
if strings.TrimSpace(e.GitExecWithOutputOrPanic(repo, "rev-parse", "--is-shallow-repository")) == "true" {
args = slices.Insert(args, 1, "--unshallow")
}
e.GitExecOrPanic(repo, args...)
return remoteName, e.GitExec(repo, "checkout", "--track", "-B", branch, remoteRef)
}
func (e *GitHandlerImpl) GitBranchHead(gitDir, branchName string) (string, error) {
id, err := e.GitExecWithOutput(gitDir, "show-ref", "--hash", "--verify", "refs/heads/"+branchName)
if err != nil {
return "", fmt.Errorf("Can't find default branch: %s", branchName)
}
return strings.TrimSpace(id), nil
}
func (e *GitHandlerImpl) GitRemoteHead(gitDir, remote, branchName string) (string, error) {
id, err := e.GitExecWithOutput(gitDir, "show-ref", "--hash", "--verify", "refs/remotes/"+remote+"/"+branchName)
if err != nil {
return "", fmt.Errorf("Can't find default branch: %s", branchName)
}
return strings.TrimSpace(id), nil
}
func (e *GitHandlerImpl) Close() error {
if err := os.RemoveAll(e.GitPath); err != nil {
return err
}
e.GitPath = ""
LogDebug("Unlocking git lock")
e.lock.Unlock()
return nil
}
@@ -175,14 +316,16 @@ func (h writeFunc) Close() error {
func (e *GitHandlerImpl) GitExecWithOutputOrPanic(cwd string, params ...string) string {
out, err := e.GitExecWithOutput(cwd, params...)
if err != nil {
log.Panicln("git command failed:", params, "@", cwd, "err:", err)
LogError("git command failed:", params, "@", cwd, "err:", err)
panic(err)
}
return out
}
func (e *GitHandlerImpl) GitExecOrPanic(cwd string, params ...string) {
if err := e.GitExec(cwd, params...); err != nil {
log.Panicln("git command failed:", params, "@", cwd, "err:", err)
LogError("git command failed:", params, "@", cwd, "err:", err)
panic(err)
}
}
@@ -210,17 +353,11 @@ func (e *GitHandlerImpl) GitExecWithOutput(cwd string, params ...string) (string
cmd.Dir = filepath.Join(e.GitPath, cwd)
cmd.Stdin = nil
if e.DebugLogger {
log.Printf("git execute: %#v\n", cmd.Args)
}
LogDebug("git execute @", cwd, ":", cmd.Args)
out, err := cmd.CombinedOutput()
if e.DebugLogger {
log.Println(string(out))
}
LogDebug(string(out))
if err != nil {
if e.DebugLogger {
log.Printf(" *** error: %v\n", err)
}
LogError("git", cmd.Args, " error:", err)
return "", fmt.Errorf("error executing: git %#v \n%s\n err: %w", cmd.Args, out, err)
}
@@ -356,21 +493,29 @@ func parseGitMsg(data <-chan byte) (GitMsg, error) {
}, nil
}
func parseGitCommitHdr(data <-chan byte) ([2]string, error) {
func parseGitCommitHdr(oldHdr [2]string, data <-chan byte) ([2]string, int, error) {
hdr := make([]byte, 0, 60)
val := make([]byte, 0, 1000)
c := <-data
size := 1
if c != '\n' { // end of header marker
for ; c != ' '; c = <-data {
hdr = append(hdr, c)
size++
}
if size == 1 { // continuation header here
hdr = []byte(oldHdr[0])
val = append([]byte(oldHdr[1]), '\n')
}
for c := <-data; c != '\n'; c = <-data {
val = append(val, c)
size++
}
size++
}
return [2]string{string(hdr), string(val)}, nil
return [2]string{string(hdr), string(val)}, size, nil
}
func parseGitCommitMsg(data <-chan byte, l int) (string, error) {
@@ -380,7 +525,6 @@ func parseGitCommitMsg(data <-chan byte, l int) (string, error) {
msg = append(msg, c)
l--
}
// l--
if l != 0 {
return "", fmt.Errorf("Unexpected data in the git commit msg: l=%d", l)
@@ -400,12 +544,14 @@ func parseGitCommit(data <-chan byte) (GitCommit, error) {
var c GitCommit
l := hdr.size
for {
hdr, err := parseGitCommitHdr(data)
var hdr [2]string
hdr, size, err := parseGitCommitHdr(hdr, data)
if err != nil {
return GitCommit{}, nil
}
l -= size
if len(hdr[0])+len(hdr[1]) == 0 { // hdr end marker
if size == 1 {
break
}
@@ -413,10 +559,7 @@ func parseGitCommit(data <-chan byte) (GitCommit, error) {
case "tree":
c.Tree = hdr[1]
}
l -= len(hdr[0]) + len(hdr[1]) + 2
}
l--
c.Msg, err = parseGitCommitMsg(data, l)
return c, err
@@ -453,7 +596,6 @@ func parseTreeEntry(data <-chan byte, hashLen int) (GitTreeEntry, error) {
}
func parseGitTree(data <-chan byte) (GitTree, error) {
hdr, err := parseGitMsg(data)
if err != nil {
return GitTree{}, err
@@ -506,7 +648,7 @@ func (e *GitHandlerImpl) GitParseCommits(cwd string, commitIDs []string) (parsed
var done sync.Mutex
done.Lock()
data_in, data_out := ChanIO{make(chan byte, 256)}, ChanIO{make(chan byte, 70)}
data_in, data_out := ChanIO{make(chan byte)}, ChanIO{make(chan byte)}
parsedCommits = make([]GitCommit, 0, len(commitIDs))
go func() {
@@ -536,15 +678,16 @@ func (e *GitHandlerImpl) GitParseCommits(cwd string, commitIDs []string) (parsed
cmd.Stdout = &data_in
cmd.Stdin = &data_out
cmd.Stderr = writeFunc(func(data []byte) (int, error) {
if e.DebugLogger {
log.Println(string(data))
}
LogError(string(data))
return len(data), nil
})
if e.DebugLogger {
log.Printf("command run: %v\n", cmd.Args)
LogDebug("command run:", cmd.Args)
if e := cmd.Run(); e != nil {
LogError(e)
close(data_in.ch)
close(data_out.ch)
return nil, e
}
err = cmd.Run()
done.Lock()
return
@@ -555,7 +698,7 @@ func (e *GitHandlerImpl) GitCatFile(cwd, commitId, filename string) (data []byte
var done sync.Mutex
done.Lock()
data_in, data_out := ChanIO{make(chan byte, 256)}, ChanIO{make(chan byte, 70)}
data_in, data_out := ChanIO{make(chan byte)}, ChanIO{make(chan byte)}
go func() {
defer done.Unlock()
@@ -563,24 +706,27 @@ func (e *GitHandlerImpl) GitCatFile(cwd, commitId, filename string) (data []byte
data_out.Write([]byte(commitId))
data_out.ch <- '\x00'
c, err := parseGitCommit(data_in.ch)
var c GitCommit
c, err = parseGitCommit(data_in.ch)
if err != nil {
log.Printf("Error parsing git commit: %v\n", err)
LogError("Error parsing git commit:", err)
return
}
data_out.Write([]byte(c.Tree))
data_out.ch <- '\x00'
tree, err := parseGitTree(data_in.ch)
var tree GitTree
tree, err = parseGitTree(data_in.ch)
if err != nil {
if e.DebugLogger {
log.Printf("Error parsing git tree: %v\n", err)
}
LogError("Error parsing git tree:", err)
return
}
for _, te := range tree.items {
if te.isBlob() && te.name == filename {
LogInfo("blob", te.hash)
data_out.Write([]byte(te.hash))
data_out.ch <- '\x00'
data, err = parseGitBlob(data_in.ch)
@@ -588,7 +734,7 @@ func (e *GitHandlerImpl) GitCatFile(cwd, commitId, filename string) (data []byte
}
}
err = fmt.Errorf("file not found: '%s'", filename)
LogError("file not found:", filename)
}()
cmd := exec.Command("/usr/bin/git", "cat-file", "--batch", "-Z")
@@ -601,28 +747,27 @@ func (e *GitHandlerImpl) GitCatFile(cwd, commitId, filename string) (data []byte
cmd.Stdout = &data_in
cmd.Stdin = &data_out
cmd.Stderr = writeFunc(func(data []byte) (int, error) {
if e.DebugLogger {
log.Println(string(data))
}
LogError(string(data))
return len(data), nil
})
if e.DebugLogger {
log.Printf("command run: %v\n", cmd.Args)
LogDebug("command run:", cmd.Args)
if e := cmd.Run(); e != nil {
LogError(e)
close(data_in.ch)
close(data_out.ch)
return nil, e
}
err = cmd.Run()
done.Lock()
return
}
// return (filename) -> (hash) map for all submodules
// TODO: recursive? map different orgs, not just assume '.' for path
func (e *GitHandlerImpl) GitSubmoduleList(gitPath, commitId string) (submoduleList map[string]string, err error) {
var done sync.Mutex
submoduleList = make(map[string]string)
done.Lock()
data_in, data_out := ChanIO{make(chan byte, 256)}, ChanIO{make(chan byte, 70)}
data_in, data_out := ChanIO{make(chan byte)}, ChanIO{make(chan byte)}
go func() {
defer done.Unlock()
@@ -636,19 +781,33 @@ func (e *GitHandlerImpl) GitSubmoduleList(gitPath, commitId string) (submoduleLi
err = fmt.Errorf("Error parsing git commit. Err: %w", err)
return
}
data_out.Write([]byte(c.Tree))
data_out.ch <- '\x00'
var tree GitTree
tree, err = parseGitTree(data_in.ch)
if err != nil {
err = fmt.Errorf("Error parsing git tree: %w", err)
return
}
trees := make(map[string]string)
trees[""] = c.Tree
for _, te := range tree.items {
if te.isSubmodule() {
submoduleList[te.name] = te.hash
for len(trees) > 0 {
for p, tree := range trees {
delete(trees, p)
data_out.Write([]byte(tree))
data_out.ch <- '\x00'
var tree GitTree
tree, err = parseGitTree(data_in.ch)
if err != nil {
err = fmt.Errorf("Error parsing git tree: %w", err)
return
}
for _, te := range tree.items {
if te.isTree() {
trees[p+te.name+"/"] = te.hash
submoduleList[p+te.name] = te.hash
} else if te.isSubmodule() {
submoduleList[p+te.name] = te.hash
}
}
}
}
}()
@@ -663,34 +822,32 @@ func (e *GitHandlerImpl) GitSubmoduleList(gitPath, commitId string) (submoduleLi
cmd.Stdout = &data_in
cmd.Stdin = &data_out
cmd.Stderr = writeFunc(func(data []byte) (int, error) {
if e.DebugLogger {
log.Println(string(data))
}
LogError(string(data))
return len(data), nil
})
if e.DebugLogger {
log.Printf("command run: %v\n", cmd.Args)
LogDebug("command run:", cmd.Args)
if e := cmd.Run(); e != nil {
LogError(e)
close(data_in.ch)
close(data_out.ch)
return submoduleList, e
}
err = cmd.Run()
done.Lock()
return submoduleList, err
}
func (e *GitHandlerImpl) GitSubmoduleCommitId(cwd, packageName, commitId string) (subCommitId string, valid bool) {
data_in, data_out := ChanIO{make(chan byte, 256)}, ChanIO{make(chan byte, 70)}
data_in, data_out := ChanIO{make(chan byte)}, ChanIO{make(chan byte)}
var wg sync.WaitGroup
wg.Add(1)
if e.DebugLogger {
log.Printf("getting commit id '%s' from git at '%s' with packageName: %s\n", commitId, cwd, packageName)
}
LogDebug("getting commit id", commitId, "from git at", cwd, "with packageName:", packageName)
go func() {
defer func() {
if recover() != nil {
subCommitId = "wrong"
subCommitId = ""
commitId = "ok"
valid = false
}
@@ -703,14 +860,16 @@ func (e *GitHandlerImpl) GitSubmoduleCommitId(cwd, packageName, commitId string)
data_out.ch <- '\x00'
c, err := parseGitCommit(data_in.ch)
if err != nil {
log.Panicf("Error parsing git commit: %v\n", err)
LogError("Error parsing git commit:", err)
panic(err)
}
data_out.Write([]byte(c.Tree))
data_out.ch <- '\x00'
tree, err := parseGitTree(data_in.ch)
if err != nil {
log.Panicf("Error parsing git tree: %v\n", err)
LogError("Error parsing git tree:", err)
panic(err)
}
for _, te := range tree.items {
@@ -731,18 +890,19 @@ func (e *GitHandlerImpl) GitSubmoduleCommitId(cwd, packageName, commitId string)
cmd.Stdout = &data_in
cmd.Stdin = &data_out
cmd.Stderr = writeFunc(func(data []byte) (int, error) {
log.Println(string(data))
LogError(string(data))
return len(data), nil
})
if e.DebugLogger {
log.Printf("command run: %v\n", cmd.Args)
}
if err := cmd.Run(); err != nil {
log.Printf("Error running command %v, err: %v", cmd.Args, err)
LogDebug("command run:", cmd.Args)
if e := cmd.Run(); e != nil {
LogError(e)
close(data_in.ch)
close(data_out.ch)
return subCommitId, false
}
wg.Wait()
return subCommitId, len(subCommitId) == len(commitId)
return subCommitId, len(subCommitId) > 0
}
const (
@@ -898,9 +1058,7 @@ func parseGitStatusData(data io.ByteReader) ([]GitStatusData, error) {
}
func (e *GitHandlerImpl) GitStatus(cwd string) (ret []GitStatusData, err error) {
if e.DebugLogger {
log.Println("getting git-status()")
}
LogDebug("getting git-status()")
cmd := exec.Command("/usr/bin/git", "status", "--porcelain=2", "-z")
cmd.Env = []string{
@@ -910,16 +1068,37 @@ func (e *GitHandlerImpl) GitStatus(cwd string) (ret []GitStatusData, err error)
}
cmd.Dir = filepath.Join(e.GitPath, cwd)
cmd.Stderr = writeFunc(func(data []byte) (int, error) {
log.Println(string(data))
LogError(string(data))
return len(data), nil
})
if e.DebugLogger {
log.Printf("command run: %v\n", cmd.Args)
}
LogDebug("command run:", cmd.Args)
out, err := cmd.Output()
if err != nil {
log.Printf("Error running command %v, err: %v", cmd.Args, err)
LogError("Error running command", cmd.Args, err)
}
return parseGitStatusData(bufio.NewReader(bytes.NewReader(out)))
}
func (e *GitHandlerImpl) GitDiff(cwd, base, head string) (string, error) {
LogDebug("getting diff from", base, "..", head)
cmd := exec.Command("/usr/bin/git", "diff", base+".."+head)
cmd.Env = []string{
"GIT_CEILING_DIRECTORIES=" + e.GitPath,
"GIT_LFS_SKIP_SMUDGE=1",
"GIT_CONFIG_GLOBAL=/dev/null",
}
cmd.Dir = filepath.Join(e.GitPath, cwd)
cmd.Stderr = writeFunc(func(data []byte) (int, error) {
LogError(string(data))
return len(data), nil
})
LogDebug("command run:", cmd.Args)
out, err := cmd.Output()
if err != nil {
LogError("Error running command", cmd.Args, err)
}
return string(out), nil
}

View File

@@ -29,6 +29,70 @@ import (
"testing"
)
func TestGitClone(t *testing.T) {
tests := []struct {
name string
repo string
branch string
remoteName string
remoteUrl string
}{
{
name: "Basic clone",
repo: "pkgAclone",
branch: "main",
remoteName: "pkgA_main",
remoteUrl: "/pkgA",
},
{
name: "Remote branch is non-existent",
repo: "pkgAclone",
branch: "main_not_here",
remoteName: "pkgA_main",
remoteUrl: "/pkgA",
},
}
return
execPath, err := os.Getwd()
if err != nil {
t.Fatal(err)
}
d := t.TempDir()
os.Chdir(d)
defer os.Chdir(execPath)
cmd := exec.Command(path.Join(execPath, "test_clone_setup.sh"))
if _, err := cmd.Output(); err != nil {
t.Fatal(err)
}
gh, err := AllocateGitWorkTree(d, "Test", "test@example.com")
if err != nil {
t.Fatal(err)
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
g, err := gh.CreateGitHandler("org")
if err != nil {
t.Fatal(err)
}
if _, err := g.GitClone(test.repo, test.branch, "file://"+d+test.remoteUrl); err != nil {
t.Fatal(err)
}
id, err := g.GitBranchHead(test.repo, test.branch)
if err != nil {
t.Fatal(err)
}
t.Fatal(id)
})
}
}
func TestGitMsgParsing(t *testing.T) {
t.Run("tree message with size 56", func(t *testing.T) {
const hdr = "f40888ea4515fe2e8eea617a16f5f50a45f652d894de3ad181d58de3aafb8f98 tree 56\x00"
@@ -136,7 +200,7 @@ committer Adam Majer <amajer@suse.com> 1720709149 +0200
})
t.Run("parse multiline headers", func(t *testing.T) {
const commitData = "cae5831ab48470ff060a5aaa12eb6e5a7acaf91e commit 1491\x00" +
const commitData = "cae5831ab48470ff060a5aaa12eb6e5a7acaf91e commit 1492\000" +
`tree 1f9c8fe8099615d6d3921528402ac53f09213b02
parent e08a654fae0ecc91678819e0b62a2e014bad3339
author Yagiz Nizipli <yagiz@nizipli.com> 1720967314 -0400
@@ -168,7 +232,7 @@ Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Ulises Gascón <ulisesgascongonzalez@gmail.com>
Reviewed-By: Richard Lau <rlau@redhat.com>
Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>` + "\x00"
Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>` + "\000"
ch := make(chan byte, 5000)
for _, b := range []byte(commitData) {
@@ -189,6 +253,51 @@ Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>` + "\x00"
}
})
t.Run("parse multiline headers", func(t *testing.T) {
const commitData = "c07c52c57a10fb355956df3caad2986613838f149274fbe312ad76560764829d commit 1150\000" + `tree 3e06b280ea056141ed5e8af9794a41ae5281930c45321803eab53a240cb60044
parent 19362a2cecb1fd25a89e03611d08ac68dcb1732f9dc0a68a40926356787fa4ca
author Adrian Schröter <adrian@suse.de> 1746600403 +0200
committer Adrian Schröter <adrian@suse.de> 1746600403 +0200
gpgsig-sha256 -----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEE1QF1zm/pNbvyhgLFkY2MlUwI22cFAmgbAd0ACgkQkY2MlUwI
22dxtA//eUCzIqxVdaEnOrFeTyxKig/mCOjaAyctmwr0vXUyElRtjXe4TzVG3QtR
uDfhIrKYLZ2tU/0TewTW/4XopWxLuqEzVQLrjuYl7K5P3GoYk52W1yGT0szzm7/i
87j4UdRL9YGU/gYO7nSzstcfTP6AcmYzVUoOnwYR0K2vyOVjO4niL3mFXxLkIgIt
jd82xcE4JpQz9Yjyq2nDdz4A55kLAwsqY+dOct4oC6bZmj1/JeoGQfPvUsvsQgcI
syCHVh0GBxjvSv50V/VPzxQTFMal/TdtvAD4kmP/9RDi/5THzus8Peam8pV0gEIC
Q15ZcuLwIsC9i7ifUDYgzLgBBRdpSI0qji4Y6clWULPVjsyghgyfQw1trBSySpC8
O1XfajUM+rXyrBLP6kzY+zl/zyzRdJ8JhljmC+SmNuyyEB77Hkn83k0f+aBhhqC2
4b3fIsKtwJZ1w6gr6SSz1BottiT9ShQzRaL8iRoF/2l5MkHPR+QFg2J7EIBqCbCQ
hFUjdvWAXQBWkkTQlJmLmJBXDOLQg3o6xCbnZM0gPFjZWE7e3Mpky7H0+xPnoeg9
ukuvkexXQ6yrdiekA7HRLc76Te/I0m7KDOOWZ3rbJV6uH/3ps4FbLQTZO12AtZ6J
n8hYdYfw9yjCxiKUjnEtXtDRe8DJpqv+hO0Wj4MI5gIA2JE2lzY=
=Keg5
-----END PGP SIGNATURE-----
dummy change, don't merge
` + "\000"
ch := make(chan byte)
go func() {
for _, b := range []byte(commitData) {
ch <- b
}
}()
commit, err := parseGitCommit(ch)
if err != nil {
t.Error(err)
}
if commit.Tree != "3e06b280ea056141ed5e8af9794a41ae5281930c45321803eab53a240cb60044" {
t.Errorf("Invalid commit object: %#v", commit)
}
if commit.Msg != "dummy change, don't merge\n" {
t.Errorf("Invalid commit msg: '%s'", commit.Msg)
}
})
t.Run("parse tree object", func(t *testing.T) {
const treeData = "\x31\x61\x30\x35\x64\x62\x37\x33\x36\x39\x33\x37\x34\x33\x30\x65\x31\x38\x64\x66\x34\x33\x61\x32\x37\x61\x39\x38\x30\x30\x31\x30\x31\x32\x65\x31\x65\x64\x32\x30\x34\x38\x32\x39\x38\x36\x37\x31\x32\x38\x66\x32\x63\x65\x38\x34\x30\x36\x62\x35\x63\x66\x63\x39\x20\x74\x72\x65\x65\x20\x32\x30\x35\x00\x34\x30\x30\x30\x30\x20\x62\x6f\x74\x73\x2d\x63\x6f\x6d\x6d\x6f\x6e\x00\x93\x17\xaa\x47\xf6\xea\x37\xe8\xbc\xe2\x80\x77\x57\x90\xf4\xa8\x01\xd7\xe3\x70\x2f\x84\xfb\xe1\xb0\x0e\x4a\x2c\x1c\x75\x2c\x2b\x34\x30\x30\x30\x30\x20\x6f\x62\x73\x2d\x73\x74\x61\x67\x69\x6e\x67\x2d\x62\x6f\x74\x00\x79\x77\x8b\x28\x7d\x37\x10\x59\xb9\x71\x28\x36\xed\x20\x31\x5f\xfb\xe1\xed\xb5\xba\x4f\x5e\xbb\x65\x65\x68\x23\x77\x32\x58\xfe\x34\x30\x30\x30\x30\x20\x70\x72\x2d\x72\x65\x76\x69\x65\x77\x00\x36\x0d\x45\xcb\x76\xb8\x93\xb3\x21\xba\xfa\xd5\x00\x9d\xfc\x59\xab\x88\xc1\x3c\x81\xcb\x48\x5a\xe0\x29\x29\x0f\xe3\x6b\x3c\x5e\x34\x30\x30\x30\x30\x20\x70\x72\x6a\x67\x69\x74\x2d\x75\x70\x64\x61\x74\x65\x72\x00\xb4\x0b\x1c\xf5\xfb\xec\x9a\xb2\x9f\x48\x3e\x21\x18\x0d\x51\xb7\x98\x6e\x21\x99\x74\x84\x67\x71\x41\x24\x42\xfc\xc9\x04\x12\x99\x00"
@@ -243,9 +352,36 @@ Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>` + "\x00"
t.Error("expected submodule not found")
}
})
t.Run("parse nested trees with subtrees", func(t *testing.T) {
const data = "873a323b262ebb3bd77b2592b2e11bdd08dbc721cbf4ac9f97637e58e1fffce7 tree 1083\x00100644\x20\x2Egitattributes\x00\xD8v\xA95\x87\xC1\xA9\xFCPn\xDD\xD4\x13\x9B\x8E\xD2\xCFs\xBD\x11q\x8A\xAE\x8A\x7Cg\xE2C\x14J\x01\xB0100644\x20\x2Egitignore\x00\xC3\xCD\x8En\x887\x3AJ\xA0P\xEEL\xD4\xF5\xD2v\x9C\xA6v\xC5D\x60\x40\x95\xD1\x0B\xA4\xB8\x86\xD4rE100644\x20COPYING\x00\x12\x2A\x28\xC8\xB9\x5D\x9B\x8A\x23\x1F\xE96\x07\x3F\xA9D\x90\xFD\xCE\x2Bi\x2D\x031\x5C\xCC\xC4fx\x00\xC22100644\x20README\x2Emd\x00\x92D\xF7\xFF\x0E0\x5C\xF2\xAC\x0DA\x06\x92\x0B\xD6z\x3CGh\x00y\x7EW1\xB9a\x8Ch\x215Fa100644\x20_service\x00\xC51\xF2\x12\xF3\x24\x9C\xD9\x9F\x0A\x93Mp\x12\xC1\xF7i\x05\x95\xC5Z\x06\x95i\x3Az\xC3\xF59\x7E\xF8\x1B100644\x20autogits\x2Echanges\x00\xF7\x8D\xBF\x0A\xCB\x5D\xB7y\x8C\xA9\x9C\xEB\x92\xAFd\x2C\x98\x23\x0C\x13\x13\xED\xDE\x5D\xBALD6\x3BR\x5B\xCA100644\x20autogits\x2Espec\x00\xD2\xBC\x20v\xD3\xE5F\xCA\xEE\xEA\x18\xC84\x0D\xA7\xCA\xD8O\xF2\x0A\xAB\x40\x2A\xFAL\x3B\xB4\xE6\x11\xE7o\xD140000\x20common\x00\xE2\xC9dg\xD0\x5D\xD1\xF1\x8ARW\xF0\x96\xD6\x29\x2F\x8F\xD9\xC7\x82\x1A\xB7\xAAw\xB0\xCE\xA8\xFE\xC8\xD7D\xF2100755\x20dev_test_helper\x2Esh\x00\xECY\xDD\xB3rz\x9Fh\xD4\x2E\x85\x02\x13\xF8\xFE\xB57\x8B\x1B6\x8E\x09dC\x1E\xE0\x90\x09\x08\xED\xBD_40000\x20devel\x2Dimporter\x00v\x98\x9B\x92\xD8\x24lu\xFC\xB2d\xC9\xCENb\xEE\x0F\x21\x8B\x92\x88\xDBs\xF8\x2E\xA8\xC8W\x1C\x20\xCF\xD440000\x20doc\x00\x8Akyq\xD0\xCF\xB8\x2F\x80Y\x2F\x11\xF0\x14\xA9\xFE\x96\x14\xE0W\x2C\xCF\xB9\x86\x7E\xFDi\xD7\x1F\x08Q\xFB40000\x20gitea\x2Devents\x2Drabbitmq\x2Dpublisher\x00\x5Cb\x3Fh\xA2\x06\x06\x0Cd\x09\xA5\xD9\xF7\x23\x5C\xF85\xF5\xB8\xBE\x7F\xD4O\x25t\xEF\xCC\xAB\x18\x7C\x0C\xF3100644\x20go\x2Emod\x00j\x85\x0B\x03\xC8\x9F\x9F\x0F\xC8\xE0\x8C\xF7\x3D\xC19\xF7\x12gk\xD6\x18JN\x24\xC0\x1C\xBE\x97oY\x02\x8D100644\x20go\x2Esum\x00h\x88\x2E\x27\xED\xD39\x8D\x12\x0F\x7D\x97\xA2\x5DE\xB9\x82o\x0Cu\xF4l\xA17s\x28\x2BQT\xE6\x12\x9040000\x20group\x2Dreview\x00\x7E\x7B\xB42\x0F\x3B\xC9o\x2C\xE79\x1DR\xE2\xE4i\xAE\xF6u\x90\x09\xD8\xC9c\xE7\xF7\xC7\x92\xFB\xD7\xDD140000\x20obs\x2Dstaging\x2Dbot\x00\x12\xE8\xAF\x09\xD4\x5D\x13\x8D\xC9\x0AvPDc\xB6\x7C\xAC4\xD9\xC5\xD4_\x98i\xBE2\xA7\x25aj\xE2k40000\x20obs\x2Dstatus\x2Dservice\x00MATY\xA3\xFA\xED\x05\xBE\xEB\x2B\x07\x9CN\xA9\xF3SB\x22MlV\xA4\x5D\xDA\x0B\x0F\x23\xA1\xA8z\xD740000\x20systemd\x00\x2D\xE2\x03\x7E\xBD\xEB6\x8F\xC5\x0E\x12\xD4\xBD\x97P\xDD\xA2\x92\xCE6n\x08Q\xCA\xE4\x15\x97\x8F\x26V\x3DW100644\x20vendor\x2Etar\x2Ezst\x00\xD9\x2Es\x03I\x91\x22\x24\xC86q\x91\x95\xEF\xA3\xC9\x3C\x06D\x90w\xAD\xCB\xAE\xEEu2i\xCE\x05\x09u40000\x20workflow\x2Ddirect\x00\x94\xDB\xDFc\xB5A\xD5\x16\xB3\xC3ng\x94J\xE7\x101jYF\x15Q\xE97\xCFg\x14\x12\x28\x3A\xFC\xDB40000\x20workflow\x2Dpr\x00\xC1\xD8Z9\x18\x60\xA2\xE2\xEF\xB0\xFC\xD7\x2Ah\xF07\x0D\xEC\x8A7\x7E\x1A\xAAn\x13\x9C\xEC\x05s\xE8\xBDf\x00"
ch := make(chan byte, 2000)
for _, b := range []byte(data) {
ch <- b
}
tree, err := parseGitTree(ch)
if err != nil {
t.Error(err)
}
found := false
for _, item := range tree.items {
t.Log(item)
if item.name == "workflow-pr" && item.hash == "c1d85a391860a2e2efb0fcd72a68f0370dec8a377e1aaa6e139cec0573e8bd66" && item.isTree() {
found = true
break
}
}
if !found {
t.Error("expected submodule not found")
}
})
}
func TestCommitTreeParsingOfHead(t *testing.T) {
func TestCommitTreeParsing(t *testing.T) {
gitDir := t.TempDir()
testDir, _ := os.Getwd()
var commitId string
@@ -260,11 +396,58 @@ func TestCommitTreeParsingOfHead(t *testing.T) {
t.Fatal(err.Error())
}
gh, err := AllocateGitWorkTree(gitDir, "", "")
if err != nil {
t.Fatal(err)
}
t.Run("GitCatFile commit", func(t *testing.T) {
h, _ := gh.ReadExistingPath(".")
defer h.Close()
file, err := h.GitCatFile("", commitId, "help")
if err != nil {
t.Error("failed", err)
}
if string(file) != "help\n" {
t.Error("expected 'help\\n' but got", string(file))
}
})
t.Run("GitCatFile commit", func(t *testing.T) {
h, _ := gh.ReadExistingPath(".")
defer h.Close()
file, err := h.GitCatFile("", "HEAD", "help")
if err != nil {
t.Error("failed", err)
}
if string(file) != "help\n" {
t.Error("expected 'help\\n' but got", string(file))
}
})
t.Run("GitCatFile bad commit", func(t *testing.T) {
h, _ := gh.ReadExistingPath(".")
defer h.Close()
file, err := h.GitCatFile("", "518b468f391bf01d5d76d497d7cbecfa8b46d185714cf8745800ae18afb21afd", "help")
if err == nil {
t.Error("expected error, but not nothing")
}
if string(file) != "" {
t.Error("expected 'help\\n' but got", file)
}
})
t.Run("reads HEAD and parses the tree", func(t *testing.T) {
const nodejs21 = "c678c57007d496a98bec668ae38f2c26a695f94af78012f15d044ccf066ccb41"
h := GitHandlerImpl{
GitPath: gitDir,
}
h, _ := gh.ReadExistingPath(".")
defer h.Close()
id, ok := h.GitSubmoduleCommitId("", "nodejs21", commitId)
if !ok {
t.Error("failed parse")
@@ -275,9 +458,9 @@ func TestCommitTreeParsingOfHead(t *testing.T) {
})
t.Run("reads README.md", func(t *testing.T) {
h := GitHandlerImpl{
GitPath: gitDir,
}
h, _ := gh.ReadExistingPath(".")
defer h.Close()
data, err := h.GitCatFile("", commitId, "README.md")
if err != nil {
t.Errorf("failed parse: %v", err)
@@ -288,9 +471,8 @@ func TestCommitTreeParsingOfHead(t *testing.T) {
})
t.Run("read HEAD", func(t *testing.T) {
h := GitHandlerImpl{
GitPath: gitDir,
}
h, _ := gh.ReadExistingPath(".")
defer h.Close()
data, err := h.GitSubmoduleList("", "HEAD")
if err != nil {
@@ -380,14 +562,13 @@ func TestGitStatusParse(t *testing.T) {
name: "Renamed file",
data: []byte("1 M. N... 100644 100644 100644 d23eb05d9ca92883ab9f4d28f3ec90c05f667f3a5c8c8e291bd65e03bac9ae3c 896cd09f36d39e782d66ae32dd5614d4f4d83fc689f132aab2dfc019a9f5b6f3 .gitmodules\x002 R. S... 160000 160000 160000 3befe051a34612530acfa84c736d2454278453ec0f78ec028f25d2980f8c3559 3befe051a34612530acfa84c736d2454278453ec0f78ec028f25d2980f8c3559 R100 pkgQ\x00pkgC\x00"),
res: []GitStatusData{
{
Path: "pkgQ",
{
Path: "pkgQ",
Status: GitStatus_Renamed,
States: [3]string{"pkgC"},
},
{
Path: ".gitmodules",
{
Path: ".gitmodules",
Status: GitStatus_Modified,
},
},

View File

@@ -36,6 +36,12 @@ func (o *IssueEditIssueAttachmentReader) ReadResponse(response runtime.ClientRes
return nil, err
}
return nil, result
case 422:
result := NewIssueEditIssueAttachmentUnprocessableEntity()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
case 423:
result := NewIssueEditIssueAttachmentLocked()
if err := result.readResponse(response, consumer, o.formats); err != nil {
@@ -189,6 +195,78 @@ func (o *IssueEditIssueAttachmentNotFound) readResponse(response runtime.ClientR
return nil
}
// NewIssueEditIssueAttachmentUnprocessableEntity creates a IssueEditIssueAttachmentUnprocessableEntity with default headers values
func NewIssueEditIssueAttachmentUnprocessableEntity() *IssueEditIssueAttachmentUnprocessableEntity {
return &IssueEditIssueAttachmentUnprocessableEntity{}
}
/*
IssueEditIssueAttachmentUnprocessableEntity describes a response with status code 422, with default header values.
APIValidationError is error format response related to input validation
*/
type IssueEditIssueAttachmentUnprocessableEntity struct {
Message string
URL string
}
// IsSuccess returns true when this issue edit issue attachment unprocessable entity response has a 2xx status code
func (o *IssueEditIssueAttachmentUnprocessableEntity) IsSuccess() bool {
return false
}
// IsRedirect returns true when this issue edit issue attachment unprocessable entity response has a 3xx status code
func (o *IssueEditIssueAttachmentUnprocessableEntity) IsRedirect() bool {
return false
}
// IsClientError returns true when this issue edit issue attachment unprocessable entity response has a 4xx status code
func (o *IssueEditIssueAttachmentUnprocessableEntity) IsClientError() bool {
return true
}
// IsServerError returns true when this issue edit issue attachment unprocessable entity response has a 5xx status code
func (o *IssueEditIssueAttachmentUnprocessableEntity) IsServerError() bool {
return false
}
// IsCode returns true when this issue edit issue attachment unprocessable entity response a status code equal to that given
func (o *IssueEditIssueAttachmentUnprocessableEntity) IsCode(code int) bool {
return code == 422
}
// Code gets the status code for the issue edit issue attachment unprocessable entity response
func (o *IssueEditIssueAttachmentUnprocessableEntity) Code() int {
return 422
}
func (o *IssueEditIssueAttachmentUnprocessableEntity) Error() string {
return fmt.Sprintf("[PATCH /repos/{owner}/{repo}/issues/{index}/assets/{attachment_id}][%d] issueEditIssueAttachmentUnprocessableEntity", 422)
}
func (o *IssueEditIssueAttachmentUnprocessableEntity) String() string {
return fmt.Sprintf("[PATCH /repos/{owner}/{repo}/issues/{index}/assets/{attachment_id}][%d] issueEditIssueAttachmentUnprocessableEntity", 422)
}
func (o *IssueEditIssueAttachmentUnprocessableEntity) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// hydrates response header message
hdrMessage := response.GetHeader("message")
if hdrMessage != "" {
o.Message = hdrMessage
}
// hydrates response header url
hdrURL := response.GetHeader("url")
if hdrURL != "" {
o.URL = hdrURL
}
return nil
}
// NewIssueEditIssueAttachmentLocked creates a IssueEditIssueAttachmentLocked with default headers values
func NewIssueEditIssueAttachmentLocked() *IssueEditIssueAttachmentLocked {
return &IssueEditIssueAttachmentLocked{}

View File

@@ -36,6 +36,12 @@ func (o *IssueEditIssueCommentAttachmentReader) ReadResponse(response runtime.Cl
return nil, err
}
return nil, result
case 422:
result := NewIssueEditIssueCommentAttachmentUnprocessableEntity()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
case 423:
result := NewIssueEditIssueCommentAttachmentLocked()
if err := result.readResponse(response, consumer, o.formats); err != nil {
@@ -189,6 +195,78 @@ func (o *IssueEditIssueCommentAttachmentNotFound) readResponse(response runtime.
return nil
}
// NewIssueEditIssueCommentAttachmentUnprocessableEntity creates a IssueEditIssueCommentAttachmentUnprocessableEntity with default headers values
func NewIssueEditIssueCommentAttachmentUnprocessableEntity() *IssueEditIssueCommentAttachmentUnprocessableEntity {
return &IssueEditIssueCommentAttachmentUnprocessableEntity{}
}
/*
IssueEditIssueCommentAttachmentUnprocessableEntity describes a response with status code 422, with default header values.
APIValidationError is error format response related to input validation
*/
type IssueEditIssueCommentAttachmentUnprocessableEntity struct {
Message string
URL string
}
// IsSuccess returns true when this issue edit issue comment attachment unprocessable entity response has a 2xx status code
func (o *IssueEditIssueCommentAttachmentUnprocessableEntity) IsSuccess() bool {
return false
}
// IsRedirect returns true when this issue edit issue comment attachment unprocessable entity response has a 3xx status code
func (o *IssueEditIssueCommentAttachmentUnprocessableEntity) IsRedirect() bool {
return false
}
// IsClientError returns true when this issue edit issue comment attachment unprocessable entity response has a 4xx status code
func (o *IssueEditIssueCommentAttachmentUnprocessableEntity) IsClientError() bool {
return true
}
// IsServerError returns true when this issue edit issue comment attachment unprocessable entity response has a 5xx status code
func (o *IssueEditIssueCommentAttachmentUnprocessableEntity) IsServerError() bool {
return false
}
// IsCode returns true when this issue edit issue comment attachment unprocessable entity response a status code equal to that given
func (o *IssueEditIssueCommentAttachmentUnprocessableEntity) IsCode(code int) bool {
return code == 422
}
// Code gets the status code for the issue edit issue comment attachment unprocessable entity response
func (o *IssueEditIssueCommentAttachmentUnprocessableEntity) Code() int {
return 422
}
func (o *IssueEditIssueCommentAttachmentUnprocessableEntity) Error() string {
return fmt.Sprintf("[PATCH /repos/{owner}/{repo}/issues/comments/{id}/assets/{attachment_id}][%d] issueEditIssueCommentAttachmentUnprocessableEntity", 422)
}
func (o *IssueEditIssueCommentAttachmentUnprocessableEntity) String() string {
return fmt.Sprintf("[PATCH /repos/{owner}/{repo}/issues/comments/{id}/assets/{attachment_id}][%d] issueEditIssueCommentAttachmentUnprocessableEntity", 422)
}
func (o *IssueEditIssueCommentAttachmentUnprocessableEntity) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// hydrates response header message
hdrMessage := response.GetHeader("message")
if hdrMessage != "" {
o.Message = hdrMessage
}
// hydrates response header url
hdrURL := response.GetHeader("url")
if hdrURL != "" {
o.URL = hdrURL
}
return nil
}
// NewIssueEditIssueCommentAttachmentLocked creates a IssueEditIssueCommentAttachmentLocked with default headers values
func NewIssueEditIssueCommentAttachmentLocked() *IssueEditIssueCommentAttachmentLocked {
return &IssueEditIssueCommentAttachmentLocked{}

View File

@@ -64,13 +64,13 @@ type IssueSearchIssuesParams struct {
/* Assigned.
filter (issues / pulls) assigned to you, default is false
Filter issues or pulls assigned to the authenticated user
*/
Assigned *bool
/* Before.
Only show notifications updated before the given time. This is a timestamp in RFC 3339 format
Only show issues updated before the given time (RFC 3339 format)
Format: date-time
*/
@@ -78,49 +78,51 @@ type IssueSearchIssuesParams struct {
/* Created.
filter (issues / pulls) created by you, default is false
Filter issues or pulls created by the authenticated user
*/
Created *bool
/* Labels.
comma separated list of labels. Fetch only issues that have any of this labels. Non existent labels are discarded
Comma-separated list of label names. Fetch only issues that have any of these labels. Non existent labels are discarded.
*/
Labels *string
/* Limit.
page size of results
Number of items per page
*/
Limit *int64
/* Mentioned.
filter (issues / pulls) mentioning you, default is false
Filter issues or pulls mentioning the authenticated user
*/
Mentioned *bool
/* Milestones.
comma separated list of milestone names. Fetch only issues that have any of this milestones. Non existent are discarded
Comma-separated list of milestone names. Fetch only issues that have any of these milestones. Non existent milestones are discarded.
*/
Milestones *string
/* Owner.
filter by owner
Filter by repository owner
*/
Owner *string
/* Page.
page number of results to return (1-based)
Page number of results to return (1-based)
Default: 1
*/
Page *int64
/* PriorityRepoID.
repository to prioritize in the results
Repository ID to prioritize in the results
Format: int64
*/
@@ -128,25 +130,25 @@ type IssueSearchIssuesParams struct {
/* Q.
search string
Search string
*/
Q *string
/* ReviewRequested.
filter pulls requesting your review, default is false
Filter pull requests where the authenticated user's review was requested
*/
ReviewRequested *bool
/* Reviewed.
filter pulls reviewed by you, default is false
Filter pull requests reviewed by the authenticated user
*/
Reviewed *bool
/* Since.
Only show notifications updated after the given time. This is a timestamp in RFC 3339 format
Only show issues updated after the given time (RFC 3339 format)
Format: date-time
*/
@@ -154,19 +156,21 @@ type IssueSearchIssuesParams struct {
/* State.
whether issue is open or closed
State of the issue
Default: "open"
*/
State *string
/* Team.
filter by team (requires organization owner parameter to be provided)
Filter by team (requires organization owner parameter)
*/
Team *string
/* Type.
filter by type (issues / pulls) if set
Filter by issue type
*/
Type *string
@@ -187,7 +191,36 @@ func (o *IssueSearchIssuesParams) WithDefaults() *IssueSearchIssuesParams {
//
// All values with no default are reset to their zero value.
func (o *IssueSearchIssuesParams) SetDefaults() {
// no default values defined for this parameter
var (
assignedDefault = bool(false)
createdDefault = bool(false)
mentionedDefault = bool(false)
pageDefault = int64(1)
reviewRequestedDefault = bool(false)
reviewedDefault = bool(false)
stateDefault = string("open")
)
val := IssueSearchIssuesParams{
Assigned: &assignedDefault,
Created: &createdDefault,
Mentioned: &mentionedDefault,
Page: &pageDefault,
ReviewRequested: &reviewRequestedDefault,
Reviewed: &reviewedDefault,
State: &stateDefault,
}
val.timeout = o.timeout
val.Context = o.Context
val.HTTPClient = o.HTTPClient
*o = val
}
// WithTimeout adds the timeout to the issue search issues params

View File

@@ -30,6 +30,18 @@ func (o *IssueSearchIssuesReader) ReadResponse(response runtime.ClientResponse,
return nil, err
}
return result, nil
case 400:
result := NewIssueSearchIssuesBadRequest()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
case 422:
result := NewIssueSearchIssuesUnprocessableEntity()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
default:
return nil, runtime.NewAPIError("[GET /repos/issues/search] issueSearchIssues", response, response.Code())
}
@@ -102,3 +114,147 @@ func (o *IssueSearchIssuesOK) readResponse(response runtime.ClientResponse, cons
return nil
}
// NewIssueSearchIssuesBadRequest creates a IssueSearchIssuesBadRequest with default headers values
func NewIssueSearchIssuesBadRequest() *IssueSearchIssuesBadRequest {
return &IssueSearchIssuesBadRequest{}
}
/*
IssueSearchIssuesBadRequest describes a response with status code 400, with default header values.
APIError is error format response
*/
type IssueSearchIssuesBadRequest struct {
Message string
URL string
}
// IsSuccess returns true when this issue search issues bad request response has a 2xx status code
func (o *IssueSearchIssuesBadRequest) IsSuccess() bool {
return false
}
// IsRedirect returns true when this issue search issues bad request response has a 3xx status code
func (o *IssueSearchIssuesBadRequest) IsRedirect() bool {
return false
}
// IsClientError returns true when this issue search issues bad request response has a 4xx status code
func (o *IssueSearchIssuesBadRequest) IsClientError() bool {
return true
}
// IsServerError returns true when this issue search issues bad request response has a 5xx status code
func (o *IssueSearchIssuesBadRequest) IsServerError() bool {
return false
}
// IsCode returns true when this issue search issues bad request response a status code equal to that given
func (o *IssueSearchIssuesBadRequest) IsCode(code int) bool {
return code == 400
}
// Code gets the status code for the issue search issues bad request response
func (o *IssueSearchIssuesBadRequest) Code() int {
return 400
}
func (o *IssueSearchIssuesBadRequest) Error() string {
return fmt.Sprintf("[GET /repos/issues/search][%d] issueSearchIssuesBadRequest", 400)
}
func (o *IssueSearchIssuesBadRequest) String() string {
return fmt.Sprintf("[GET /repos/issues/search][%d] issueSearchIssuesBadRequest", 400)
}
func (o *IssueSearchIssuesBadRequest) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// hydrates response header message
hdrMessage := response.GetHeader("message")
if hdrMessage != "" {
o.Message = hdrMessage
}
// hydrates response header url
hdrURL := response.GetHeader("url")
if hdrURL != "" {
o.URL = hdrURL
}
return nil
}
// NewIssueSearchIssuesUnprocessableEntity creates a IssueSearchIssuesUnprocessableEntity with default headers values
func NewIssueSearchIssuesUnprocessableEntity() *IssueSearchIssuesUnprocessableEntity {
return &IssueSearchIssuesUnprocessableEntity{}
}
/*
IssueSearchIssuesUnprocessableEntity describes a response with status code 422, with default header values.
APIValidationError is error format response related to input validation
*/
type IssueSearchIssuesUnprocessableEntity struct {
Message string
URL string
}
// IsSuccess returns true when this issue search issues unprocessable entity response has a 2xx status code
func (o *IssueSearchIssuesUnprocessableEntity) IsSuccess() bool {
return false
}
// IsRedirect returns true when this issue search issues unprocessable entity response has a 3xx status code
func (o *IssueSearchIssuesUnprocessableEntity) IsRedirect() bool {
return false
}
// IsClientError returns true when this issue search issues unprocessable entity response has a 4xx status code
func (o *IssueSearchIssuesUnprocessableEntity) IsClientError() bool {
return true
}
// IsServerError returns true when this issue search issues unprocessable entity response has a 5xx status code
func (o *IssueSearchIssuesUnprocessableEntity) IsServerError() bool {
return false
}
// IsCode returns true when this issue search issues unprocessable entity response a status code equal to that given
func (o *IssueSearchIssuesUnprocessableEntity) IsCode(code int) bool {
return code == 422
}
// Code gets the status code for the issue search issues unprocessable entity response
func (o *IssueSearchIssuesUnprocessableEntity) Code() int {
return 422
}
func (o *IssueSearchIssuesUnprocessableEntity) Error() string {
return fmt.Sprintf("[GET /repos/issues/search][%d] issueSearchIssuesUnprocessableEntity", 422)
}
func (o *IssueSearchIssuesUnprocessableEntity) String() string {
return fmt.Sprintf("[GET /repos/issues/search][%d] issueSearchIssuesUnprocessableEntity", 422)
}
func (o *IssueSearchIssuesUnprocessableEntity) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// hydrates response header message
hdrMessage := response.GetHeader("message")
if hdrMessage != "" {
o.Message = hdrMessage
}
// hydrates response header url
hdrURL := response.GetHeader("url")
if hdrURL != "" {
o.URL = hdrURL
}
return nil
}

View File

@@ -0,0 +1,242 @@
// Code generated by go-swagger; DO NOT EDIT.
package repository
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// NewListActionTasksParams creates a new ListActionTasksParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewListActionTasksParams() *ListActionTasksParams {
return &ListActionTasksParams{
timeout: cr.DefaultTimeout,
}
}
// NewListActionTasksParamsWithTimeout creates a new ListActionTasksParams object
// with the ability to set a timeout on a request.
func NewListActionTasksParamsWithTimeout(timeout time.Duration) *ListActionTasksParams {
return &ListActionTasksParams{
timeout: timeout,
}
}
// NewListActionTasksParamsWithContext creates a new ListActionTasksParams object
// with the ability to set a context for a request.
func NewListActionTasksParamsWithContext(ctx context.Context) *ListActionTasksParams {
return &ListActionTasksParams{
Context: ctx,
}
}
// NewListActionTasksParamsWithHTTPClient creates a new ListActionTasksParams object
// with the ability to set a custom HTTPClient for a request.
func NewListActionTasksParamsWithHTTPClient(client *http.Client) *ListActionTasksParams {
return &ListActionTasksParams{
HTTPClient: client,
}
}
/*
ListActionTasksParams contains all the parameters to send to the API endpoint
for the list action tasks operation.
Typically these are written to a http.Request.
*/
type ListActionTasksParams struct {
/* Limit.
page size of results, default maximum page size is 50
*/
Limit *int64
/* Owner.
owner of the repo
*/
Owner string
/* Page.
page number of results to return (1-based)
*/
Page *int64
/* Repo.
name of the repo
*/
Repo string
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the list action tasks params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *ListActionTasksParams) WithDefaults() *ListActionTasksParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the list action tasks params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *ListActionTasksParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the list action tasks params
func (o *ListActionTasksParams) WithTimeout(timeout time.Duration) *ListActionTasksParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the list action tasks params
func (o *ListActionTasksParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the list action tasks params
func (o *ListActionTasksParams) WithContext(ctx context.Context) *ListActionTasksParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the list action tasks params
func (o *ListActionTasksParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the list action tasks params
func (o *ListActionTasksParams) WithHTTPClient(client *http.Client) *ListActionTasksParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the list action tasks params
func (o *ListActionTasksParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithLimit adds the limit to the list action tasks params
func (o *ListActionTasksParams) WithLimit(limit *int64) *ListActionTasksParams {
o.SetLimit(limit)
return o
}
// SetLimit adds the limit to the list action tasks params
func (o *ListActionTasksParams) SetLimit(limit *int64) {
o.Limit = limit
}
// WithOwner adds the owner to the list action tasks params
func (o *ListActionTasksParams) WithOwner(owner string) *ListActionTasksParams {
o.SetOwner(owner)
return o
}
// SetOwner adds the owner to the list action tasks params
func (o *ListActionTasksParams) SetOwner(owner string) {
o.Owner = owner
}
// WithPage adds the page to the list action tasks params
func (o *ListActionTasksParams) WithPage(page *int64) *ListActionTasksParams {
o.SetPage(page)
return o
}
// SetPage adds the page to the list action tasks params
func (o *ListActionTasksParams) SetPage(page *int64) {
o.Page = page
}
// WithRepo adds the repo to the list action tasks params
func (o *ListActionTasksParams) WithRepo(repo string) *ListActionTasksParams {
o.SetRepo(repo)
return o
}
// SetRepo adds the repo to the list action tasks params
func (o *ListActionTasksParams) SetRepo(repo string) {
o.Repo = repo
}
// WriteToRequest writes these params to a swagger request
func (o *ListActionTasksParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
if o.Limit != nil {
// query param limit
var qrLimit int64
if o.Limit != nil {
qrLimit = *o.Limit
}
qLimit := swag.FormatInt64(qrLimit)
if qLimit != "" {
if err := r.SetQueryParam("limit", qLimit); err != nil {
return err
}
}
}
// path param owner
if err := r.SetPathParam("owner", o.Owner); err != nil {
return err
}
if o.Page != nil {
// query param page
var qrPage int64
if o.Page != nil {
qrPage = *o.Page
}
qPage := swag.FormatInt64(qrPage)
if qPage != "" {
if err := r.SetQueryParam("page", qPage); err != nil {
return err
}
}
}
// path param repo
if err := r.SetPathParam("repo", o.Repo); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View File

@@ -0,0 +1,464 @@
// Code generated by go-swagger; DO NOT EDIT.
package repository
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
"src.opensuse.org/autogits/common/gitea-generated/models"
)
// ListActionTasksReader is a Reader for the ListActionTasks structure.
type ListActionTasksReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *ListActionTasksReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewListActionTasksOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
case 400:
result := NewListActionTasksBadRequest()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
case 403:
result := NewListActionTasksForbidden()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
case 404:
result := NewListActionTasksNotFound()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
case 409:
result := NewListActionTasksConflict()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
case 422:
result := NewListActionTasksUnprocessableEntity()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
default:
return nil, runtime.NewAPIError("[GET /repos/{owner}/{repo}/actions/tasks] ListActionTasks", response, response.Code())
}
}
// NewListActionTasksOK creates a ListActionTasksOK with default headers values
func NewListActionTasksOK() *ListActionTasksOK {
return &ListActionTasksOK{}
}
/*
ListActionTasksOK describes a response with status code 200, with default header values.
TasksList
*/
type ListActionTasksOK struct {
Payload *models.ActionTaskResponse
}
// IsSuccess returns true when this list action tasks o k response has a 2xx status code
func (o *ListActionTasksOK) IsSuccess() bool {
return true
}
// IsRedirect returns true when this list action tasks o k response has a 3xx status code
func (o *ListActionTasksOK) IsRedirect() bool {
return false
}
// IsClientError returns true when this list action tasks o k response has a 4xx status code
func (o *ListActionTasksOK) IsClientError() bool {
return false
}
// IsServerError returns true when this list action tasks o k response has a 5xx status code
func (o *ListActionTasksOK) IsServerError() bool {
return false
}
// IsCode returns true when this list action tasks o k response a status code equal to that given
func (o *ListActionTasksOK) IsCode(code int) bool {
return code == 200
}
// Code gets the status code for the list action tasks o k response
func (o *ListActionTasksOK) Code() int {
return 200
}
func (o *ListActionTasksOK) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /repos/{owner}/{repo}/actions/tasks][%d] listActionTasksOK %s", 200, payload)
}
func (o *ListActionTasksOK) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /repos/{owner}/{repo}/actions/tasks][%d] listActionTasksOK %s", 200, payload)
}
func (o *ListActionTasksOK) GetPayload() *models.ActionTaskResponse {
return o.Payload
}
func (o *ListActionTasksOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
o.Payload = new(models.ActionTaskResponse)
// response payload
if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewListActionTasksBadRequest creates a ListActionTasksBadRequest with default headers values
func NewListActionTasksBadRequest() *ListActionTasksBadRequest {
return &ListActionTasksBadRequest{}
}
/*
ListActionTasksBadRequest describes a response with status code 400, with default header values.
APIError is error format response
*/
type ListActionTasksBadRequest struct {
Message string
URL string
}
// IsSuccess returns true when this list action tasks bad request response has a 2xx status code
func (o *ListActionTasksBadRequest) IsSuccess() bool {
return false
}
// IsRedirect returns true when this list action tasks bad request response has a 3xx status code
func (o *ListActionTasksBadRequest) IsRedirect() bool {
return false
}
// IsClientError returns true when this list action tasks bad request response has a 4xx status code
func (o *ListActionTasksBadRequest) IsClientError() bool {
return true
}
// IsServerError returns true when this list action tasks bad request response has a 5xx status code
func (o *ListActionTasksBadRequest) IsServerError() bool {
return false
}
// IsCode returns true when this list action tasks bad request response a status code equal to that given
func (o *ListActionTasksBadRequest) IsCode(code int) bool {
return code == 400
}
// Code gets the status code for the list action tasks bad request response
func (o *ListActionTasksBadRequest) Code() int {
return 400
}
func (o *ListActionTasksBadRequest) Error() string {
return fmt.Sprintf("[GET /repos/{owner}/{repo}/actions/tasks][%d] listActionTasksBadRequest", 400)
}
func (o *ListActionTasksBadRequest) String() string {
return fmt.Sprintf("[GET /repos/{owner}/{repo}/actions/tasks][%d] listActionTasksBadRequest", 400)
}
func (o *ListActionTasksBadRequest) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// hydrates response header message
hdrMessage := response.GetHeader("message")
if hdrMessage != "" {
o.Message = hdrMessage
}
// hydrates response header url
hdrURL := response.GetHeader("url")
if hdrURL != "" {
o.URL = hdrURL
}
return nil
}
// NewListActionTasksForbidden creates a ListActionTasksForbidden with default headers values
func NewListActionTasksForbidden() *ListActionTasksForbidden {
return &ListActionTasksForbidden{}
}
/*
ListActionTasksForbidden describes a response with status code 403, with default header values.
APIForbiddenError is a forbidden error response
*/
type ListActionTasksForbidden struct {
Message string
URL string
}
// IsSuccess returns true when this list action tasks forbidden response has a 2xx status code
func (o *ListActionTasksForbidden) IsSuccess() bool {
return false
}
// IsRedirect returns true when this list action tasks forbidden response has a 3xx status code
func (o *ListActionTasksForbidden) IsRedirect() bool {
return false
}
// IsClientError returns true when this list action tasks forbidden response has a 4xx status code
func (o *ListActionTasksForbidden) IsClientError() bool {
return true
}
// IsServerError returns true when this list action tasks forbidden response has a 5xx status code
func (o *ListActionTasksForbidden) IsServerError() bool {
return false
}
// IsCode returns true when this list action tasks forbidden response a status code equal to that given
func (o *ListActionTasksForbidden) IsCode(code int) bool {
return code == 403
}
// Code gets the status code for the list action tasks forbidden response
func (o *ListActionTasksForbidden) Code() int {
return 403
}
func (o *ListActionTasksForbidden) Error() string {
return fmt.Sprintf("[GET /repos/{owner}/{repo}/actions/tasks][%d] listActionTasksForbidden", 403)
}
func (o *ListActionTasksForbidden) String() string {
return fmt.Sprintf("[GET /repos/{owner}/{repo}/actions/tasks][%d] listActionTasksForbidden", 403)
}
func (o *ListActionTasksForbidden) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// hydrates response header message
hdrMessage := response.GetHeader("message")
if hdrMessage != "" {
o.Message = hdrMessage
}
// hydrates response header url
hdrURL := response.GetHeader("url")
if hdrURL != "" {
o.URL = hdrURL
}
return nil
}
// NewListActionTasksNotFound creates a ListActionTasksNotFound with default headers values
func NewListActionTasksNotFound() *ListActionTasksNotFound {
return &ListActionTasksNotFound{}
}
/*
ListActionTasksNotFound describes a response with status code 404, with default header values.
APINotFound is a not found empty response
*/
type ListActionTasksNotFound struct {
}
// IsSuccess returns true when this list action tasks not found response has a 2xx status code
func (o *ListActionTasksNotFound) IsSuccess() bool {
return false
}
// IsRedirect returns true when this list action tasks not found response has a 3xx status code
func (o *ListActionTasksNotFound) IsRedirect() bool {
return false
}
// IsClientError returns true when this list action tasks not found response has a 4xx status code
func (o *ListActionTasksNotFound) IsClientError() bool {
return true
}
// IsServerError returns true when this list action tasks not found response has a 5xx status code
func (o *ListActionTasksNotFound) IsServerError() bool {
return false
}
// IsCode returns true when this list action tasks not found response a status code equal to that given
func (o *ListActionTasksNotFound) IsCode(code int) bool {
return code == 404
}
// Code gets the status code for the list action tasks not found response
func (o *ListActionTasksNotFound) Code() int {
return 404
}
func (o *ListActionTasksNotFound) Error() string {
return fmt.Sprintf("[GET /repos/{owner}/{repo}/actions/tasks][%d] listActionTasksNotFound", 404)
}
func (o *ListActionTasksNotFound) String() string {
return fmt.Sprintf("[GET /repos/{owner}/{repo}/actions/tasks][%d] listActionTasksNotFound", 404)
}
func (o *ListActionTasksNotFound) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
return nil
}
// NewListActionTasksConflict creates a ListActionTasksConflict with default headers values
func NewListActionTasksConflict() *ListActionTasksConflict {
return &ListActionTasksConflict{}
}
/*
ListActionTasksConflict describes a response with status code 409, with default header values.
APIConflict is a conflict empty response
*/
type ListActionTasksConflict struct {
}
// IsSuccess returns true when this list action tasks conflict response has a 2xx status code
func (o *ListActionTasksConflict) IsSuccess() bool {
return false
}
// IsRedirect returns true when this list action tasks conflict response has a 3xx status code
func (o *ListActionTasksConflict) IsRedirect() bool {
return false
}
// IsClientError returns true when this list action tasks conflict response has a 4xx status code
func (o *ListActionTasksConflict) IsClientError() bool {
return true
}
// IsServerError returns true when this list action tasks conflict response has a 5xx status code
func (o *ListActionTasksConflict) IsServerError() bool {
return false
}
// IsCode returns true when this list action tasks conflict response a status code equal to that given
func (o *ListActionTasksConflict) IsCode(code int) bool {
return code == 409
}
// Code gets the status code for the list action tasks conflict response
func (o *ListActionTasksConflict) Code() int {
return 409
}
func (o *ListActionTasksConflict) Error() string {
return fmt.Sprintf("[GET /repos/{owner}/{repo}/actions/tasks][%d] listActionTasksConflict", 409)
}
func (o *ListActionTasksConflict) String() string {
return fmt.Sprintf("[GET /repos/{owner}/{repo}/actions/tasks][%d] listActionTasksConflict", 409)
}
func (o *ListActionTasksConflict) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
return nil
}
// NewListActionTasksUnprocessableEntity creates a ListActionTasksUnprocessableEntity with default headers values
func NewListActionTasksUnprocessableEntity() *ListActionTasksUnprocessableEntity {
return &ListActionTasksUnprocessableEntity{}
}
/*
ListActionTasksUnprocessableEntity describes a response with status code 422, with default header values.
APIValidationError is error format response related to input validation
*/
type ListActionTasksUnprocessableEntity struct {
Message string
URL string
}
// IsSuccess returns true when this list action tasks unprocessable entity response has a 2xx status code
func (o *ListActionTasksUnprocessableEntity) IsSuccess() bool {
return false
}
// IsRedirect returns true when this list action tasks unprocessable entity response has a 3xx status code
func (o *ListActionTasksUnprocessableEntity) IsRedirect() bool {
return false
}
// IsClientError returns true when this list action tasks unprocessable entity response has a 4xx status code
func (o *ListActionTasksUnprocessableEntity) IsClientError() bool {
return true
}
// IsServerError returns true when this list action tasks unprocessable entity response has a 5xx status code
func (o *ListActionTasksUnprocessableEntity) IsServerError() bool {
return false
}
// IsCode returns true when this list action tasks unprocessable entity response a status code equal to that given
func (o *ListActionTasksUnprocessableEntity) IsCode(code int) bool {
return code == 422
}
// Code gets the status code for the list action tasks unprocessable entity response
func (o *ListActionTasksUnprocessableEntity) Code() int {
return 422
}
func (o *ListActionTasksUnprocessableEntity) Error() string {
return fmt.Sprintf("[GET /repos/{owner}/{repo}/actions/tasks][%d] listActionTasksUnprocessableEntity", 422)
}
func (o *ListActionTasksUnprocessableEntity) String() string {
return fmt.Sprintf("[GET /repos/{owner}/{repo}/actions/tasks][%d] listActionTasksUnprocessableEntity", 422)
}
func (o *ListActionTasksUnprocessableEntity) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// hydrates response header message
hdrMessage := response.GetHeader("message")
if hdrMessage != "" {
o.Message = hdrMessage
}
// hydrates response header url
hdrURL := response.GetHeader("url")
if hdrURL != "" {
o.URL = hdrURL
}
return nil
}

View File

@@ -0,0 +1,194 @@
// Code generated by go-swagger; DO NOT EDIT.
package repository
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
"src.opensuse.org/autogits/common/gitea-generated/models"
)
// NewRepoCreateTagProtectionParams creates a new RepoCreateTagProtectionParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewRepoCreateTagProtectionParams() *RepoCreateTagProtectionParams {
return &RepoCreateTagProtectionParams{
timeout: cr.DefaultTimeout,
}
}
// NewRepoCreateTagProtectionParamsWithTimeout creates a new RepoCreateTagProtectionParams object
// with the ability to set a timeout on a request.
func NewRepoCreateTagProtectionParamsWithTimeout(timeout time.Duration) *RepoCreateTagProtectionParams {
return &RepoCreateTagProtectionParams{
timeout: timeout,
}
}
// NewRepoCreateTagProtectionParamsWithContext creates a new RepoCreateTagProtectionParams object
// with the ability to set a context for a request.
func NewRepoCreateTagProtectionParamsWithContext(ctx context.Context) *RepoCreateTagProtectionParams {
return &RepoCreateTagProtectionParams{
Context: ctx,
}
}
// NewRepoCreateTagProtectionParamsWithHTTPClient creates a new RepoCreateTagProtectionParams object
// with the ability to set a custom HTTPClient for a request.
func NewRepoCreateTagProtectionParamsWithHTTPClient(client *http.Client) *RepoCreateTagProtectionParams {
return &RepoCreateTagProtectionParams{
HTTPClient: client,
}
}
/*
RepoCreateTagProtectionParams contains all the parameters to send to the API endpoint
for the repo create tag protection operation.
Typically these are written to a http.Request.
*/
type RepoCreateTagProtectionParams struct {
// Body.
Body *models.CreateTagProtectionOption
/* Owner.
owner of the repo
*/
Owner string
/* Repo.
name of the repo
*/
Repo string
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the repo create tag protection params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *RepoCreateTagProtectionParams) WithDefaults() *RepoCreateTagProtectionParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the repo create tag protection params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *RepoCreateTagProtectionParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the repo create tag protection params
func (o *RepoCreateTagProtectionParams) WithTimeout(timeout time.Duration) *RepoCreateTagProtectionParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the repo create tag protection params
func (o *RepoCreateTagProtectionParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the repo create tag protection params
func (o *RepoCreateTagProtectionParams) WithContext(ctx context.Context) *RepoCreateTagProtectionParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the repo create tag protection params
func (o *RepoCreateTagProtectionParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the repo create tag protection params
func (o *RepoCreateTagProtectionParams) WithHTTPClient(client *http.Client) *RepoCreateTagProtectionParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the repo create tag protection params
func (o *RepoCreateTagProtectionParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithBody adds the body to the repo create tag protection params
func (o *RepoCreateTagProtectionParams) WithBody(body *models.CreateTagProtectionOption) *RepoCreateTagProtectionParams {
o.SetBody(body)
return o
}
// SetBody adds the body to the repo create tag protection params
func (o *RepoCreateTagProtectionParams) SetBody(body *models.CreateTagProtectionOption) {
o.Body = body
}
// WithOwner adds the owner to the repo create tag protection params
func (o *RepoCreateTagProtectionParams) WithOwner(owner string) *RepoCreateTagProtectionParams {
o.SetOwner(owner)
return o
}
// SetOwner adds the owner to the repo create tag protection params
func (o *RepoCreateTagProtectionParams) SetOwner(owner string) {
o.Owner = owner
}
// WithRepo adds the repo to the repo create tag protection params
func (o *RepoCreateTagProtectionParams) WithRepo(repo string) *RepoCreateTagProtectionParams {
o.SetRepo(repo)
return o
}
// SetRepo adds the repo to the repo create tag protection params
func (o *RepoCreateTagProtectionParams) SetRepo(repo string) {
o.Repo = repo
}
// WriteToRequest writes these params to a swagger request
func (o *RepoCreateTagProtectionParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
if o.Body != nil {
if err := r.SetBodyParam(o.Body); err != nil {
return err
}
}
// path param owner
if err := r.SetPathParam("owner", o.Owner); err != nil {
return err
}
// path param repo
if err := r.SetPathParam("repo", o.Repo); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View File

@@ -0,0 +1,402 @@
// Code generated by go-swagger; DO NOT EDIT.
package repository
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
"src.opensuse.org/autogits/common/gitea-generated/models"
)
// RepoCreateTagProtectionReader is a Reader for the RepoCreateTagProtection structure.
type RepoCreateTagProtectionReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *RepoCreateTagProtectionReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 201:
result := NewRepoCreateTagProtectionCreated()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
case 403:
result := NewRepoCreateTagProtectionForbidden()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
case 404:
result := NewRepoCreateTagProtectionNotFound()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
case 422:
result := NewRepoCreateTagProtectionUnprocessableEntity()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
case 423:
result := NewRepoCreateTagProtectionLocked()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
default:
return nil, runtime.NewAPIError("[POST /repos/{owner}/{repo}/tag_protections] repoCreateTagProtection", response, response.Code())
}
}
// NewRepoCreateTagProtectionCreated creates a RepoCreateTagProtectionCreated with default headers values
func NewRepoCreateTagProtectionCreated() *RepoCreateTagProtectionCreated {
return &RepoCreateTagProtectionCreated{}
}
/*
RepoCreateTagProtectionCreated describes a response with status code 201, with default header values.
TagProtection
*/
type RepoCreateTagProtectionCreated struct {
Payload *models.TagProtection
}
// IsSuccess returns true when this repo create tag protection created response has a 2xx status code
func (o *RepoCreateTagProtectionCreated) IsSuccess() bool {
return true
}
// IsRedirect returns true when this repo create tag protection created response has a 3xx status code
func (o *RepoCreateTagProtectionCreated) IsRedirect() bool {
return false
}
// IsClientError returns true when this repo create tag protection created response has a 4xx status code
func (o *RepoCreateTagProtectionCreated) IsClientError() bool {
return false
}
// IsServerError returns true when this repo create tag protection created response has a 5xx status code
func (o *RepoCreateTagProtectionCreated) IsServerError() bool {
return false
}
// IsCode returns true when this repo create tag protection created response a status code equal to that given
func (o *RepoCreateTagProtectionCreated) IsCode(code int) bool {
return code == 201
}
// Code gets the status code for the repo create tag protection created response
func (o *RepoCreateTagProtectionCreated) Code() int {
return 201
}
func (o *RepoCreateTagProtectionCreated) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[POST /repos/{owner}/{repo}/tag_protections][%d] repoCreateTagProtectionCreated %s", 201, payload)
}
func (o *RepoCreateTagProtectionCreated) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[POST /repos/{owner}/{repo}/tag_protections][%d] repoCreateTagProtectionCreated %s", 201, payload)
}
func (o *RepoCreateTagProtectionCreated) GetPayload() *models.TagProtection {
return o.Payload
}
func (o *RepoCreateTagProtectionCreated) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
o.Payload = new(models.TagProtection)
// response payload
if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewRepoCreateTagProtectionForbidden creates a RepoCreateTagProtectionForbidden with default headers values
func NewRepoCreateTagProtectionForbidden() *RepoCreateTagProtectionForbidden {
return &RepoCreateTagProtectionForbidden{}
}
/*
RepoCreateTagProtectionForbidden describes a response with status code 403, with default header values.
APIForbiddenError is a forbidden error response
*/
type RepoCreateTagProtectionForbidden struct {
Message string
URL string
}
// IsSuccess returns true when this repo create tag protection forbidden response has a 2xx status code
func (o *RepoCreateTagProtectionForbidden) IsSuccess() bool {
return false
}
// IsRedirect returns true when this repo create tag protection forbidden response has a 3xx status code
func (o *RepoCreateTagProtectionForbidden) IsRedirect() bool {
return false
}
// IsClientError returns true when this repo create tag protection forbidden response has a 4xx status code
func (o *RepoCreateTagProtectionForbidden) IsClientError() bool {
return true
}
// IsServerError returns true when this repo create tag protection forbidden response has a 5xx status code
func (o *RepoCreateTagProtectionForbidden) IsServerError() bool {
return false
}
// IsCode returns true when this repo create tag protection forbidden response a status code equal to that given
func (o *RepoCreateTagProtectionForbidden) IsCode(code int) bool {
return code == 403
}
// Code gets the status code for the repo create tag protection forbidden response
func (o *RepoCreateTagProtectionForbidden) Code() int {
return 403
}
func (o *RepoCreateTagProtectionForbidden) Error() string {
return fmt.Sprintf("[POST /repos/{owner}/{repo}/tag_protections][%d] repoCreateTagProtectionForbidden", 403)
}
func (o *RepoCreateTagProtectionForbidden) String() string {
return fmt.Sprintf("[POST /repos/{owner}/{repo}/tag_protections][%d] repoCreateTagProtectionForbidden", 403)
}
func (o *RepoCreateTagProtectionForbidden) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// hydrates response header message
hdrMessage := response.GetHeader("message")
if hdrMessage != "" {
o.Message = hdrMessage
}
// hydrates response header url
hdrURL := response.GetHeader("url")
if hdrURL != "" {
o.URL = hdrURL
}
return nil
}
// NewRepoCreateTagProtectionNotFound creates a RepoCreateTagProtectionNotFound with default headers values
func NewRepoCreateTagProtectionNotFound() *RepoCreateTagProtectionNotFound {
return &RepoCreateTagProtectionNotFound{}
}
/*
RepoCreateTagProtectionNotFound describes a response with status code 404, with default header values.
APINotFound is a not found empty response
*/
type RepoCreateTagProtectionNotFound struct {
}
// IsSuccess returns true when this repo create tag protection not found response has a 2xx status code
func (o *RepoCreateTagProtectionNotFound) IsSuccess() bool {
return false
}
// IsRedirect returns true when this repo create tag protection not found response has a 3xx status code
func (o *RepoCreateTagProtectionNotFound) IsRedirect() bool {
return false
}
// IsClientError returns true when this repo create tag protection not found response has a 4xx status code
func (o *RepoCreateTagProtectionNotFound) IsClientError() bool {
return true
}
// IsServerError returns true when this repo create tag protection not found response has a 5xx status code
func (o *RepoCreateTagProtectionNotFound) IsServerError() bool {
return false
}
// IsCode returns true when this repo create tag protection not found response a status code equal to that given
func (o *RepoCreateTagProtectionNotFound) IsCode(code int) bool {
return code == 404
}
// Code gets the status code for the repo create tag protection not found response
func (o *RepoCreateTagProtectionNotFound) Code() int {
return 404
}
func (o *RepoCreateTagProtectionNotFound) Error() string {
return fmt.Sprintf("[POST /repos/{owner}/{repo}/tag_protections][%d] repoCreateTagProtectionNotFound", 404)
}
func (o *RepoCreateTagProtectionNotFound) String() string {
return fmt.Sprintf("[POST /repos/{owner}/{repo}/tag_protections][%d] repoCreateTagProtectionNotFound", 404)
}
func (o *RepoCreateTagProtectionNotFound) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
return nil
}
// NewRepoCreateTagProtectionUnprocessableEntity creates a RepoCreateTagProtectionUnprocessableEntity with default headers values
func NewRepoCreateTagProtectionUnprocessableEntity() *RepoCreateTagProtectionUnprocessableEntity {
return &RepoCreateTagProtectionUnprocessableEntity{}
}
/*
RepoCreateTagProtectionUnprocessableEntity describes a response with status code 422, with default header values.
APIValidationError is error format response related to input validation
*/
type RepoCreateTagProtectionUnprocessableEntity struct {
Message string
URL string
}
// IsSuccess returns true when this repo create tag protection unprocessable entity response has a 2xx status code
func (o *RepoCreateTagProtectionUnprocessableEntity) IsSuccess() bool {
return false
}
// IsRedirect returns true when this repo create tag protection unprocessable entity response has a 3xx status code
func (o *RepoCreateTagProtectionUnprocessableEntity) IsRedirect() bool {
return false
}
// IsClientError returns true when this repo create tag protection unprocessable entity response has a 4xx status code
func (o *RepoCreateTagProtectionUnprocessableEntity) IsClientError() bool {
return true
}
// IsServerError returns true when this repo create tag protection unprocessable entity response has a 5xx status code
func (o *RepoCreateTagProtectionUnprocessableEntity) IsServerError() bool {
return false
}
// IsCode returns true when this repo create tag protection unprocessable entity response a status code equal to that given
func (o *RepoCreateTagProtectionUnprocessableEntity) IsCode(code int) bool {
return code == 422
}
// Code gets the status code for the repo create tag protection unprocessable entity response
func (o *RepoCreateTagProtectionUnprocessableEntity) Code() int {
return 422
}
func (o *RepoCreateTagProtectionUnprocessableEntity) Error() string {
return fmt.Sprintf("[POST /repos/{owner}/{repo}/tag_protections][%d] repoCreateTagProtectionUnprocessableEntity", 422)
}
func (o *RepoCreateTagProtectionUnprocessableEntity) String() string {
return fmt.Sprintf("[POST /repos/{owner}/{repo}/tag_protections][%d] repoCreateTagProtectionUnprocessableEntity", 422)
}
func (o *RepoCreateTagProtectionUnprocessableEntity) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// hydrates response header message
hdrMessage := response.GetHeader("message")
if hdrMessage != "" {
o.Message = hdrMessage
}
// hydrates response header url
hdrURL := response.GetHeader("url")
if hdrURL != "" {
o.URL = hdrURL
}
return nil
}
// NewRepoCreateTagProtectionLocked creates a RepoCreateTagProtectionLocked with default headers values
func NewRepoCreateTagProtectionLocked() *RepoCreateTagProtectionLocked {
return &RepoCreateTagProtectionLocked{}
}
/*
RepoCreateTagProtectionLocked describes a response with status code 423, with default header values.
APIRepoArchivedError is an error that is raised when an archived repo should be modified
*/
type RepoCreateTagProtectionLocked struct {
Message string
URL string
}
// IsSuccess returns true when this repo create tag protection locked response has a 2xx status code
func (o *RepoCreateTagProtectionLocked) IsSuccess() bool {
return false
}
// IsRedirect returns true when this repo create tag protection locked response has a 3xx status code
func (o *RepoCreateTagProtectionLocked) IsRedirect() bool {
return false
}
// IsClientError returns true when this repo create tag protection locked response has a 4xx status code
func (o *RepoCreateTagProtectionLocked) IsClientError() bool {
return true
}
// IsServerError returns true when this repo create tag protection locked response has a 5xx status code
func (o *RepoCreateTagProtectionLocked) IsServerError() bool {
return false
}
// IsCode returns true when this repo create tag protection locked response a status code equal to that given
func (o *RepoCreateTagProtectionLocked) IsCode(code int) bool {
return code == 423
}
// Code gets the status code for the repo create tag protection locked response
func (o *RepoCreateTagProtectionLocked) Code() int {
return 423
}
func (o *RepoCreateTagProtectionLocked) Error() string {
return fmt.Sprintf("[POST /repos/{owner}/{repo}/tag_protections][%d] repoCreateTagProtectionLocked", 423)
}
func (o *RepoCreateTagProtectionLocked) String() string {
return fmt.Sprintf("[POST /repos/{owner}/{repo}/tag_protections][%d] repoCreateTagProtectionLocked", 423)
}
func (o *RepoCreateTagProtectionLocked) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// hydrates response header message
hdrMessage := response.GetHeader("message")
if hdrMessage != "" {
o.Message = hdrMessage
}
// hydrates response header url
hdrURL := response.GetHeader("url")
if hdrURL != "" {
o.URL = hdrURL
}
return nil
}

View File

@@ -0,0 +1,196 @@
// Code generated by go-swagger; DO NOT EDIT.
package repository
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// NewRepoDeleteTagProtectionParams creates a new RepoDeleteTagProtectionParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewRepoDeleteTagProtectionParams() *RepoDeleteTagProtectionParams {
return &RepoDeleteTagProtectionParams{
timeout: cr.DefaultTimeout,
}
}
// NewRepoDeleteTagProtectionParamsWithTimeout creates a new RepoDeleteTagProtectionParams object
// with the ability to set a timeout on a request.
func NewRepoDeleteTagProtectionParamsWithTimeout(timeout time.Duration) *RepoDeleteTagProtectionParams {
return &RepoDeleteTagProtectionParams{
timeout: timeout,
}
}
// NewRepoDeleteTagProtectionParamsWithContext creates a new RepoDeleteTagProtectionParams object
// with the ability to set a context for a request.
func NewRepoDeleteTagProtectionParamsWithContext(ctx context.Context) *RepoDeleteTagProtectionParams {
return &RepoDeleteTagProtectionParams{
Context: ctx,
}
}
// NewRepoDeleteTagProtectionParamsWithHTTPClient creates a new RepoDeleteTagProtectionParams object
// with the ability to set a custom HTTPClient for a request.
func NewRepoDeleteTagProtectionParamsWithHTTPClient(client *http.Client) *RepoDeleteTagProtectionParams {
return &RepoDeleteTagProtectionParams{
HTTPClient: client,
}
}
/*
RepoDeleteTagProtectionParams contains all the parameters to send to the API endpoint
for the repo delete tag protection operation.
Typically these are written to a http.Request.
*/
type RepoDeleteTagProtectionParams struct {
/* ID.
id of protected tag
*/
ID int64
/* Owner.
owner of the repo
*/
Owner string
/* Repo.
name of the repo
*/
Repo string
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the repo delete tag protection params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *RepoDeleteTagProtectionParams) WithDefaults() *RepoDeleteTagProtectionParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the repo delete tag protection params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *RepoDeleteTagProtectionParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the repo delete tag protection params
func (o *RepoDeleteTagProtectionParams) WithTimeout(timeout time.Duration) *RepoDeleteTagProtectionParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the repo delete tag protection params
func (o *RepoDeleteTagProtectionParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the repo delete tag protection params
func (o *RepoDeleteTagProtectionParams) WithContext(ctx context.Context) *RepoDeleteTagProtectionParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the repo delete tag protection params
func (o *RepoDeleteTagProtectionParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the repo delete tag protection params
func (o *RepoDeleteTagProtectionParams) WithHTTPClient(client *http.Client) *RepoDeleteTagProtectionParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the repo delete tag protection params
func (o *RepoDeleteTagProtectionParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithID adds the id to the repo delete tag protection params
func (o *RepoDeleteTagProtectionParams) WithID(id int64) *RepoDeleteTagProtectionParams {
o.SetID(id)
return o
}
// SetID adds the id to the repo delete tag protection params
func (o *RepoDeleteTagProtectionParams) SetID(id int64) {
o.ID = id
}
// WithOwner adds the owner to the repo delete tag protection params
func (o *RepoDeleteTagProtectionParams) WithOwner(owner string) *RepoDeleteTagProtectionParams {
o.SetOwner(owner)
return o
}
// SetOwner adds the owner to the repo delete tag protection params
func (o *RepoDeleteTagProtectionParams) SetOwner(owner string) {
o.Owner = owner
}
// WithRepo adds the repo to the repo delete tag protection params
func (o *RepoDeleteTagProtectionParams) WithRepo(repo string) *RepoDeleteTagProtectionParams {
o.SetRepo(repo)
return o
}
// SetRepo adds the repo to the repo delete tag protection params
func (o *RepoDeleteTagProtectionParams) SetRepo(repo string) {
o.Repo = repo
}
// WriteToRequest writes these params to a swagger request
func (o *RepoDeleteTagProtectionParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
// path param id
if err := r.SetPathParam("id", swag.FormatInt64(o.ID)); err != nil {
return err
}
// path param owner
if err := r.SetPathParam("owner", o.Owner); err != nil {
return err
}
// path param repo
if err := r.SetPathParam("repo", o.Repo); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View File

@@ -0,0 +1,150 @@
// Code generated by go-swagger; DO NOT EDIT.
package repository
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"fmt"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
)
// RepoDeleteTagProtectionReader is a Reader for the RepoDeleteTagProtection structure.
type RepoDeleteTagProtectionReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *RepoDeleteTagProtectionReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 204:
result := NewRepoDeleteTagProtectionNoContent()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
case 404:
result := NewRepoDeleteTagProtectionNotFound()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
default:
return nil, runtime.NewAPIError("[DELETE /repos/{owner}/{repo}/tag_protections/{id}] repoDeleteTagProtection", response, response.Code())
}
}
// NewRepoDeleteTagProtectionNoContent creates a RepoDeleteTagProtectionNoContent with default headers values
func NewRepoDeleteTagProtectionNoContent() *RepoDeleteTagProtectionNoContent {
return &RepoDeleteTagProtectionNoContent{}
}
/*
RepoDeleteTagProtectionNoContent describes a response with status code 204, with default header values.
APIEmpty is an empty response
*/
type RepoDeleteTagProtectionNoContent struct {
}
// IsSuccess returns true when this repo delete tag protection no content response has a 2xx status code
func (o *RepoDeleteTagProtectionNoContent) IsSuccess() bool {
return true
}
// IsRedirect returns true when this repo delete tag protection no content response has a 3xx status code
func (o *RepoDeleteTagProtectionNoContent) IsRedirect() bool {
return false
}
// IsClientError returns true when this repo delete tag protection no content response has a 4xx status code
func (o *RepoDeleteTagProtectionNoContent) IsClientError() bool {
return false
}
// IsServerError returns true when this repo delete tag protection no content response has a 5xx status code
func (o *RepoDeleteTagProtectionNoContent) IsServerError() bool {
return false
}
// IsCode returns true when this repo delete tag protection no content response a status code equal to that given
func (o *RepoDeleteTagProtectionNoContent) IsCode(code int) bool {
return code == 204
}
// Code gets the status code for the repo delete tag protection no content response
func (o *RepoDeleteTagProtectionNoContent) Code() int {
return 204
}
func (o *RepoDeleteTagProtectionNoContent) Error() string {
return fmt.Sprintf("[DELETE /repos/{owner}/{repo}/tag_protections/{id}][%d] repoDeleteTagProtectionNoContent", 204)
}
func (o *RepoDeleteTagProtectionNoContent) String() string {
return fmt.Sprintf("[DELETE /repos/{owner}/{repo}/tag_protections/{id}][%d] repoDeleteTagProtectionNoContent", 204)
}
func (o *RepoDeleteTagProtectionNoContent) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
return nil
}
// NewRepoDeleteTagProtectionNotFound creates a RepoDeleteTagProtectionNotFound with default headers values
func NewRepoDeleteTagProtectionNotFound() *RepoDeleteTagProtectionNotFound {
return &RepoDeleteTagProtectionNotFound{}
}
/*
RepoDeleteTagProtectionNotFound describes a response with status code 404, with default header values.
APINotFound is a not found empty response
*/
type RepoDeleteTagProtectionNotFound struct {
}
// IsSuccess returns true when this repo delete tag protection not found response has a 2xx status code
func (o *RepoDeleteTagProtectionNotFound) IsSuccess() bool {
return false
}
// IsRedirect returns true when this repo delete tag protection not found response has a 3xx status code
func (o *RepoDeleteTagProtectionNotFound) IsRedirect() bool {
return false
}
// IsClientError returns true when this repo delete tag protection not found response has a 4xx status code
func (o *RepoDeleteTagProtectionNotFound) IsClientError() bool {
return true
}
// IsServerError returns true when this repo delete tag protection not found response has a 5xx status code
func (o *RepoDeleteTagProtectionNotFound) IsServerError() bool {
return false
}
// IsCode returns true when this repo delete tag protection not found response a status code equal to that given
func (o *RepoDeleteTagProtectionNotFound) IsCode(code int) bool {
return code == 404
}
// Code gets the status code for the repo delete tag protection not found response
func (o *RepoDeleteTagProtectionNotFound) Code() int {
return 404
}
func (o *RepoDeleteTagProtectionNotFound) Error() string {
return fmt.Sprintf("[DELETE /repos/{owner}/{repo}/tag_protections/{id}][%d] repoDeleteTagProtectionNotFound", 404)
}
func (o *RepoDeleteTagProtectionNotFound) String() string {
return fmt.Sprintf("[DELETE /repos/{owner}/{repo}/tag_protections/{id}][%d] repoDeleteTagProtectionNotFound", 404)
}
func (o *RepoDeleteTagProtectionNotFound) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
return nil
}

View File

@@ -36,6 +36,12 @@ func (o *RepoEditReleaseAttachmentReader) ReadResponse(response runtime.ClientRe
return nil, err
}
return nil, result
case 422:
result := NewRepoEditReleaseAttachmentUnprocessableEntity()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
default:
return nil, runtime.NewAPIError("[PATCH /repos/{owner}/{repo}/releases/{id}/assets/{attachment_id}] repoEditReleaseAttachment", response, response.Code())
}
@@ -166,3 +172,75 @@ func (o *RepoEditReleaseAttachmentNotFound) readResponse(response runtime.Client
return nil
}
// NewRepoEditReleaseAttachmentUnprocessableEntity creates a RepoEditReleaseAttachmentUnprocessableEntity with default headers values
func NewRepoEditReleaseAttachmentUnprocessableEntity() *RepoEditReleaseAttachmentUnprocessableEntity {
return &RepoEditReleaseAttachmentUnprocessableEntity{}
}
/*
RepoEditReleaseAttachmentUnprocessableEntity describes a response with status code 422, with default header values.
APIValidationError is error format response related to input validation
*/
type RepoEditReleaseAttachmentUnprocessableEntity struct {
Message string
URL string
}
// IsSuccess returns true when this repo edit release attachment unprocessable entity response has a 2xx status code
func (o *RepoEditReleaseAttachmentUnprocessableEntity) IsSuccess() bool {
return false
}
// IsRedirect returns true when this repo edit release attachment unprocessable entity response has a 3xx status code
func (o *RepoEditReleaseAttachmentUnprocessableEntity) IsRedirect() bool {
return false
}
// IsClientError returns true when this repo edit release attachment unprocessable entity response has a 4xx status code
func (o *RepoEditReleaseAttachmentUnprocessableEntity) IsClientError() bool {
return true
}
// IsServerError returns true when this repo edit release attachment unprocessable entity response has a 5xx status code
func (o *RepoEditReleaseAttachmentUnprocessableEntity) IsServerError() bool {
return false
}
// IsCode returns true when this repo edit release attachment unprocessable entity response a status code equal to that given
func (o *RepoEditReleaseAttachmentUnprocessableEntity) IsCode(code int) bool {
return code == 422
}
// Code gets the status code for the repo edit release attachment unprocessable entity response
func (o *RepoEditReleaseAttachmentUnprocessableEntity) Code() int {
return 422
}
func (o *RepoEditReleaseAttachmentUnprocessableEntity) Error() string {
return fmt.Sprintf("[PATCH /repos/{owner}/{repo}/releases/{id}/assets/{attachment_id}][%d] repoEditReleaseAttachmentUnprocessableEntity", 422)
}
func (o *RepoEditReleaseAttachmentUnprocessableEntity) String() string {
return fmt.Sprintf("[PATCH /repos/{owner}/{repo}/releases/{id}/assets/{attachment_id}][%d] repoEditReleaseAttachmentUnprocessableEntity", 422)
}
func (o *RepoEditReleaseAttachmentUnprocessableEntity) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// hydrates response header message
hdrMessage := response.GetHeader("message")
if hdrMessage != "" {
o.Message = hdrMessage
}
// hydrates response header url
hdrURL := response.GetHeader("url")
if hdrURL != "" {
o.URL = hdrURL
}
return nil
}

View File

@@ -0,0 +1,217 @@
// Code generated by go-swagger; DO NOT EDIT.
package repository
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"src.opensuse.org/autogits/common/gitea-generated/models"
)
// NewRepoEditTagProtectionParams creates a new RepoEditTagProtectionParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewRepoEditTagProtectionParams() *RepoEditTagProtectionParams {
return &RepoEditTagProtectionParams{
timeout: cr.DefaultTimeout,
}
}
// NewRepoEditTagProtectionParamsWithTimeout creates a new RepoEditTagProtectionParams object
// with the ability to set a timeout on a request.
func NewRepoEditTagProtectionParamsWithTimeout(timeout time.Duration) *RepoEditTagProtectionParams {
return &RepoEditTagProtectionParams{
timeout: timeout,
}
}
// NewRepoEditTagProtectionParamsWithContext creates a new RepoEditTagProtectionParams object
// with the ability to set a context for a request.
func NewRepoEditTagProtectionParamsWithContext(ctx context.Context) *RepoEditTagProtectionParams {
return &RepoEditTagProtectionParams{
Context: ctx,
}
}
// NewRepoEditTagProtectionParamsWithHTTPClient creates a new RepoEditTagProtectionParams object
// with the ability to set a custom HTTPClient for a request.
func NewRepoEditTagProtectionParamsWithHTTPClient(client *http.Client) *RepoEditTagProtectionParams {
return &RepoEditTagProtectionParams{
HTTPClient: client,
}
}
/*
RepoEditTagProtectionParams contains all the parameters to send to the API endpoint
for the repo edit tag protection operation.
Typically these are written to a http.Request.
*/
type RepoEditTagProtectionParams struct {
// Body.
Body *models.EditTagProtectionOption
/* ID.
id of protected tag
*/
ID int64
/* Owner.
owner of the repo
*/
Owner string
/* Repo.
name of the repo
*/
Repo string
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the repo edit tag protection params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *RepoEditTagProtectionParams) WithDefaults() *RepoEditTagProtectionParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the repo edit tag protection params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *RepoEditTagProtectionParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the repo edit tag protection params
func (o *RepoEditTagProtectionParams) WithTimeout(timeout time.Duration) *RepoEditTagProtectionParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the repo edit tag protection params
func (o *RepoEditTagProtectionParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the repo edit tag protection params
func (o *RepoEditTagProtectionParams) WithContext(ctx context.Context) *RepoEditTagProtectionParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the repo edit tag protection params
func (o *RepoEditTagProtectionParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the repo edit tag protection params
func (o *RepoEditTagProtectionParams) WithHTTPClient(client *http.Client) *RepoEditTagProtectionParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the repo edit tag protection params
func (o *RepoEditTagProtectionParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithBody adds the body to the repo edit tag protection params
func (o *RepoEditTagProtectionParams) WithBody(body *models.EditTagProtectionOption) *RepoEditTagProtectionParams {
o.SetBody(body)
return o
}
// SetBody adds the body to the repo edit tag protection params
func (o *RepoEditTagProtectionParams) SetBody(body *models.EditTagProtectionOption) {
o.Body = body
}
// WithID adds the id to the repo edit tag protection params
func (o *RepoEditTagProtectionParams) WithID(id int64) *RepoEditTagProtectionParams {
o.SetID(id)
return o
}
// SetID adds the id to the repo edit tag protection params
func (o *RepoEditTagProtectionParams) SetID(id int64) {
o.ID = id
}
// WithOwner adds the owner to the repo edit tag protection params
func (o *RepoEditTagProtectionParams) WithOwner(owner string) *RepoEditTagProtectionParams {
o.SetOwner(owner)
return o
}
// SetOwner adds the owner to the repo edit tag protection params
func (o *RepoEditTagProtectionParams) SetOwner(owner string) {
o.Owner = owner
}
// WithRepo adds the repo to the repo edit tag protection params
func (o *RepoEditTagProtectionParams) WithRepo(repo string) *RepoEditTagProtectionParams {
o.SetRepo(repo)
return o
}
// SetRepo adds the repo to the repo edit tag protection params
func (o *RepoEditTagProtectionParams) SetRepo(repo string) {
o.Repo = repo
}
// WriteToRequest writes these params to a swagger request
func (o *RepoEditTagProtectionParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
if o.Body != nil {
if err := r.SetBodyParam(o.Body); err != nil {
return err
}
}
// path param id
if err := r.SetPathParam("id", swag.FormatInt64(o.ID)); err != nil {
return err
}
// path param owner
if err := r.SetPathParam("owner", o.Owner); err != nil {
return err
}
// path param repo
if err := r.SetPathParam("repo", o.Repo); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View File

@@ -0,0 +1,324 @@
// Code generated by go-swagger; DO NOT EDIT.
package repository
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
"src.opensuse.org/autogits/common/gitea-generated/models"
)
// RepoEditTagProtectionReader is a Reader for the RepoEditTagProtection structure.
type RepoEditTagProtectionReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *RepoEditTagProtectionReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewRepoEditTagProtectionOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
case 404:
result := NewRepoEditTagProtectionNotFound()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
case 422:
result := NewRepoEditTagProtectionUnprocessableEntity()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
case 423:
result := NewRepoEditTagProtectionLocked()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
default:
return nil, runtime.NewAPIError("[PATCH /repos/{owner}/{repo}/tag_protections/{id}] repoEditTagProtection", response, response.Code())
}
}
// NewRepoEditTagProtectionOK creates a RepoEditTagProtectionOK with default headers values
func NewRepoEditTagProtectionOK() *RepoEditTagProtectionOK {
return &RepoEditTagProtectionOK{}
}
/*
RepoEditTagProtectionOK describes a response with status code 200, with default header values.
TagProtection
*/
type RepoEditTagProtectionOK struct {
Payload *models.TagProtection
}
// IsSuccess returns true when this repo edit tag protection o k response has a 2xx status code
func (o *RepoEditTagProtectionOK) IsSuccess() bool {
return true
}
// IsRedirect returns true when this repo edit tag protection o k response has a 3xx status code
func (o *RepoEditTagProtectionOK) IsRedirect() bool {
return false
}
// IsClientError returns true when this repo edit tag protection o k response has a 4xx status code
func (o *RepoEditTagProtectionOK) IsClientError() bool {
return false
}
// IsServerError returns true when this repo edit tag protection o k response has a 5xx status code
func (o *RepoEditTagProtectionOK) IsServerError() bool {
return false
}
// IsCode returns true when this repo edit tag protection o k response a status code equal to that given
func (o *RepoEditTagProtectionOK) IsCode(code int) bool {
return code == 200
}
// Code gets the status code for the repo edit tag protection o k response
func (o *RepoEditTagProtectionOK) Code() int {
return 200
}
func (o *RepoEditTagProtectionOK) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[PATCH /repos/{owner}/{repo}/tag_protections/{id}][%d] repoEditTagProtectionOK %s", 200, payload)
}
func (o *RepoEditTagProtectionOK) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[PATCH /repos/{owner}/{repo}/tag_protections/{id}][%d] repoEditTagProtectionOK %s", 200, payload)
}
func (o *RepoEditTagProtectionOK) GetPayload() *models.TagProtection {
return o.Payload
}
func (o *RepoEditTagProtectionOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
o.Payload = new(models.TagProtection)
// response payload
if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewRepoEditTagProtectionNotFound creates a RepoEditTagProtectionNotFound with default headers values
func NewRepoEditTagProtectionNotFound() *RepoEditTagProtectionNotFound {
return &RepoEditTagProtectionNotFound{}
}
/*
RepoEditTagProtectionNotFound describes a response with status code 404, with default header values.
APINotFound is a not found empty response
*/
type RepoEditTagProtectionNotFound struct {
}
// IsSuccess returns true when this repo edit tag protection not found response has a 2xx status code
func (o *RepoEditTagProtectionNotFound) IsSuccess() bool {
return false
}
// IsRedirect returns true when this repo edit tag protection not found response has a 3xx status code
func (o *RepoEditTagProtectionNotFound) IsRedirect() bool {
return false
}
// IsClientError returns true when this repo edit tag protection not found response has a 4xx status code
func (o *RepoEditTagProtectionNotFound) IsClientError() bool {
return true
}
// IsServerError returns true when this repo edit tag protection not found response has a 5xx status code
func (o *RepoEditTagProtectionNotFound) IsServerError() bool {
return false
}
// IsCode returns true when this repo edit tag protection not found response a status code equal to that given
func (o *RepoEditTagProtectionNotFound) IsCode(code int) bool {
return code == 404
}
// Code gets the status code for the repo edit tag protection not found response
func (o *RepoEditTagProtectionNotFound) Code() int {
return 404
}
func (o *RepoEditTagProtectionNotFound) Error() string {
return fmt.Sprintf("[PATCH /repos/{owner}/{repo}/tag_protections/{id}][%d] repoEditTagProtectionNotFound", 404)
}
func (o *RepoEditTagProtectionNotFound) String() string {
return fmt.Sprintf("[PATCH /repos/{owner}/{repo}/tag_protections/{id}][%d] repoEditTagProtectionNotFound", 404)
}
func (o *RepoEditTagProtectionNotFound) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
return nil
}
// NewRepoEditTagProtectionUnprocessableEntity creates a RepoEditTagProtectionUnprocessableEntity with default headers values
func NewRepoEditTagProtectionUnprocessableEntity() *RepoEditTagProtectionUnprocessableEntity {
return &RepoEditTagProtectionUnprocessableEntity{}
}
/*
RepoEditTagProtectionUnprocessableEntity describes a response with status code 422, with default header values.
APIValidationError is error format response related to input validation
*/
type RepoEditTagProtectionUnprocessableEntity struct {
Message string
URL string
}
// IsSuccess returns true when this repo edit tag protection unprocessable entity response has a 2xx status code
func (o *RepoEditTagProtectionUnprocessableEntity) IsSuccess() bool {
return false
}
// IsRedirect returns true when this repo edit tag protection unprocessable entity response has a 3xx status code
func (o *RepoEditTagProtectionUnprocessableEntity) IsRedirect() bool {
return false
}
// IsClientError returns true when this repo edit tag protection unprocessable entity response has a 4xx status code
func (o *RepoEditTagProtectionUnprocessableEntity) IsClientError() bool {
return true
}
// IsServerError returns true when this repo edit tag protection unprocessable entity response has a 5xx status code
func (o *RepoEditTagProtectionUnprocessableEntity) IsServerError() bool {
return false
}
// IsCode returns true when this repo edit tag protection unprocessable entity response a status code equal to that given
func (o *RepoEditTagProtectionUnprocessableEntity) IsCode(code int) bool {
return code == 422
}
// Code gets the status code for the repo edit tag protection unprocessable entity response
func (o *RepoEditTagProtectionUnprocessableEntity) Code() int {
return 422
}
func (o *RepoEditTagProtectionUnprocessableEntity) Error() string {
return fmt.Sprintf("[PATCH /repos/{owner}/{repo}/tag_protections/{id}][%d] repoEditTagProtectionUnprocessableEntity", 422)
}
func (o *RepoEditTagProtectionUnprocessableEntity) String() string {
return fmt.Sprintf("[PATCH /repos/{owner}/{repo}/tag_protections/{id}][%d] repoEditTagProtectionUnprocessableEntity", 422)
}
func (o *RepoEditTagProtectionUnprocessableEntity) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// hydrates response header message
hdrMessage := response.GetHeader("message")
if hdrMessage != "" {
o.Message = hdrMessage
}
// hydrates response header url
hdrURL := response.GetHeader("url")
if hdrURL != "" {
o.URL = hdrURL
}
return nil
}
// NewRepoEditTagProtectionLocked creates a RepoEditTagProtectionLocked with default headers values
func NewRepoEditTagProtectionLocked() *RepoEditTagProtectionLocked {
return &RepoEditTagProtectionLocked{}
}
/*
RepoEditTagProtectionLocked describes a response with status code 423, with default header values.
APIRepoArchivedError is an error that is raised when an archived repo should be modified
*/
type RepoEditTagProtectionLocked struct {
Message string
URL string
}
// IsSuccess returns true when this repo edit tag protection locked response has a 2xx status code
func (o *RepoEditTagProtectionLocked) IsSuccess() bool {
return false
}
// IsRedirect returns true when this repo edit tag protection locked response has a 3xx status code
func (o *RepoEditTagProtectionLocked) IsRedirect() bool {
return false
}
// IsClientError returns true when this repo edit tag protection locked response has a 4xx status code
func (o *RepoEditTagProtectionLocked) IsClientError() bool {
return true
}
// IsServerError returns true when this repo edit tag protection locked response has a 5xx status code
func (o *RepoEditTagProtectionLocked) IsServerError() bool {
return false
}
// IsCode returns true when this repo edit tag protection locked response a status code equal to that given
func (o *RepoEditTagProtectionLocked) IsCode(code int) bool {
return code == 423
}
// Code gets the status code for the repo edit tag protection locked response
func (o *RepoEditTagProtectionLocked) Code() int {
return 423
}
func (o *RepoEditTagProtectionLocked) Error() string {
return fmt.Sprintf("[PATCH /repos/{owner}/{repo}/tag_protections/{id}][%d] repoEditTagProtectionLocked", 423)
}
func (o *RepoEditTagProtectionLocked) String() string {
return fmt.Sprintf("[PATCH /repos/{owner}/{repo}/tag_protections/{id}][%d] repoEditTagProtectionLocked", 423)
}
func (o *RepoEditTagProtectionLocked) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// hydrates response header message
hdrMessage := response.GetHeader("message")
if hdrMessage != "" {
o.Message = hdrMessage
}
// hydrates response header url
hdrURL := response.GetHeader("url")
if hdrURL != "" {
o.URL = hdrURL
}
return nil
}

View File

@@ -0,0 +1,173 @@
// Code generated by go-swagger; DO NOT EDIT.
package repository
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
)
// NewRepoGetLicensesParams creates a new RepoGetLicensesParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewRepoGetLicensesParams() *RepoGetLicensesParams {
return &RepoGetLicensesParams{
timeout: cr.DefaultTimeout,
}
}
// NewRepoGetLicensesParamsWithTimeout creates a new RepoGetLicensesParams object
// with the ability to set a timeout on a request.
func NewRepoGetLicensesParamsWithTimeout(timeout time.Duration) *RepoGetLicensesParams {
return &RepoGetLicensesParams{
timeout: timeout,
}
}
// NewRepoGetLicensesParamsWithContext creates a new RepoGetLicensesParams object
// with the ability to set a context for a request.
func NewRepoGetLicensesParamsWithContext(ctx context.Context) *RepoGetLicensesParams {
return &RepoGetLicensesParams{
Context: ctx,
}
}
// NewRepoGetLicensesParamsWithHTTPClient creates a new RepoGetLicensesParams object
// with the ability to set a custom HTTPClient for a request.
func NewRepoGetLicensesParamsWithHTTPClient(client *http.Client) *RepoGetLicensesParams {
return &RepoGetLicensesParams{
HTTPClient: client,
}
}
/*
RepoGetLicensesParams contains all the parameters to send to the API endpoint
for the repo get licenses operation.
Typically these are written to a http.Request.
*/
type RepoGetLicensesParams struct {
/* Owner.
owner of the repo
*/
Owner string
/* Repo.
name of the repo
*/
Repo string
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the repo get licenses params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *RepoGetLicensesParams) WithDefaults() *RepoGetLicensesParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the repo get licenses params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *RepoGetLicensesParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the repo get licenses params
func (o *RepoGetLicensesParams) WithTimeout(timeout time.Duration) *RepoGetLicensesParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the repo get licenses params
func (o *RepoGetLicensesParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the repo get licenses params
func (o *RepoGetLicensesParams) WithContext(ctx context.Context) *RepoGetLicensesParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the repo get licenses params
func (o *RepoGetLicensesParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the repo get licenses params
func (o *RepoGetLicensesParams) WithHTTPClient(client *http.Client) *RepoGetLicensesParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the repo get licenses params
func (o *RepoGetLicensesParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithOwner adds the owner to the repo get licenses params
func (o *RepoGetLicensesParams) WithOwner(owner string) *RepoGetLicensesParams {
o.SetOwner(owner)
return o
}
// SetOwner adds the owner to the repo get licenses params
func (o *RepoGetLicensesParams) SetOwner(owner string) {
o.Owner = owner
}
// WithRepo adds the repo to the repo get licenses params
func (o *RepoGetLicensesParams) WithRepo(repo string) *RepoGetLicensesParams {
o.SetRepo(repo)
return o
}
// SetRepo adds the repo to the repo get licenses params
func (o *RepoGetLicensesParams) SetRepo(repo string) {
o.Repo = repo
}
// WriteToRequest writes these params to a swagger request
func (o *RepoGetLicensesParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
// path param owner
if err := r.SetPathParam("owner", o.Owner); err != nil {
return err
}
// path param repo
if err := r.SetPathParam("repo", o.Repo); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View File

@@ -0,0 +1,164 @@
// Code generated by go-swagger; DO NOT EDIT.
package repository
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
)
// RepoGetLicensesReader is a Reader for the RepoGetLicenses structure.
type RepoGetLicensesReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *RepoGetLicensesReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewRepoGetLicensesOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
case 404:
result := NewRepoGetLicensesNotFound()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
default:
return nil, runtime.NewAPIError("[GET /repos/{owner}/{repo}/licenses] repoGetLicenses", response, response.Code())
}
}
// NewRepoGetLicensesOK creates a RepoGetLicensesOK with default headers values
func NewRepoGetLicensesOK() *RepoGetLicensesOK {
return &RepoGetLicensesOK{}
}
/*
RepoGetLicensesOK describes a response with status code 200, with default header values.
LicensesList
*/
type RepoGetLicensesOK struct {
Payload []string
}
// IsSuccess returns true when this repo get licenses o k response has a 2xx status code
func (o *RepoGetLicensesOK) IsSuccess() bool {
return true
}
// IsRedirect returns true when this repo get licenses o k response has a 3xx status code
func (o *RepoGetLicensesOK) IsRedirect() bool {
return false
}
// IsClientError returns true when this repo get licenses o k response has a 4xx status code
func (o *RepoGetLicensesOK) IsClientError() bool {
return false
}
// IsServerError returns true when this repo get licenses o k response has a 5xx status code
func (o *RepoGetLicensesOK) IsServerError() bool {
return false
}
// IsCode returns true when this repo get licenses o k response a status code equal to that given
func (o *RepoGetLicensesOK) IsCode(code int) bool {
return code == 200
}
// Code gets the status code for the repo get licenses o k response
func (o *RepoGetLicensesOK) Code() int {
return 200
}
func (o *RepoGetLicensesOK) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /repos/{owner}/{repo}/licenses][%d] repoGetLicensesOK %s", 200, payload)
}
func (o *RepoGetLicensesOK) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /repos/{owner}/{repo}/licenses][%d] repoGetLicensesOK %s", 200, payload)
}
func (o *RepoGetLicensesOK) GetPayload() []string {
return o.Payload
}
func (o *RepoGetLicensesOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewRepoGetLicensesNotFound creates a RepoGetLicensesNotFound with default headers values
func NewRepoGetLicensesNotFound() *RepoGetLicensesNotFound {
return &RepoGetLicensesNotFound{}
}
/*
RepoGetLicensesNotFound describes a response with status code 404, with default header values.
APINotFound is a not found empty response
*/
type RepoGetLicensesNotFound struct {
}
// IsSuccess returns true when this repo get licenses not found response has a 2xx status code
func (o *RepoGetLicensesNotFound) IsSuccess() bool {
return false
}
// IsRedirect returns true when this repo get licenses not found response has a 3xx status code
func (o *RepoGetLicensesNotFound) IsRedirect() bool {
return false
}
// IsClientError returns true when this repo get licenses not found response has a 4xx status code
func (o *RepoGetLicensesNotFound) IsClientError() bool {
return true
}
// IsServerError returns true when this repo get licenses not found response has a 5xx status code
func (o *RepoGetLicensesNotFound) IsServerError() bool {
return false
}
// IsCode returns true when this repo get licenses not found response a status code equal to that given
func (o *RepoGetLicensesNotFound) IsCode(code int) bool {
return code == 404
}
// Code gets the status code for the repo get licenses not found response
func (o *RepoGetLicensesNotFound) Code() int {
return 404
}
func (o *RepoGetLicensesNotFound) Error() string {
return fmt.Sprintf("[GET /repos/{owner}/{repo}/licenses][%d] repoGetLicensesNotFound", 404)
}
func (o *RepoGetLicensesNotFound) String() string {
return fmt.Sprintf("[GET /repos/{owner}/{repo}/licenses][%d] repoGetLicensesNotFound", 404)
}
func (o *RepoGetLicensesNotFound) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
return nil
}

View File

@@ -63,7 +63,7 @@ type RepoGetRawFileOrLFSParams struct {
/* Filepath.
filepath of the file to get
path of the file to get, it should be "{ref}/{filepath}". If there is no ref could be inferred, it will be treated as the default branch
*/
Filepath string
@@ -75,7 +75,7 @@ type RepoGetRawFileOrLFSParams struct {
/* Ref.
The name of the commit/branch/tag. Default the repositorys default branch (usually master)
The name of the commit/branch/tag. Default the repositorys default branch
*/
Ref *string

View File

@@ -63,7 +63,7 @@ type RepoGetRawFileParams struct {
/* Filepath.
filepath of the file to get
path of the file to get, it should be "{ref}/{filepath}". If there is no ref could be inferred, it will be treated as the default branch
*/
Filepath string
@@ -75,7 +75,7 @@ type RepoGetRawFileParams struct {
/* Ref.
The name of the commit/branch/tag. Default the repositorys default branch (usually master)
The name of the commit/branch/tag. Default the repositorys default branch
*/
Ref *string

View File

@@ -27,7 +27,7 @@ func (o *RepoGetRunnerRegistrationTokenReader) ReadResponse(response runtime.Cli
}
return result, nil
default:
return nil, runtime.NewAPIError("[GET /repos/{owner}/{repo}/runners/registration-token] repoGetRunnerRegistrationToken", response, response.Code())
return nil, runtime.NewAPIError("[GET /repos/{owner}/{repo}/actions/runners/registration-token] repoGetRunnerRegistrationToken", response, response.Code())
}
}
@@ -76,11 +76,11 @@ func (o *RepoGetRunnerRegistrationTokenOK) Code() int {
}
func (o *RepoGetRunnerRegistrationTokenOK) Error() string {
return fmt.Sprintf("[GET /repos/{owner}/{repo}/runners/registration-token][%d] repoGetRunnerRegistrationTokenOK", 200)
return fmt.Sprintf("[GET /repos/{owner}/{repo}/actions/runners/registration-token][%d] repoGetRunnerRegistrationTokenOK", 200)
}
func (o *RepoGetRunnerRegistrationTokenOK) String() string {
return fmt.Sprintf("[GET /repos/{owner}/{repo}/runners/registration-token][%d] repoGetRunnerRegistrationTokenOK", 200)
return fmt.Sprintf("[GET /repos/{owner}/{repo}/actions/runners/registration-token][%d] repoGetRunnerRegistrationTokenOK", 200)
}
func (o *RepoGetRunnerRegistrationTokenOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {

View File

@@ -0,0 +1,196 @@
// Code generated by go-swagger; DO NOT EDIT.
package repository
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// NewRepoGetTagProtectionParams creates a new RepoGetTagProtectionParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewRepoGetTagProtectionParams() *RepoGetTagProtectionParams {
return &RepoGetTagProtectionParams{
timeout: cr.DefaultTimeout,
}
}
// NewRepoGetTagProtectionParamsWithTimeout creates a new RepoGetTagProtectionParams object
// with the ability to set a timeout on a request.
func NewRepoGetTagProtectionParamsWithTimeout(timeout time.Duration) *RepoGetTagProtectionParams {
return &RepoGetTagProtectionParams{
timeout: timeout,
}
}
// NewRepoGetTagProtectionParamsWithContext creates a new RepoGetTagProtectionParams object
// with the ability to set a context for a request.
func NewRepoGetTagProtectionParamsWithContext(ctx context.Context) *RepoGetTagProtectionParams {
return &RepoGetTagProtectionParams{
Context: ctx,
}
}
// NewRepoGetTagProtectionParamsWithHTTPClient creates a new RepoGetTagProtectionParams object
// with the ability to set a custom HTTPClient for a request.
func NewRepoGetTagProtectionParamsWithHTTPClient(client *http.Client) *RepoGetTagProtectionParams {
return &RepoGetTagProtectionParams{
HTTPClient: client,
}
}
/*
RepoGetTagProtectionParams contains all the parameters to send to the API endpoint
for the repo get tag protection operation.
Typically these are written to a http.Request.
*/
type RepoGetTagProtectionParams struct {
/* ID.
id of the tag protect to get
*/
ID int64
/* Owner.
owner of the repo
*/
Owner string
/* Repo.
name of the repo
*/
Repo string
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the repo get tag protection params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *RepoGetTagProtectionParams) WithDefaults() *RepoGetTagProtectionParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the repo get tag protection params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *RepoGetTagProtectionParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the repo get tag protection params
func (o *RepoGetTagProtectionParams) WithTimeout(timeout time.Duration) *RepoGetTagProtectionParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the repo get tag protection params
func (o *RepoGetTagProtectionParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the repo get tag protection params
func (o *RepoGetTagProtectionParams) WithContext(ctx context.Context) *RepoGetTagProtectionParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the repo get tag protection params
func (o *RepoGetTagProtectionParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the repo get tag protection params
func (o *RepoGetTagProtectionParams) WithHTTPClient(client *http.Client) *RepoGetTagProtectionParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the repo get tag protection params
func (o *RepoGetTagProtectionParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithID adds the id to the repo get tag protection params
func (o *RepoGetTagProtectionParams) WithID(id int64) *RepoGetTagProtectionParams {
o.SetID(id)
return o
}
// SetID adds the id to the repo get tag protection params
func (o *RepoGetTagProtectionParams) SetID(id int64) {
o.ID = id
}
// WithOwner adds the owner to the repo get tag protection params
func (o *RepoGetTagProtectionParams) WithOwner(owner string) *RepoGetTagProtectionParams {
o.SetOwner(owner)
return o
}
// SetOwner adds the owner to the repo get tag protection params
func (o *RepoGetTagProtectionParams) SetOwner(owner string) {
o.Owner = owner
}
// WithRepo adds the repo to the repo get tag protection params
func (o *RepoGetTagProtectionParams) WithRepo(repo string) *RepoGetTagProtectionParams {
o.SetRepo(repo)
return o
}
// SetRepo adds the repo to the repo get tag protection params
func (o *RepoGetTagProtectionParams) SetRepo(repo string) {
o.Repo = repo
}
// WriteToRequest writes these params to a swagger request
func (o *RepoGetTagProtectionParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
// path param id
if err := r.SetPathParam("id", swag.FormatInt64(o.ID)); err != nil {
return err
}
// path param owner
if err := r.SetPathParam("owner", o.Owner); err != nil {
return err
}
// path param repo
if err := r.SetPathParam("repo", o.Repo); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View File

@@ -0,0 +1,168 @@
// Code generated by go-swagger; DO NOT EDIT.
package repository
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
"src.opensuse.org/autogits/common/gitea-generated/models"
)
// RepoGetTagProtectionReader is a Reader for the RepoGetTagProtection structure.
type RepoGetTagProtectionReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *RepoGetTagProtectionReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewRepoGetTagProtectionOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
case 404:
result := NewRepoGetTagProtectionNotFound()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
default:
return nil, runtime.NewAPIError("[GET /repos/{owner}/{repo}/tag_protections/{id}] repoGetTagProtection", response, response.Code())
}
}
// NewRepoGetTagProtectionOK creates a RepoGetTagProtectionOK with default headers values
func NewRepoGetTagProtectionOK() *RepoGetTagProtectionOK {
return &RepoGetTagProtectionOK{}
}
/*
RepoGetTagProtectionOK describes a response with status code 200, with default header values.
TagProtection
*/
type RepoGetTagProtectionOK struct {
Payload *models.TagProtection
}
// IsSuccess returns true when this repo get tag protection o k response has a 2xx status code
func (o *RepoGetTagProtectionOK) IsSuccess() bool {
return true
}
// IsRedirect returns true when this repo get tag protection o k response has a 3xx status code
func (o *RepoGetTagProtectionOK) IsRedirect() bool {
return false
}
// IsClientError returns true when this repo get tag protection o k response has a 4xx status code
func (o *RepoGetTagProtectionOK) IsClientError() bool {
return false
}
// IsServerError returns true when this repo get tag protection o k response has a 5xx status code
func (o *RepoGetTagProtectionOK) IsServerError() bool {
return false
}
// IsCode returns true when this repo get tag protection o k response a status code equal to that given
func (o *RepoGetTagProtectionOK) IsCode(code int) bool {
return code == 200
}
// Code gets the status code for the repo get tag protection o k response
func (o *RepoGetTagProtectionOK) Code() int {
return 200
}
func (o *RepoGetTagProtectionOK) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /repos/{owner}/{repo}/tag_protections/{id}][%d] repoGetTagProtectionOK %s", 200, payload)
}
func (o *RepoGetTagProtectionOK) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /repos/{owner}/{repo}/tag_protections/{id}][%d] repoGetTagProtectionOK %s", 200, payload)
}
func (o *RepoGetTagProtectionOK) GetPayload() *models.TagProtection {
return o.Payload
}
func (o *RepoGetTagProtectionOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
o.Payload = new(models.TagProtection)
// response payload
if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewRepoGetTagProtectionNotFound creates a RepoGetTagProtectionNotFound with default headers values
func NewRepoGetTagProtectionNotFound() *RepoGetTagProtectionNotFound {
return &RepoGetTagProtectionNotFound{}
}
/*
RepoGetTagProtectionNotFound describes a response with status code 404, with default header values.
APINotFound is a not found empty response
*/
type RepoGetTagProtectionNotFound struct {
}
// IsSuccess returns true when this repo get tag protection not found response has a 2xx status code
func (o *RepoGetTagProtectionNotFound) IsSuccess() bool {
return false
}
// IsRedirect returns true when this repo get tag protection not found response has a 3xx status code
func (o *RepoGetTagProtectionNotFound) IsRedirect() bool {
return false
}
// IsClientError returns true when this repo get tag protection not found response has a 4xx status code
func (o *RepoGetTagProtectionNotFound) IsClientError() bool {
return true
}
// IsServerError returns true when this repo get tag protection not found response has a 5xx status code
func (o *RepoGetTagProtectionNotFound) IsServerError() bool {
return false
}
// IsCode returns true when this repo get tag protection not found response a status code equal to that given
func (o *RepoGetTagProtectionNotFound) IsCode(code int) bool {
return code == 404
}
// Code gets the status code for the repo get tag protection not found response
func (o *RepoGetTagProtectionNotFound) Code() int {
return 404
}
func (o *RepoGetTagProtectionNotFound) Error() string {
return fmt.Sprintf("[GET /repos/{owner}/{repo}/tag_protections/{id}][%d] repoGetTagProtectionNotFound", 404)
}
func (o *RepoGetTagProtectionNotFound) String() string {
return fmt.Sprintf("[GET /repos/{owner}/{repo}/tag_protections/{id}][%d] repoGetTagProtectionNotFound", 404)
}
func (o *RepoGetTagProtectionNotFound) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
return nil
}

View File

@@ -70,7 +70,7 @@ type RepoListPullRequestsParams struct {
/* Limit.
page size of results
Page size of results
*/
Limit *int64
@@ -84,19 +84,27 @@ type RepoListPullRequestsParams struct {
/* Owner.
owner of the repo
Owner of the repo
*/
Owner string
/* Page.
page number of results to return (1-based)
Page number of results to return (1-based)
Default: 1
*/
Page *int64
/* Poster.
Filter by pull request author
*/
Poster *string
/* Repo.
name of the repo
Name of the repo
*/
Repo string
@@ -108,7 +116,9 @@ type RepoListPullRequestsParams struct {
/* State.
State of pull request: open or closed (optional)
State of pull request
Default: "open"
*/
State *string
@@ -129,7 +139,21 @@ func (o *RepoListPullRequestsParams) WithDefaults() *RepoListPullRequestsParams
//
// All values with no default are reset to their zero value.
func (o *RepoListPullRequestsParams) SetDefaults() {
// no default values defined for this parameter
var (
pageDefault = int64(1)
stateDefault = string("open")
)
val := RepoListPullRequestsParams{
Page: &pageDefault,
State: &stateDefault,
}
val.timeout = o.timeout
val.Context = o.Context
val.HTTPClient = o.HTTPClient
*o = val
}
// WithTimeout adds the timeout to the repo list pull requests params
@@ -220,6 +244,17 @@ func (o *RepoListPullRequestsParams) SetPage(page *int64) {
o.Page = page
}
// WithPoster adds the poster to the repo list pull requests params
func (o *RepoListPullRequestsParams) WithPoster(poster *string) *RepoListPullRequestsParams {
o.SetPoster(poster)
return o
}
// SetPoster adds the poster to the repo list pull requests params
func (o *RepoListPullRequestsParams) SetPoster(poster *string) {
o.Poster = poster
}
// WithRepo adds the repo to the repo list pull requests params
func (o *RepoListPullRequestsParams) WithRepo(repo string) *RepoListPullRequestsParams {
o.SetRepo(repo)
@@ -328,6 +363,23 @@ func (o *RepoListPullRequestsParams) WriteToRequest(r runtime.ClientRequest, reg
}
}
if o.Poster != nil {
// query param poster
var qrPoster string
if o.Poster != nil {
qrPoster = *o.Poster
}
qPoster := qrPoster
if qPoster != "" {
if err := r.SetQueryParam("poster", qPoster); err != nil {
return err
}
}
}
// path param repo
if err := r.SetPathParam("repo", o.Repo); err != nil {
return err

View File

@@ -36,6 +36,12 @@ func (o *RepoListPullRequestsReader) ReadResponse(response runtime.ClientRespons
return nil, err
}
return nil, result
case 500:
result := NewRepoListPullRequestsInternalServerError()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
default:
return nil, runtime.NewAPIError("[GET /repos/{owner}/{repo}/pulls] repoListPullRequests", response, response.Code())
}
@@ -164,3 +170,75 @@ func (o *RepoListPullRequestsNotFound) readResponse(response runtime.ClientRespo
return nil
}
// NewRepoListPullRequestsInternalServerError creates a RepoListPullRequestsInternalServerError with default headers values
func NewRepoListPullRequestsInternalServerError() *RepoListPullRequestsInternalServerError {
return &RepoListPullRequestsInternalServerError{}
}
/*
RepoListPullRequestsInternalServerError describes a response with status code 500, with default header values.
APIError is error format response
*/
type RepoListPullRequestsInternalServerError struct {
Message string
URL string
}
// IsSuccess returns true when this repo list pull requests internal server error response has a 2xx status code
func (o *RepoListPullRequestsInternalServerError) IsSuccess() bool {
return false
}
// IsRedirect returns true when this repo list pull requests internal server error response has a 3xx status code
func (o *RepoListPullRequestsInternalServerError) IsRedirect() bool {
return false
}
// IsClientError returns true when this repo list pull requests internal server error response has a 4xx status code
func (o *RepoListPullRequestsInternalServerError) IsClientError() bool {
return false
}
// IsServerError returns true when this repo list pull requests internal server error response has a 5xx status code
func (o *RepoListPullRequestsInternalServerError) IsServerError() bool {
return true
}
// IsCode returns true when this repo list pull requests internal server error response a status code equal to that given
func (o *RepoListPullRequestsInternalServerError) IsCode(code int) bool {
return code == 500
}
// Code gets the status code for the repo list pull requests internal server error response
func (o *RepoListPullRequestsInternalServerError) Code() int {
return 500
}
func (o *RepoListPullRequestsInternalServerError) Error() string {
return fmt.Sprintf("[GET /repos/{owner}/{repo}/pulls][%d] repoListPullRequestsInternalServerError", 500)
}
func (o *RepoListPullRequestsInternalServerError) String() string {
return fmt.Sprintf("[GET /repos/{owner}/{repo}/pulls][%d] repoListPullRequestsInternalServerError", 500)
}
func (o *RepoListPullRequestsInternalServerError) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// hydrates response header message
hdrMessage := response.GetHeader("message")
if hdrMessage != "" {
o.Message = hdrMessage
}
// hydrates response header url
hdrURL := response.GetHeader("url")
if hdrURL != "" {
o.URL = hdrURL
}
return nil
}

View File

@@ -0,0 +1,173 @@
// Code generated by go-swagger; DO NOT EDIT.
package repository
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
)
// NewRepoListTagProtectionParams creates a new RepoListTagProtectionParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewRepoListTagProtectionParams() *RepoListTagProtectionParams {
return &RepoListTagProtectionParams{
timeout: cr.DefaultTimeout,
}
}
// NewRepoListTagProtectionParamsWithTimeout creates a new RepoListTagProtectionParams object
// with the ability to set a timeout on a request.
func NewRepoListTagProtectionParamsWithTimeout(timeout time.Duration) *RepoListTagProtectionParams {
return &RepoListTagProtectionParams{
timeout: timeout,
}
}
// NewRepoListTagProtectionParamsWithContext creates a new RepoListTagProtectionParams object
// with the ability to set a context for a request.
func NewRepoListTagProtectionParamsWithContext(ctx context.Context) *RepoListTagProtectionParams {
return &RepoListTagProtectionParams{
Context: ctx,
}
}
// NewRepoListTagProtectionParamsWithHTTPClient creates a new RepoListTagProtectionParams object
// with the ability to set a custom HTTPClient for a request.
func NewRepoListTagProtectionParamsWithHTTPClient(client *http.Client) *RepoListTagProtectionParams {
return &RepoListTagProtectionParams{
HTTPClient: client,
}
}
/*
RepoListTagProtectionParams contains all the parameters to send to the API endpoint
for the repo list tag protection operation.
Typically these are written to a http.Request.
*/
type RepoListTagProtectionParams struct {
/* Owner.
owner of the repo
*/
Owner string
/* Repo.
name of the repo
*/
Repo string
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the repo list tag protection params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *RepoListTagProtectionParams) WithDefaults() *RepoListTagProtectionParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the repo list tag protection params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *RepoListTagProtectionParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the repo list tag protection params
func (o *RepoListTagProtectionParams) WithTimeout(timeout time.Duration) *RepoListTagProtectionParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the repo list tag protection params
func (o *RepoListTagProtectionParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the repo list tag protection params
func (o *RepoListTagProtectionParams) WithContext(ctx context.Context) *RepoListTagProtectionParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the repo list tag protection params
func (o *RepoListTagProtectionParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the repo list tag protection params
func (o *RepoListTagProtectionParams) WithHTTPClient(client *http.Client) *RepoListTagProtectionParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the repo list tag protection params
func (o *RepoListTagProtectionParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithOwner adds the owner to the repo list tag protection params
func (o *RepoListTagProtectionParams) WithOwner(owner string) *RepoListTagProtectionParams {
o.SetOwner(owner)
return o
}
// SetOwner adds the owner to the repo list tag protection params
func (o *RepoListTagProtectionParams) SetOwner(owner string) {
o.Owner = owner
}
// WithRepo adds the repo to the repo list tag protection params
func (o *RepoListTagProtectionParams) WithRepo(repo string) *RepoListTagProtectionParams {
o.SetRepo(repo)
return o
}
// SetRepo adds the repo to the repo list tag protection params
func (o *RepoListTagProtectionParams) SetRepo(repo string) {
o.Repo = repo
}
// WriteToRequest writes these params to a swagger request
func (o *RepoListTagProtectionParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
// path param owner
if err := r.SetPathParam("owner", o.Owner); err != nil {
return err
}
// path param repo
if err := r.SetPathParam("repo", o.Repo); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View File

@@ -0,0 +1,104 @@
// Code generated by go-swagger; DO NOT EDIT.
package repository
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
"src.opensuse.org/autogits/common/gitea-generated/models"
)
// RepoListTagProtectionReader is a Reader for the RepoListTagProtection structure.
type RepoListTagProtectionReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *RepoListTagProtectionReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewRepoListTagProtectionOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
default:
return nil, runtime.NewAPIError("[GET /repos/{owner}/{repo}/tag_protections] repoListTagProtection", response, response.Code())
}
}
// NewRepoListTagProtectionOK creates a RepoListTagProtectionOK with default headers values
func NewRepoListTagProtectionOK() *RepoListTagProtectionOK {
return &RepoListTagProtectionOK{}
}
/*
RepoListTagProtectionOK describes a response with status code 200, with default header values.
TagProtectionList
*/
type RepoListTagProtectionOK struct {
Payload []*models.TagProtection
}
// IsSuccess returns true when this repo list tag protection o k response has a 2xx status code
func (o *RepoListTagProtectionOK) IsSuccess() bool {
return true
}
// IsRedirect returns true when this repo list tag protection o k response has a 3xx status code
func (o *RepoListTagProtectionOK) IsRedirect() bool {
return false
}
// IsClientError returns true when this repo list tag protection o k response has a 4xx status code
func (o *RepoListTagProtectionOK) IsClientError() bool {
return false
}
// IsServerError returns true when this repo list tag protection o k response has a 5xx status code
func (o *RepoListTagProtectionOK) IsServerError() bool {
return false
}
// IsCode returns true when this repo list tag protection o k response a status code equal to that given
func (o *RepoListTagProtectionOK) IsCode(code int) bool {
return code == 200
}
// Code gets the status code for the repo list tag protection o k response
func (o *RepoListTagProtectionOK) Code() int {
return 200
}
func (o *RepoListTagProtectionOK) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /repos/{owner}/{repo}/tag_protections][%d] repoListTagProtectionOK %s", 200, payload)
}
func (o *RepoListTagProtectionOK) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[GET /repos/{owner}/{repo}/tag_protections][%d] repoListTagProtectionOK %s", 200, payload)
}
func (o *RepoListTagProtectionOK) GetPayload() []*models.TagProtection {
return o.Payload
}
func (o *RepoListTagProtectionOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// response payload
if err := consumer.Consume(response.Body(), &o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}

View File

@@ -0,0 +1,194 @@
// Code generated by go-swagger; DO NOT EDIT.
package repository
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
"src.opensuse.org/autogits/common/gitea-generated/models"
)
// NewRepoMergeUpstreamParams creates a new RepoMergeUpstreamParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewRepoMergeUpstreamParams() *RepoMergeUpstreamParams {
return &RepoMergeUpstreamParams{
timeout: cr.DefaultTimeout,
}
}
// NewRepoMergeUpstreamParamsWithTimeout creates a new RepoMergeUpstreamParams object
// with the ability to set a timeout on a request.
func NewRepoMergeUpstreamParamsWithTimeout(timeout time.Duration) *RepoMergeUpstreamParams {
return &RepoMergeUpstreamParams{
timeout: timeout,
}
}
// NewRepoMergeUpstreamParamsWithContext creates a new RepoMergeUpstreamParams object
// with the ability to set a context for a request.
func NewRepoMergeUpstreamParamsWithContext(ctx context.Context) *RepoMergeUpstreamParams {
return &RepoMergeUpstreamParams{
Context: ctx,
}
}
// NewRepoMergeUpstreamParamsWithHTTPClient creates a new RepoMergeUpstreamParams object
// with the ability to set a custom HTTPClient for a request.
func NewRepoMergeUpstreamParamsWithHTTPClient(client *http.Client) *RepoMergeUpstreamParams {
return &RepoMergeUpstreamParams{
HTTPClient: client,
}
}
/*
RepoMergeUpstreamParams contains all the parameters to send to the API endpoint
for the repo merge upstream operation.
Typically these are written to a http.Request.
*/
type RepoMergeUpstreamParams struct {
// Body.
Body *models.MergeUpstreamRequest
/* Owner.
owner of the repo
*/
Owner string
/* Repo.
name of the repo
*/
Repo string
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the repo merge upstream params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *RepoMergeUpstreamParams) WithDefaults() *RepoMergeUpstreamParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the repo merge upstream params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *RepoMergeUpstreamParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the repo merge upstream params
func (o *RepoMergeUpstreamParams) WithTimeout(timeout time.Duration) *RepoMergeUpstreamParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the repo merge upstream params
func (o *RepoMergeUpstreamParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the repo merge upstream params
func (o *RepoMergeUpstreamParams) WithContext(ctx context.Context) *RepoMergeUpstreamParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the repo merge upstream params
func (o *RepoMergeUpstreamParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the repo merge upstream params
func (o *RepoMergeUpstreamParams) WithHTTPClient(client *http.Client) *RepoMergeUpstreamParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the repo merge upstream params
func (o *RepoMergeUpstreamParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithBody adds the body to the repo merge upstream params
func (o *RepoMergeUpstreamParams) WithBody(body *models.MergeUpstreamRequest) *RepoMergeUpstreamParams {
o.SetBody(body)
return o
}
// SetBody adds the body to the repo merge upstream params
func (o *RepoMergeUpstreamParams) SetBody(body *models.MergeUpstreamRequest) {
o.Body = body
}
// WithOwner adds the owner to the repo merge upstream params
func (o *RepoMergeUpstreamParams) WithOwner(owner string) *RepoMergeUpstreamParams {
o.SetOwner(owner)
return o
}
// SetOwner adds the owner to the repo merge upstream params
func (o *RepoMergeUpstreamParams) SetOwner(owner string) {
o.Owner = owner
}
// WithRepo adds the repo to the repo merge upstream params
func (o *RepoMergeUpstreamParams) WithRepo(repo string) *RepoMergeUpstreamParams {
o.SetRepo(repo)
return o
}
// SetRepo adds the repo to the repo merge upstream params
func (o *RepoMergeUpstreamParams) SetRepo(repo string) {
o.Repo = repo
}
// WriteToRequest writes these params to a swagger request
func (o *RepoMergeUpstreamParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
if o.Body != nil {
if err := r.SetBodyParam(o.Body); err != nil {
return err
}
}
// path param owner
if err := r.SetPathParam("owner", o.Owner); err != nil {
return err
}
// path param repo
if err := r.SetPathParam("repo", o.Repo); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View File

@@ -0,0 +1,246 @@
// Code generated by go-swagger; DO NOT EDIT.
package repository
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"encoding/json"
"fmt"
"io"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
"src.opensuse.org/autogits/common/gitea-generated/models"
)
// RepoMergeUpstreamReader is a Reader for the RepoMergeUpstream structure.
type RepoMergeUpstreamReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *RepoMergeUpstreamReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 200:
result := NewRepoMergeUpstreamOK()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
case 400:
result := NewRepoMergeUpstreamBadRequest()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
case 404:
result := NewRepoMergeUpstreamNotFound()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
default:
return nil, runtime.NewAPIError("[POST /repos/{owner}/{repo}/merge-upstream] repoMergeUpstream", response, response.Code())
}
}
// NewRepoMergeUpstreamOK creates a RepoMergeUpstreamOK with default headers values
func NewRepoMergeUpstreamOK() *RepoMergeUpstreamOK {
return &RepoMergeUpstreamOK{}
}
/*
RepoMergeUpstreamOK describes a response with status code 200, with default header values.
RepoMergeUpstreamOK repo merge upstream o k
*/
type RepoMergeUpstreamOK struct {
Payload *models.MergeUpstreamResponse
}
// IsSuccess returns true when this repo merge upstream o k response has a 2xx status code
func (o *RepoMergeUpstreamOK) IsSuccess() bool {
return true
}
// IsRedirect returns true when this repo merge upstream o k response has a 3xx status code
func (o *RepoMergeUpstreamOK) IsRedirect() bool {
return false
}
// IsClientError returns true when this repo merge upstream o k response has a 4xx status code
func (o *RepoMergeUpstreamOK) IsClientError() bool {
return false
}
// IsServerError returns true when this repo merge upstream o k response has a 5xx status code
func (o *RepoMergeUpstreamOK) IsServerError() bool {
return false
}
// IsCode returns true when this repo merge upstream o k response a status code equal to that given
func (o *RepoMergeUpstreamOK) IsCode(code int) bool {
return code == 200
}
// Code gets the status code for the repo merge upstream o k response
func (o *RepoMergeUpstreamOK) Code() int {
return 200
}
func (o *RepoMergeUpstreamOK) Error() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[POST /repos/{owner}/{repo}/merge-upstream][%d] repoMergeUpstreamOK %s", 200, payload)
}
func (o *RepoMergeUpstreamOK) String() string {
payload, _ := json.Marshal(o.Payload)
return fmt.Sprintf("[POST /repos/{owner}/{repo}/merge-upstream][%d] repoMergeUpstreamOK %s", 200, payload)
}
func (o *RepoMergeUpstreamOK) GetPayload() *models.MergeUpstreamResponse {
return o.Payload
}
func (o *RepoMergeUpstreamOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
o.Payload = new(models.MergeUpstreamResponse)
// response payload
if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF {
return err
}
return nil
}
// NewRepoMergeUpstreamBadRequest creates a RepoMergeUpstreamBadRequest with default headers values
func NewRepoMergeUpstreamBadRequest() *RepoMergeUpstreamBadRequest {
return &RepoMergeUpstreamBadRequest{}
}
/*
RepoMergeUpstreamBadRequest describes a response with status code 400, with default header values.
APIError is error format response
*/
type RepoMergeUpstreamBadRequest struct {
Message string
URL string
}
// IsSuccess returns true when this repo merge upstream bad request response has a 2xx status code
func (o *RepoMergeUpstreamBadRequest) IsSuccess() bool {
return false
}
// IsRedirect returns true when this repo merge upstream bad request response has a 3xx status code
func (o *RepoMergeUpstreamBadRequest) IsRedirect() bool {
return false
}
// IsClientError returns true when this repo merge upstream bad request response has a 4xx status code
func (o *RepoMergeUpstreamBadRequest) IsClientError() bool {
return true
}
// IsServerError returns true when this repo merge upstream bad request response has a 5xx status code
func (o *RepoMergeUpstreamBadRequest) IsServerError() bool {
return false
}
// IsCode returns true when this repo merge upstream bad request response a status code equal to that given
func (o *RepoMergeUpstreamBadRequest) IsCode(code int) bool {
return code == 400
}
// Code gets the status code for the repo merge upstream bad request response
func (o *RepoMergeUpstreamBadRequest) Code() int {
return 400
}
func (o *RepoMergeUpstreamBadRequest) Error() string {
return fmt.Sprintf("[POST /repos/{owner}/{repo}/merge-upstream][%d] repoMergeUpstreamBadRequest", 400)
}
func (o *RepoMergeUpstreamBadRequest) String() string {
return fmt.Sprintf("[POST /repos/{owner}/{repo}/merge-upstream][%d] repoMergeUpstreamBadRequest", 400)
}
func (o *RepoMergeUpstreamBadRequest) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// hydrates response header message
hdrMessage := response.GetHeader("message")
if hdrMessage != "" {
o.Message = hdrMessage
}
// hydrates response header url
hdrURL := response.GetHeader("url")
if hdrURL != "" {
o.URL = hdrURL
}
return nil
}
// NewRepoMergeUpstreamNotFound creates a RepoMergeUpstreamNotFound with default headers values
func NewRepoMergeUpstreamNotFound() *RepoMergeUpstreamNotFound {
return &RepoMergeUpstreamNotFound{}
}
/*
RepoMergeUpstreamNotFound describes a response with status code 404, with default header values.
APINotFound is a not found empty response
*/
type RepoMergeUpstreamNotFound struct {
}
// IsSuccess returns true when this repo merge upstream not found response has a 2xx status code
func (o *RepoMergeUpstreamNotFound) IsSuccess() bool {
return false
}
// IsRedirect returns true when this repo merge upstream not found response has a 3xx status code
func (o *RepoMergeUpstreamNotFound) IsRedirect() bool {
return false
}
// IsClientError returns true when this repo merge upstream not found response has a 4xx status code
func (o *RepoMergeUpstreamNotFound) IsClientError() bool {
return true
}
// IsServerError returns true when this repo merge upstream not found response has a 5xx status code
func (o *RepoMergeUpstreamNotFound) IsServerError() bool {
return false
}
// IsCode returns true when this repo merge upstream not found response a status code equal to that given
func (o *RepoMergeUpstreamNotFound) IsCode(code int) bool {
return code == 404
}
// Code gets the status code for the repo merge upstream not found response
func (o *RepoMergeUpstreamNotFound) Code() int {
return 404
}
func (o *RepoMergeUpstreamNotFound) Error() string {
return fmt.Sprintf("[POST /repos/{owner}/{repo}/merge-upstream][%d] repoMergeUpstreamNotFound", 404)
}
func (o *RepoMergeUpstreamNotFound) String() string {
return fmt.Sprintf("[POST /repos/{owner}/{repo}/merge-upstream][%d] repoMergeUpstreamNotFound", 404)
}
func (o *RepoMergeUpstreamNotFound) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
return nil
}

View File

@@ -132,7 +132,7 @@ type RepoSearchParams struct {
/* Sort.
sort repos by attribute. Supported values are "alpha", "created", "updated", "size", and "id". Default is "alpha"
sort repos by attribute. Supported values are "alpha", "created", "updated", "size", "git_size", "lfs_size", "stars", "forks" and "id". Default is "alpha"
*/
Sort *string

View File

@@ -0,0 +1,216 @@
// Code generated by go-swagger; DO NOT EDIT.
package repository
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
"src.opensuse.org/autogits/common/gitea-generated/models"
)
// NewRepoUpdateBranchParams creates a new RepoUpdateBranchParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewRepoUpdateBranchParams() *RepoUpdateBranchParams {
return &RepoUpdateBranchParams{
timeout: cr.DefaultTimeout,
}
}
// NewRepoUpdateBranchParamsWithTimeout creates a new RepoUpdateBranchParams object
// with the ability to set a timeout on a request.
func NewRepoUpdateBranchParamsWithTimeout(timeout time.Duration) *RepoUpdateBranchParams {
return &RepoUpdateBranchParams{
timeout: timeout,
}
}
// NewRepoUpdateBranchParamsWithContext creates a new RepoUpdateBranchParams object
// with the ability to set a context for a request.
func NewRepoUpdateBranchParamsWithContext(ctx context.Context) *RepoUpdateBranchParams {
return &RepoUpdateBranchParams{
Context: ctx,
}
}
// NewRepoUpdateBranchParamsWithHTTPClient creates a new RepoUpdateBranchParams object
// with the ability to set a custom HTTPClient for a request.
func NewRepoUpdateBranchParamsWithHTTPClient(client *http.Client) *RepoUpdateBranchParams {
return &RepoUpdateBranchParams{
HTTPClient: client,
}
}
/*
RepoUpdateBranchParams contains all the parameters to send to the API endpoint
for the repo update branch operation.
Typically these are written to a http.Request.
*/
type RepoUpdateBranchParams struct {
// Body.
Body *models.UpdateBranchRepoOption
/* Branch.
name of the branch
*/
Branch string
/* Owner.
owner of the repo
*/
Owner string
/* Repo.
name of the repo
*/
Repo string
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the repo update branch params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *RepoUpdateBranchParams) WithDefaults() *RepoUpdateBranchParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the repo update branch params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *RepoUpdateBranchParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the repo update branch params
func (o *RepoUpdateBranchParams) WithTimeout(timeout time.Duration) *RepoUpdateBranchParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the repo update branch params
func (o *RepoUpdateBranchParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the repo update branch params
func (o *RepoUpdateBranchParams) WithContext(ctx context.Context) *RepoUpdateBranchParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the repo update branch params
func (o *RepoUpdateBranchParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the repo update branch params
func (o *RepoUpdateBranchParams) WithHTTPClient(client *http.Client) *RepoUpdateBranchParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the repo update branch params
func (o *RepoUpdateBranchParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithBody adds the body to the repo update branch params
func (o *RepoUpdateBranchParams) WithBody(body *models.UpdateBranchRepoOption) *RepoUpdateBranchParams {
o.SetBody(body)
return o
}
// SetBody adds the body to the repo update branch params
func (o *RepoUpdateBranchParams) SetBody(body *models.UpdateBranchRepoOption) {
o.Body = body
}
// WithBranch adds the branch to the repo update branch params
func (o *RepoUpdateBranchParams) WithBranch(branch string) *RepoUpdateBranchParams {
o.SetBranch(branch)
return o
}
// SetBranch adds the branch to the repo update branch params
func (o *RepoUpdateBranchParams) SetBranch(branch string) {
o.Branch = branch
}
// WithOwner adds the owner to the repo update branch params
func (o *RepoUpdateBranchParams) WithOwner(owner string) *RepoUpdateBranchParams {
o.SetOwner(owner)
return o
}
// SetOwner adds the owner to the repo update branch params
func (o *RepoUpdateBranchParams) SetOwner(owner string) {
o.Owner = owner
}
// WithRepo adds the repo to the repo update branch params
func (o *RepoUpdateBranchParams) WithRepo(repo string) *RepoUpdateBranchParams {
o.SetRepo(repo)
return o
}
// SetRepo adds the repo to the repo update branch params
func (o *RepoUpdateBranchParams) SetRepo(repo string) {
o.Repo = repo
}
// WriteToRequest writes these params to a swagger request
func (o *RepoUpdateBranchParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
if o.Body != nil {
if err := r.SetBodyParam(o.Body); err != nil {
return err
}
}
// path param branch
if err := r.SetPathParam("branch", o.Branch); err != nil {
return err
}
// path param owner
if err := r.SetPathParam("owner", o.Owner); err != nil {
return err
}
// path param repo
if err := r.SetPathParam("repo", o.Repo); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View File

@@ -0,0 +1,194 @@
// Code generated by go-swagger; DO NOT EDIT.
package repository
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"net/http"
"time"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime"
cr "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
"src.opensuse.org/autogits/common/gitea-generated/models"
)
// NewRepoUpdateBranchProtectionPrioriesParams creates a new RepoUpdateBranchProtectionPrioriesParams object,
// with the default timeout for this client.
//
// Default values are not hydrated, since defaults are normally applied by the API server side.
//
// To enforce default values in parameter, use SetDefaults or WithDefaults.
func NewRepoUpdateBranchProtectionPrioriesParams() *RepoUpdateBranchProtectionPrioriesParams {
return &RepoUpdateBranchProtectionPrioriesParams{
timeout: cr.DefaultTimeout,
}
}
// NewRepoUpdateBranchProtectionPrioriesParamsWithTimeout creates a new RepoUpdateBranchProtectionPrioriesParams object
// with the ability to set a timeout on a request.
func NewRepoUpdateBranchProtectionPrioriesParamsWithTimeout(timeout time.Duration) *RepoUpdateBranchProtectionPrioriesParams {
return &RepoUpdateBranchProtectionPrioriesParams{
timeout: timeout,
}
}
// NewRepoUpdateBranchProtectionPrioriesParamsWithContext creates a new RepoUpdateBranchProtectionPrioriesParams object
// with the ability to set a context for a request.
func NewRepoUpdateBranchProtectionPrioriesParamsWithContext(ctx context.Context) *RepoUpdateBranchProtectionPrioriesParams {
return &RepoUpdateBranchProtectionPrioriesParams{
Context: ctx,
}
}
// NewRepoUpdateBranchProtectionPrioriesParamsWithHTTPClient creates a new RepoUpdateBranchProtectionPrioriesParams object
// with the ability to set a custom HTTPClient for a request.
func NewRepoUpdateBranchProtectionPrioriesParamsWithHTTPClient(client *http.Client) *RepoUpdateBranchProtectionPrioriesParams {
return &RepoUpdateBranchProtectionPrioriesParams{
HTTPClient: client,
}
}
/*
RepoUpdateBranchProtectionPrioriesParams contains all the parameters to send to the API endpoint
for the repo update branch protection priories operation.
Typically these are written to a http.Request.
*/
type RepoUpdateBranchProtectionPrioriesParams struct {
// Body.
Body *models.UpdateBranchProtectionPriories
/* Owner.
owner of the repo
*/
Owner string
/* Repo.
name of the repo
*/
Repo string
timeout time.Duration
Context context.Context
HTTPClient *http.Client
}
// WithDefaults hydrates default values in the repo update branch protection priories params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *RepoUpdateBranchProtectionPrioriesParams) WithDefaults() *RepoUpdateBranchProtectionPrioriesParams {
o.SetDefaults()
return o
}
// SetDefaults hydrates default values in the repo update branch protection priories params (not the query body).
//
// All values with no default are reset to their zero value.
func (o *RepoUpdateBranchProtectionPrioriesParams) SetDefaults() {
// no default values defined for this parameter
}
// WithTimeout adds the timeout to the repo update branch protection priories params
func (o *RepoUpdateBranchProtectionPrioriesParams) WithTimeout(timeout time.Duration) *RepoUpdateBranchProtectionPrioriesParams {
o.SetTimeout(timeout)
return o
}
// SetTimeout adds the timeout to the repo update branch protection priories params
func (o *RepoUpdateBranchProtectionPrioriesParams) SetTimeout(timeout time.Duration) {
o.timeout = timeout
}
// WithContext adds the context to the repo update branch protection priories params
func (o *RepoUpdateBranchProtectionPrioriesParams) WithContext(ctx context.Context) *RepoUpdateBranchProtectionPrioriesParams {
o.SetContext(ctx)
return o
}
// SetContext adds the context to the repo update branch protection priories params
func (o *RepoUpdateBranchProtectionPrioriesParams) SetContext(ctx context.Context) {
o.Context = ctx
}
// WithHTTPClient adds the HTTPClient to the repo update branch protection priories params
func (o *RepoUpdateBranchProtectionPrioriesParams) WithHTTPClient(client *http.Client) *RepoUpdateBranchProtectionPrioriesParams {
o.SetHTTPClient(client)
return o
}
// SetHTTPClient adds the HTTPClient to the repo update branch protection priories params
func (o *RepoUpdateBranchProtectionPrioriesParams) SetHTTPClient(client *http.Client) {
o.HTTPClient = client
}
// WithBody adds the body to the repo update branch protection priories params
func (o *RepoUpdateBranchProtectionPrioriesParams) WithBody(body *models.UpdateBranchProtectionPriories) *RepoUpdateBranchProtectionPrioriesParams {
o.SetBody(body)
return o
}
// SetBody adds the body to the repo update branch protection priories params
func (o *RepoUpdateBranchProtectionPrioriesParams) SetBody(body *models.UpdateBranchProtectionPriories) {
o.Body = body
}
// WithOwner adds the owner to the repo update branch protection priories params
func (o *RepoUpdateBranchProtectionPrioriesParams) WithOwner(owner string) *RepoUpdateBranchProtectionPrioriesParams {
o.SetOwner(owner)
return o
}
// SetOwner adds the owner to the repo update branch protection priories params
func (o *RepoUpdateBranchProtectionPrioriesParams) SetOwner(owner string) {
o.Owner = owner
}
// WithRepo adds the repo to the repo update branch protection priories params
func (o *RepoUpdateBranchProtectionPrioriesParams) WithRepo(repo string) *RepoUpdateBranchProtectionPrioriesParams {
o.SetRepo(repo)
return o
}
// SetRepo adds the repo to the repo update branch protection priories params
func (o *RepoUpdateBranchProtectionPrioriesParams) SetRepo(repo string) {
o.Repo = repo
}
// WriteToRequest writes these params to a swagger request
func (o *RepoUpdateBranchProtectionPrioriesParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error {
if err := r.SetTimeout(o.timeout); err != nil {
return err
}
var res []error
if o.Body != nil {
if err := r.SetBodyParam(o.Body); err != nil {
return err
}
}
// path param owner
if err := r.SetPathParam("owner", o.Owner); err != nil {
return err
}
// path param repo
if err := r.SetPathParam("repo", o.Repo); err != nil {
return err
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}

View File

@@ -0,0 +1,306 @@
// Code generated by go-swagger; DO NOT EDIT.
package repository
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"fmt"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
)
// RepoUpdateBranchProtectionPrioriesReader is a Reader for the RepoUpdateBranchProtectionPriories structure.
type RepoUpdateBranchProtectionPrioriesReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *RepoUpdateBranchProtectionPrioriesReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 204:
result := NewRepoUpdateBranchProtectionPrioriesNoContent()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
case 404:
result := NewRepoUpdateBranchProtectionPrioriesNotFound()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
case 422:
result := NewRepoUpdateBranchProtectionPrioriesUnprocessableEntity()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
case 423:
result := NewRepoUpdateBranchProtectionPrioriesLocked()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
default:
return nil, runtime.NewAPIError("[POST /repos/{owner}/{repo}/branch_protections/priority] repoUpdateBranchProtectionPriories", response, response.Code())
}
}
// NewRepoUpdateBranchProtectionPrioriesNoContent creates a RepoUpdateBranchProtectionPrioriesNoContent with default headers values
func NewRepoUpdateBranchProtectionPrioriesNoContent() *RepoUpdateBranchProtectionPrioriesNoContent {
return &RepoUpdateBranchProtectionPrioriesNoContent{}
}
/*
RepoUpdateBranchProtectionPrioriesNoContent describes a response with status code 204, with default header values.
APIEmpty is an empty response
*/
type RepoUpdateBranchProtectionPrioriesNoContent struct {
}
// IsSuccess returns true when this repo update branch protection priories no content response has a 2xx status code
func (o *RepoUpdateBranchProtectionPrioriesNoContent) IsSuccess() bool {
return true
}
// IsRedirect returns true when this repo update branch protection priories no content response has a 3xx status code
func (o *RepoUpdateBranchProtectionPrioriesNoContent) IsRedirect() bool {
return false
}
// IsClientError returns true when this repo update branch protection priories no content response has a 4xx status code
func (o *RepoUpdateBranchProtectionPrioriesNoContent) IsClientError() bool {
return false
}
// IsServerError returns true when this repo update branch protection priories no content response has a 5xx status code
func (o *RepoUpdateBranchProtectionPrioriesNoContent) IsServerError() bool {
return false
}
// IsCode returns true when this repo update branch protection priories no content response a status code equal to that given
func (o *RepoUpdateBranchProtectionPrioriesNoContent) IsCode(code int) bool {
return code == 204
}
// Code gets the status code for the repo update branch protection priories no content response
func (o *RepoUpdateBranchProtectionPrioriesNoContent) Code() int {
return 204
}
func (o *RepoUpdateBranchProtectionPrioriesNoContent) Error() string {
return fmt.Sprintf("[POST /repos/{owner}/{repo}/branch_protections/priority][%d] repoUpdateBranchProtectionPrioriesNoContent", 204)
}
func (o *RepoUpdateBranchProtectionPrioriesNoContent) String() string {
return fmt.Sprintf("[POST /repos/{owner}/{repo}/branch_protections/priority][%d] repoUpdateBranchProtectionPrioriesNoContent", 204)
}
func (o *RepoUpdateBranchProtectionPrioriesNoContent) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
return nil
}
// NewRepoUpdateBranchProtectionPrioriesNotFound creates a RepoUpdateBranchProtectionPrioriesNotFound with default headers values
func NewRepoUpdateBranchProtectionPrioriesNotFound() *RepoUpdateBranchProtectionPrioriesNotFound {
return &RepoUpdateBranchProtectionPrioriesNotFound{}
}
/*
RepoUpdateBranchProtectionPrioriesNotFound describes a response with status code 404, with default header values.
APINotFound is a not found empty response
*/
type RepoUpdateBranchProtectionPrioriesNotFound struct {
}
// IsSuccess returns true when this repo update branch protection priories not found response has a 2xx status code
func (o *RepoUpdateBranchProtectionPrioriesNotFound) IsSuccess() bool {
return false
}
// IsRedirect returns true when this repo update branch protection priories not found response has a 3xx status code
func (o *RepoUpdateBranchProtectionPrioriesNotFound) IsRedirect() bool {
return false
}
// IsClientError returns true when this repo update branch protection priories not found response has a 4xx status code
func (o *RepoUpdateBranchProtectionPrioriesNotFound) IsClientError() bool {
return true
}
// IsServerError returns true when this repo update branch protection priories not found response has a 5xx status code
func (o *RepoUpdateBranchProtectionPrioriesNotFound) IsServerError() bool {
return false
}
// IsCode returns true when this repo update branch protection priories not found response a status code equal to that given
func (o *RepoUpdateBranchProtectionPrioriesNotFound) IsCode(code int) bool {
return code == 404
}
// Code gets the status code for the repo update branch protection priories not found response
func (o *RepoUpdateBranchProtectionPrioriesNotFound) Code() int {
return 404
}
func (o *RepoUpdateBranchProtectionPrioriesNotFound) Error() string {
return fmt.Sprintf("[POST /repos/{owner}/{repo}/branch_protections/priority][%d] repoUpdateBranchProtectionPrioriesNotFound", 404)
}
func (o *RepoUpdateBranchProtectionPrioriesNotFound) String() string {
return fmt.Sprintf("[POST /repos/{owner}/{repo}/branch_protections/priority][%d] repoUpdateBranchProtectionPrioriesNotFound", 404)
}
func (o *RepoUpdateBranchProtectionPrioriesNotFound) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
return nil
}
// NewRepoUpdateBranchProtectionPrioriesUnprocessableEntity creates a RepoUpdateBranchProtectionPrioriesUnprocessableEntity with default headers values
func NewRepoUpdateBranchProtectionPrioriesUnprocessableEntity() *RepoUpdateBranchProtectionPrioriesUnprocessableEntity {
return &RepoUpdateBranchProtectionPrioriesUnprocessableEntity{}
}
/*
RepoUpdateBranchProtectionPrioriesUnprocessableEntity describes a response with status code 422, with default header values.
APIValidationError is error format response related to input validation
*/
type RepoUpdateBranchProtectionPrioriesUnprocessableEntity struct {
Message string
URL string
}
// IsSuccess returns true when this repo update branch protection priories unprocessable entity response has a 2xx status code
func (o *RepoUpdateBranchProtectionPrioriesUnprocessableEntity) IsSuccess() bool {
return false
}
// IsRedirect returns true when this repo update branch protection priories unprocessable entity response has a 3xx status code
func (o *RepoUpdateBranchProtectionPrioriesUnprocessableEntity) IsRedirect() bool {
return false
}
// IsClientError returns true when this repo update branch protection priories unprocessable entity response has a 4xx status code
func (o *RepoUpdateBranchProtectionPrioriesUnprocessableEntity) IsClientError() bool {
return true
}
// IsServerError returns true when this repo update branch protection priories unprocessable entity response has a 5xx status code
func (o *RepoUpdateBranchProtectionPrioriesUnprocessableEntity) IsServerError() bool {
return false
}
// IsCode returns true when this repo update branch protection priories unprocessable entity response a status code equal to that given
func (o *RepoUpdateBranchProtectionPrioriesUnprocessableEntity) IsCode(code int) bool {
return code == 422
}
// Code gets the status code for the repo update branch protection priories unprocessable entity response
func (o *RepoUpdateBranchProtectionPrioriesUnprocessableEntity) Code() int {
return 422
}
func (o *RepoUpdateBranchProtectionPrioriesUnprocessableEntity) Error() string {
return fmt.Sprintf("[POST /repos/{owner}/{repo}/branch_protections/priority][%d] repoUpdateBranchProtectionPrioriesUnprocessableEntity", 422)
}
func (o *RepoUpdateBranchProtectionPrioriesUnprocessableEntity) String() string {
return fmt.Sprintf("[POST /repos/{owner}/{repo}/branch_protections/priority][%d] repoUpdateBranchProtectionPrioriesUnprocessableEntity", 422)
}
func (o *RepoUpdateBranchProtectionPrioriesUnprocessableEntity) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// hydrates response header message
hdrMessage := response.GetHeader("message")
if hdrMessage != "" {
o.Message = hdrMessage
}
// hydrates response header url
hdrURL := response.GetHeader("url")
if hdrURL != "" {
o.URL = hdrURL
}
return nil
}
// NewRepoUpdateBranchProtectionPrioriesLocked creates a RepoUpdateBranchProtectionPrioriesLocked with default headers values
func NewRepoUpdateBranchProtectionPrioriesLocked() *RepoUpdateBranchProtectionPrioriesLocked {
return &RepoUpdateBranchProtectionPrioriesLocked{}
}
/*
RepoUpdateBranchProtectionPrioriesLocked describes a response with status code 423, with default header values.
APIRepoArchivedError is an error that is raised when an archived repo should be modified
*/
type RepoUpdateBranchProtectionPrioriesLocked struct {
Message string
URL string
}
// IsSuccess returns true when this repo update branch protection priories locked response has a 2xx status code
func (o *RepoUpdateBranchProtectionPrioriesLocked) IsSuccess() bool {
return false
}
// IsRedirect returns true when this repo update branch protection priories locked response has a 3xx status code
func (o *RepoUpdateBranchProtectionPrioriesLocked) IsRedirect() bool {
return false
}
// IsClientError returns true when this repo update branch protection priories locked response has a 4xx status code
func (o *RepoUpdateBranchProtectionPrioriesLocked) IsClientError() bool {
return true
}
// IsServerError returns true when this repo update branch protection priories locked response has a 5xx status code
func (o *RepoUpdateBranchProtectionPrioriesLocked) IsServerError() bool {
return false
}
// IsCode returns true when this repo update branch protection priories locked response a status code equal to that given
func (o *RepoUpdateBranchProtectionPrioriesLocked) IsCode(code int) bool {
return code == 423
}
// Code gets the status code for the repo update branch protection priories locked response
func (o *RepoUpdateBranchProtectionPrioriesLocked) Code() int {
return 423
}
func (o *RepoUpdateBranchProtectionPrioriesLocked) Error() string {
return fmt.Sprintf("[POST /repos/{owner}/{repo}/branch_protections/priority][%d] repoUpdateBranchProtectionPrioriesLocked", 423)
}
func (o *RepoUpdateBranchProtectionPrioriesLocked) String() string {
return fmt.Sprintf("[POST /repos/{owner}/{repo}/branch_protections/priority][%d] repoUpdateBranchProtectionPrioriesLocked", 423)
}
func (o *RepoUpdateBranchProtectionPrioriesLocked) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// hydrates response header message
hdrMessage := response.GetHeader("message")
if hdrMessage != "" {
o.Message = hdrMessage
}
// hydrates response header url
hdrURL := response.GetHeader("url")
if hdrURL != "" {
o.URL = hdrURL
}
return nil
}

View File

@@ -0,0 +1,306 @@
// Code generated by go-swagger; DO NOT EDIT.
package repository
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"fmt"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
)
// RepoUpdateBranchReader is a Reader for the RepoUpdateBranch structure.
type RepoUpdateBranchReader struct {
formats strfmt.Registry
}
// ReadResponse reads a server response into the received o.
func (o *RepoUpdateBranchReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
switch response.Code() {
case 204:
result := NewRepoUpdateBranchNoContent()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return result, nil
case 403:
result := NewRepoUpdateBranchForbidden()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
case 404:
result := NewRepoUpdateBranchNotFound()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
case 422:
result := NewRepoUpdateBranchUnprocessableEntity()
if err := result.readResponse(response, consumer, o.formats); err != nil {
return nil, err
}
return nil, result
default:
return nil, runtime.NewAPIError("[PATCH /repos/{owner}/{repo}/branches/{branch}] repoUpdateBranch", response, response.Code())
}
}
// NewRepoUpdateBranchNoContent creates a RepoUpdateBranchNoContent with default headers values
func NewRepoUpdateBranchNoContent() *RepoUpdateBranchNoContent {
return &RepoUpdateBranchNoContent{}
}
/*
RepoUpdateBranchNoContent describes a response with status code 204, with default header values.
APIEmpty is an empty response
*/
type RepoUpdateBranchNoContent struct {
}
// IsSuccess returns true when this repo update branch no content response has a 2xx status code
func (o *RepoUpdateBranchNoContent) IsSuccess() bool {
return true
}
// IsRedirect returns true when this repo update branch no content response has a 3xx status code
func (o *RepoUpdateBranchNoContent) IsRedirect() bool {
return false
}
// IsClientError returns true when this repo update branch no content response has a 4xx status code
func (o *RepoUpdateBranchNoContent) IsClientError() bool {
return false
}
// IsServerError returns true when this repo update branch no content response has a 5xx status code
func (o *RepoUpdateBranchNoContent) IsServerError() bool {
return false
}
// IsCode returns true when this repo update branch no content response a status code equal to that given
func (o *RepoUpdateBranchNoContent) IsCode(code int) bool {
return code == 204
}
// Code gets the status code for the repo update branch no content response
func (o *RepoUpdateBranchNoContent) Code() int {
return 204
}
func (o *RepoUpdateBranchNoContent) Error() string {
return fmt.Sprintf("[PATCH /repos/{owner}/{repo}/branches/{branch}][%d] repoUpdateBranchNoContent", 204)
}
func (o *RepoUpdateBranchNoContent) String() string {
return fmt.Sprintf("[PATCH /repos/{owner}/{repo}/branches/{branch}][%d] repoUpdateBranchNoContent", 204)
}
func (o *RepoUpdateBranchNoContent) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
return nil
}
// NewRepoUpdateBranchForbidden creates a RepoUpdateBranchForbidden with default headers values
func NewRepoUpdateBranchForbidden() *RepoUpdateBranchForbidden {
return &RepoUpdateBranchForbidden{}
}
/*
RepoUpdateBranchForbidden describes a response with status code 403, with default header values.
APIForbiddenError is a forbidden error response
*/
type RepoUpdateBranchForbidden struct {
Message string
URL string
}
// IsSuccess returns true when this repo update branch forbidden response has a 2xx status code
func (o *RepoUpdateBranchForbidden) IsSuccess() bool {
return false
}
// IsRedirect returns true when this repo update branch forbidden response has a 3xx status code
func (o *RepoUpdateBranchForbidden) IsRedirect() bool {
return false
}
// IsClientError returns true when this repo update branch forbidden response has a 4xx status code
func (o *RepoUpdateBranchForbidden) IsClientError() bool {
return true
}
// IsServerError returns true when this repo update branch forbidden response has a 5xx status code
func (o *RepoUpdateBranchForbidden) IsServerError() bool {
return false
}
// IsCode returns true when this repo update branch forbidden response a status code equal to that given
func (o *RepoUpdateBranchForbidden) IsCode(code int) bool {
return code == 403
}
// Code gets the status code for the repo update branch forbidden response
func (o *RepoUpdateBranchForbidden) Code() int {
return 403
}
func (o *RepoUpdateBranchForbidden) Error() string {
return fmt.Sprintf("[PATCH /repos/{owner}/{repo}/branches/{branch}][%d] repoUpdateBranchForbidden", 403)
}
func (o *RepoUpdateBranchForbidden) String() string {
return fmt.Sprintf("[PATCH /repos/{owner}/{repo}/branches/{branch}][%d] repoUpdateBranchForbidden", 403)
}
func (o *RepoUpdateBranchForbidden) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// hydrates response header message
hdrMessage := response.GetHeader("message")
if hdrMessage != "" {
o.Message = hdrMessage
}
// hydrates response header url
hdrURL := response.GetHeader("url")
if hdrURL != "" {
o.URL = hdrURL
}
return nil
}
// NewRepoUpdateBranchNotFound creates a RepoUpdateBranchNotFound with default headers values
func NewRepoUpdateBranchNotFound() *RepoUpdateBranchNotFound {
return &RepoUpdateBranchNotFound{}
}
/*
RepoUpdateBranchNotFound describes a response with status code 404, with default header values.
APINotFound is a not found empty response
*/
type RepoUpdateBranchNotFound struct {
}
// IsSuccess returns true when this repo update branch not found response has a 2xx status code
func (o *RepoUpdateBranchNotFound) IsSuccess() bool {
return false
}
// IsRedirect returns true when this repo update branch not found response has a 3xx status code
func (o *RepoUpdateBranchNotFound) IsRedirect() bool {
return false
}
// IsClientError returns true when this repo update branch not found response has a 4xx status code
func (o *RepoUpdateBranchNotFound) IsClientError() bool {
return true
}
// IsServerError returns true when this repo update branch not found response has a 5xx status code
func (o *RepoUpdateBranchNotFound) IsServerError() bool {
return false
}
// IsCode returns true when this repo update branch not found response a status code equal to that given
func (o *RepoUpdateBranchNotFound) IsCode(code int) bool {
return code == 404
}
// Code gets the status code for the repo update branch not found response
func (o *RepoUpdateBranchNotFound) Code() int {
return 404
}
func (o *RepoUpdateBranchNotFound) Error() string {
return fmt.Sprintf("[PATCH /repos/{owner}/{repo}/branches/{branch}][%d] repoUpdateBranchNotFound", 404)
}
func (o *RepoUpdateBranchNotFound) String() string {
return fmt.Sprintf("[PATCH /repos/{owner}/{repo}/branches/{branch}][%d] repoUpdateBranchNotFound", 404)
}
func (o *RepoUpdateBranchNotFound) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
return nil
}
// NewRepoUpdateBranchUnprocessableEntity creates a RepoUpdateBranchUnprocessableEntity with default headers values
func NewRepoUpdateBranchUnprocessableEntity() *RepoUpdateBranchUnprocessableEntity {
return &RepoUpdateBranchUnprocessableEntity{}
}
/*
RepoUpdateBranchUnprocessableEntity describes a response with status code 422, with default header values.
APIValidationError is error format response related to input validation
*/
type RepoUpdateBranchUnprocessableEntity struct {
Message string
URL string
}
// IsSuccess returns true when this repo update branch unprocessable entity response has a 2xx status code
func (o *RepoUpdateBranchUnprocessableEntity) IsSuccess() bool {
return false
}
// IsRedirect returns true when this repo update branch unprocessable entity response has a 3xx status code
func (o *RepoUpdateBranchUnprocessableEntity) IsRedirect() bool {
return false
}
// IsClientError returns true when this repo update branch unprocessable entity response has a 4xx status code
func (o *RepoUpdateBranchUnprocessableEntity) IsClientError() bool {
return true
}
// IsServerError returns true when this repo update branch unprocessable entity response has a 5xx status code
func (o *RepoUpdateBranchUnprocessableEntity) IsServerError() bool {
return false
}
// IsCode returns true when this repo update branch unprocessable entity response a status code equal to that given
func (o *RepoUpdateBranchUnprocessableEntity) IsCode(code int) bool {
return code == 422
}
// Code gets the status code for the repo update branch unprocessable entity response
func (o *RepoUpdateBranchUnprocessableEntity) Code() int {
return 422
}
func (o *RepoUpdateBranchUnprocessableEntity) Error() string {
return fmt.Sprintf("[PATCH /repos/{owner}/{repo}/branches/{branch}][%d] repoUpdateBranchUnprocessableEntity", 422)
}
func (o *RepoUpdateBranchUnprocessableEntity) String() string {
return fmt.Sprintf("[PATCH /repos/{owner}/{repo}/branches/{branch}][%d] repoUpdateBranchUnprocessableEntity", 422)
}
func (o *RepoUpdateBranchUnprocessableEntity) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error {
// hydrates response header message
hdrMessage := response.GetHeader("message")
if hdrMessage != "" {
o.Message = hdrMessage
}
// hydrates response header url
hdrURL := response.GetHeader("url")
if hdrURL != "" {
o.URL = hdrURL
}
return nil
}

View File

@@ -127,6 +127,8 @@ type ClientService interface {
GetTree(params *GetTreeParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*GetTreeOK, error)
ListActionTasks(params *ListActionTasksParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*ListActionTasksOK, error)
AcceptRepoTransfer(params *AcceptRepoTransferParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*AcceptRepoTransferAccepted, error)
CreateCurrentUserRepo(params *CreateCurrentUserRepoParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*CreateCurrentUserRepoCreated, error)
@@ -193,6 +195,8 @@ type ClientService interface {
RepoCreateTag(params *RepoCreateTagParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoCreateTagOK, error)
RepoCreateTagProtection(params *RepoCreateTagProtectionParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoCreateTagProtectionCreated, error)
RepoCreateWikiPage(params *RepoCreateWikiPageParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoCreateWikiPageCreated, error)
RepoDelete(params *RepoDeleteParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoDeleteNoContent, error)
@@ -227,6 +231,8 @@ type ClientService interface {
RepoDeleteTag(params *RepoDeleteTagParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoDeleteTagNoContent, error)
RepoDeleteTagProtection(params *RepoDeleteTagProtectionParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoDeleteTagProtectionNoContent, error)
RepoDeleteTeam(params *RepoDeleteTeamParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoDeleteTeamNoContent, error)
RepoDeleteTopic(params *RepoDeleteTopicParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoDeleteTopicNoContent, error)
@@ -253,6 +259,8 @@ type ClientService interface {
RepoEditReleaseAttachment(params *RepoEditReleaseAttachmentParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoEditReleaseAttachmentCreated, error)
RepoEditTagProtection(params *RepoEditTagProtectionParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoEditTagProtectionOK, error)
RepoEditWikiPage(params *RepoEditWikiPageParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoEditWikiPageOK, error)
RepoGet(params *RepoGetParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoGetOK, error)
@@ -293,6 +301,8 @@ type ClientService interface {
RepoGetLatestRelease(params *RepoGetLatestReleaseParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoGetLatestReleaseOK, error)
RepoGetLicenses(params *RepoGetLicensesParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoGetLicensesOK, error)
RepoGetNote(params *RepoGetNoteParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoGetNoteOK, error)
RepoGetPullRequest(params *RepoGetPullRequestParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoGetPullRequestOK, error)
@@ -329,6 +339,8 @@ type ClientService interface {
RepoGetTag(params *RepoGetTagParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoGetTagOK, error)
RepoGetTagProtection(params *RepoGetTagProtectionParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoGetTagProtectionOK, error)
RepoGetWikiPage(params *RepoGetWikiPageParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoGetWikiPageOK, error)
RepoGetWikiPageRevisions(params *RepoGetWikiPageRevisionsParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoGetWikiPageRevisionsOK, error)
@@ -377,6 +389,8 @@ type ClientService interface {
RepoListSubscribers(params *RepoListSubscribersParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoListSubscribersOK, error)
RepoListTagProtection(params *RepoListTagProtectionParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoListTagProtectionOK, error)
RepoListTags(params *RepoListTagsParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoListTagsOK, error)
RepoListTeams(params *RepoListTeamsParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoListTeamsOK, error)
@@ -385,6 +399,8 @@ type ClientService interface {
RepoMergePullRequest(params *RepoMergePullRequestParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoMergePullRequestOK, error)
RepoMergeUpstream(params *RepoMergeUpstreamParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoMergeUpstreamOK, error)
RepoMigrate(params *RepoMigrateParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoMigrateCreated, error)
RepoMirrorSync(params *RepoMirrorSyncParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoMirrorSyncOK, error)
@@ -411,6 +427,10 @@ type ClientService interface {
RepoUpdateAvatar(params *RepoUpdateAvatarParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoUpdateAvatarNoContent, error)
RepoUpdateBranch(params *RepoUpdateBranchParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoUpdateBranchNoContent, error)
RepoUpdateBranchProtectionPriories(params *RepoUpdateBranchProtectionPrioriesParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoUpdateBranchProtectionPrioriesNoContent, error)
RepoUpdateFile(params *RepoUpdateFileParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoUpdateFileOK, error)
RepoUpdatePullRequest(params *RepoUpdatePullRequestParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoUpdatePullRequestOK, error)
@@ -553,6 +573,45 @@ func (a *Client) GetTree(params *GetTreeParams, authInfo runtime.ClientAuthInfoW
panic(msg)
}
/*
ListActionTasks lists a repository s action tasks
*/
func (a *Client) ListActionTasks(params *ListActionTasksParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*ListActionTasksOK, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewListActionTasksParams()
}
op := &runtime.ClientOperation{
ID: "ListActionTasks",
Method: "GET",
PathPattern: "/repos/{owner}/{repo}/actions/tasks",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json", "text/plain"},
Schemes: []string{"http", "https"},
Params: params,
Reader: &ListActionTasksReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
result, err := a.transport.Submit(op)
if err != nil {
return nil, err
}
success, ok := result.(*ListActionTasksOK)
if ok {
return success, nil
}
// unexpected success response
// safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue
msg := fmt.Sprintf("unexpected success response for ListActionTasks: API contract not enforced by server. Client expected to get an error, but got: %T", result)
panic(msg)
}
/*
AcceptRepoTransfer accepts a repo transfer
*/
@@ -987,7 +1046,7 @@ func (a *Client) RejectRepoTransfer(params *RejectRepoTransferParams, authInfo r
}
/*
RepoAddCollaborator adds a collaborator to a repository
RepoAddCollaborator adds or update a collaborator to a repository
*/
func (a *Client) RepoAddCollaborator(params *RepoAddCollaboratorParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoAddCollaboratorNoContent, error) {
// TODO: Validate the params before sending
@@ -1844,6 +1903,45 @@ func (a *Client) RepoCreateTag(params *RepoCreateTagParams, authInfo runtime.Cli
panic(msg)
}
/*
RepoCreateTagProtection creates a tag protections for a repository
*/
func (a *Client) RepoCreateTagProtection(params *RepoCreateTagProtectionParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoCreateTagProtectionCreated, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewRepoCreateTagProtectionParams()
}
op := &runtime.ClientOperation{
ID: "repoCreateTagProtection",
Method: "POST",
PathPattern: "/repos/{owner}/{repo}/tag_protections",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http", "https"},
Params: params,
Reader: &RepoCreateTagProtectionReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
result, err := a.transport.Submit(op)
if err != nil {
return nil, err
}
success, ok := result.(*RepoCreateTagProtectionCreated)
if ok {
return success, nil
}
// unexpected success response
// safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue
msg := fmt.Sprintf("unexpected success response for repoCreateTagProtection: API contract not enforced by server. Client expected to get an error, but got: %T", result)
panic(msg)
}
/*
RepoCreateWikiPage creates a wiki page
*/
@@ -2507,6 +2605,45 @@ func (a *Client) RepoDeleteTag(params *RepoDeleteTagParams, authInfo runtime.Cli
panic(msg)
}
/*
RepoDeleteTagProtection deletes a specific tag protection for the repository
*/
func (a *Client) RepoDeleteTagProtection(params *RepoDeleteTagProtectionParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoDeleteTagProtectionNoContent, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewRepoDeleteTagProtectionParams()
}
op := &runtime.ClientOperation{
ID: "repoDeleteTagProtection",
Method: "DELETE",
PathPattern: "/repos/{owner}/{repo}/tag_protections/{id}",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json", "text/plain"},
Schemes: []string{"http", "https"},
Params: params,
Reader: &RepoDeleteTagProtectionReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
result, err := a.transport.Submit(op)
if err != nil {
return nil, err
}
success, ok := result.(*RepoDeleteTagProtectionNoContent)
if ok {
return success, nil
}
// unexpected success response
// safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue
msg := fmt.Sprintf("unexpected success response for repoDeleteTagProtection: API contract not enforced by server. Client expected to get an error, but got: %T", result)
panic(msg)
}
/*
RepoDeleteTeam deletes a team from a repository
*/
@@ -3014,6 +3151,45 @@ func (a *Client) RepoEditReleaseAttachment(params *RepoEditReleaseAttachmentPara
panic(msg)
}
/*
RepoEditTagProtection edits a tag protections for a repository only fields that are set will be changed
*/
func (a *Client) RepoEditTagProtection(params *RepoEditTagProtectionParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoEditTagProtectionOK, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewRepoEditTagProtectionParams()
}
op := &runtime.ClientOperation{
ID: "repoEditTagProtection",
Method: "PATCH",
PathPattern: "/repos/{owner}/{repo}/tag_protections/{id}",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http", "https"},
Params: params,
Reader: &RepoEditTagProtectionReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
result, err := a.transport.Submit(op)
if err != nil {
return nil, err
}
success, ok := result.(*RepoEditTagProtectionOK)
if ok {
return success, nil
}
// unexpected success response
// safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue
msg := fmt.Sprintf("unexpected success response for repoEditTagProtection: API contract not enforced by server. Client expected to get an error, but got: %T", result)
panic(msg)
}
/*
RepoEditWikiPage edits a wiki page
*/
@@ -3366,7 +3542,7 @@ func (a *Client) RepoGetCombinedStatusByRef(params *RepoGetCombinedStatusByRefPa
}
/*
RepoGetCommitPullRequest gets the pull request of the commit
RepoGetCommitPullRequest gets the merged pull request of the commit
*/
func (a *Client) RepoGetCommitPullRequest(params *RepoGetCommitPullRequestParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoGetCommitPullRequestOK, error) {
// TODO: Validate the params before sending
@@ -3794,6 +3970,45 @@ func (a *Client) RepoGetLatestRelease(params *RepoGetLatestReleaseParams, authIn
panic(msg)
}
/*
RepoGetLicenses gets repo licenses
*/
func (a *Client) RepoGetLicenses(params *RepoGetLicensesParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoGetLicensesOK, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewRepoGetLicensesParams()
}
op := &runtime.ClientOperation{
ID: "repoGetLicenses",
Method: "GET",
PathPattern: "/repos/{owner}/{repo}/licenses",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json", "text/plain"},
Schemes: []string{"http", "https"},
Params: params,
Reader: &RepoGetLicensesReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
result, err := a.transport.Submit(op)
if err != nil {
return nil, err
}
success, ok := result.(*RepoGetLicensesOK)
if ok {
return success, nil
}
// unexpected success response
// safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue
msg := fmt.Sprintf("unexpected success response for repoGetLicenses: API contract not enforced by server. Client expected to get an error, but got: %T", result)
panic(msg)
}
/*
RepoGetNote gets a note corresponding to a single commit from a repository
*/
@@ -4119,7 +4334,7 @@ func (a *Client) RepoGetRawFile(params *RepoGetRawFileParams, authInfo runtime.C
Method: "GET",
PathPattern: "/repos/{owner}/{repo}/raw/{filepath}",
ProducesMediaTypes: []string{"application/octet-stream"},
ConsumesMediaTypes: []string{"application/octet-stream"},
ConsumesMediaTypes: []string{"application/json", "text/plain"},
Schemes: []string{"http", "https"},
Params: params,
Reader: &RepoGetRawFileReader{formats: a.formats, writer: writer},
@@ -4390,7 +4605,7 @@ func (a *Client) RepoGetRunnerRegistrationToken(params *RepoGetRunnerRegistratio
op := &runtime.ClientOperation{
ID: "repoGetRunnerRegistrationToken",
Method: "GET",
PathPattern: "/repos/{owner}/{repo}/runners/registration-token",
PathPattern: "/repos/{owner}/{repo}/actions/runners/registration-token",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json", "text/plain"},
Schemes: []string{"http", "https"},
@@ -4496,6 +4711,45 @@ func (a *Client) RepoGetTag(params *RepoGetTagParams, authInfo runtime.ClientAut
panic(msg)
}
/*
RepoGetTagProtection gets a specific tag protection for the repository
*/
func (a *Client) RepoGetTagProtection(params *RepoGetTagProtectionParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoGetTagProtectionOK, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewRepoGetTagProtectionParams()
}
op := &runtime.ClientOperation{
ID: "repoGetTagProtection",
Method: "GET",
PathPattern: "/repos/{owner}/{repo}/tag_protections/{id}",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json", "text/plain"},
Schemes: []string{"http", "https"},
Params: params,
Reader: &RepoGetTagProtectionReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
result, err := a.transport.Submit(op)
if err != nil {
return nil, err
}
success, ok := result.(*RepoGetTagProtectionOK)
if ok {
return success, nil
}
// unexpected success response
// safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue
msg := fmt.Sprintf("unexpected success response for repoGetTagProtection: API contract not enforced by server. Client expected to get an error, but got: %T", result)
panic(msg)
}
/*
RepoGetWikiPage gets a wiki page
*/
@@ -5432,6 +5686,45 @@ func (a *Client) RepoListSubscribers(params *RepoListSubscribersParams, authInfo
panic(msg)
}
/*
RepoListTagProtection lists tag protections for a repository
*/
func (a *Client) RepoListTagProtection(params *RepoListTagProtectionParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoListTagProtectionOK, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewRepoListTagProtectionParams()
}
op := &runtime.ClientOperation{
ID: "repoListTagProtection",
Method: "GET",
PathPattern: "/repos/{owner}/{repo}/tag_protections",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json", "text/plain"},
Schemes: []string{"http", "https"},
Params: params,
Reader: &RepoListTagProtectionReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
result, err := a.transport.Submit(op)
if err != nil {
return nil, err
}
success, ok := result.(*RepoListTagProtectionOK)
if ok {
return success, nil
}
// unexpected success response
// safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue
msg := fmt.Sprintf("unexpected success response for repoListTagProtection: API contract not enforced by server. Client expected to get an error, but got: %T", result)
panic(msg)
}
/*
RepoListTags lists a repository s tags
*/
@@ -5588,6 +5881,45 @@ func (a *Client) RepoMergePullRequest(params *RepoMergePullRequestParams, authIn
panic(msg)
}
/*
RepoMergeUpstream merges a branch from upstream
*/
func (a *Client) RepoMergeUpstream(params *RepoMergeUpstreamParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoMergeUpstreamOK, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewRepoMergeUpstreamParams()
}
op := &runtime.ClientOperation{
ID: "repoMergeUpstream",
Method: "POST",
PathPattern: "/repos/{owner}/{repo}/merge-upstream",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json", "text/plain"},
Schemes: []string{"http", "https"},
Params: params,
Reader: &RepoMergeUpstreamReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
result, err := a.transport.Submit(op)
if err != nil {
return nil, err
}
success, ok := result.(*RepoMergeUpstreamOK)
if ok {
return success, nil
}
// unexpected success response
// safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue
msg := fmt.Sprintf("unexpected success response for repoMergeUpstream: API contract not enforced by server. Client expected to get an error, but got: %T", result)
panic(msg)
}
/*
RepoMigrate migrates a remote git repository
*/
@@ -6095,6 +6427,84 @@ func (a *Client) RepoUpdateAvatar(params *RepoUpdateAvatarParams, authInfo runti
panic(msg)
}
/*
RepoUpdateBranch updates a branch
*/
func (a *Client) RepoUpdateBranch(params *RepoUpdateBranchParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoUpdateBranchNoContent, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewRepoUpdateBranchParams()
}
op := &runtime.ClientOperation{
ID: "repoUpdateBranch",
Method: "PATCH",
PathPattern: "/repos/{owner}/{repo}/branches/{branch}",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http", "https"},
Params: params,
Reader: &RepoUpdateBranchReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
result, err := a.transport.Submit(op)
if err != nil {
return nil, err
}
success, ok := result.(*RepoUpdateBranchNoContent)
if ok {
return success, nil
}
// unexpected success response
// safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue
msg := fmt.Sprintf("unexpected success response for repoUpdateBranch: API contract not enforced by server. Client expected to get an error, but got: %T", result)
panic(msg)
}
/*
RepoUpdateBranchProtectionPriories updates the priorities of branch protections for a repository
*/
func (a *Client) RepoUpdateBranchProtectionPriories(params *RepoUpdateBranchProtectionPrioriesParams, authInfo runtime.ClientAuthInfoWriter, opts ...ClientOption) (*RepoUpdateBranchProtectionPrioriesNoContent, error) {
// TODO: Validate the params before sending
if params == nil {
params = NewRepoUpdateBranchProtectionPrioriesParams()
}
op := &runtime.ClientOperation{
ID: "repoUpdateBranchProtectionPriories",
Method: "POST",
PathPattern: "/repos/{owner}/{repo}/branch_protections/priority",
ProducesMediaTypes: []string{"application/json"},
ConsumesMediaTypes: []string{"application/json"},
Schemes: []string{"http", "https"},
Params: params,
Reader: &RepoUpdateBranchProtectionPrioriesReader{formats: a.formats},
AuthInfo: authInfo,
Context: params.Context,
Client: params.HTTPClient,
}
for _, opt := range opts {
opt(op)
}
result, err := a.transport.Submit(op)
if err != nil {
return nil, err
}
success, ok := result.(*RepoUpdateBranchProtectionPrioriesNoContent)
if ok {
return success, nil
}
// unexpected success response
// safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue
msg := fmt.Sprintf("unexpected success response for repoUpdateBranchProtectionPriories: API contract not enforced by server. Client expected to get an error, but got: %T", result)
panic(msg)
}
/*
RepoUpdateFile updates a file in a repository
*/

View File

@@ -0,0 +1,144 @@
// Code generated by go-swagger; DO NOT EDIT.
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// ActionTask ActionTask represents a ActionTask
//
// swagger:model ActionTask
type ActionTask struct {
// created at
// Format: date-time
CreatedAt strfmt.DateTime `json:"created_at,omitempty"`
// display title
DisplayTitle string `json:"display_title,omitempty"`
// event
Event string `json:"event,omitempty"`
// head branch
HeadBranch string `json:"head_branch,omitempty"`
// head s h a
HeadSHA string `json:"head_sha,omitempty"`
// ID
ID int64 `json:"id,omitempty"`
// name
Name string `json:"name,omitempty"`
// run number
RunNumber int64 `json:"run_number,omitempty"`
// run started at
// Format: date-time
RunStartedAt strfmt.DateTime `json:"run_started_at,omitempty"`
// status
Status string `json:"status,omitempty"`
// URL
URL string `json:"url,omitempty"`
// updated at
// Format: date-time
UpdatedAt strfmt.DateTime `json:"updated_at,omitempty"`
// workflow ID
WorkflowID string `json:"workflow_id,omitempty"`
}
// Validate validates this action task
func (m *ActionTask) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateCreatedAt(formats); err != nil {
res = append(res, err)
}
if err := m.validateRunStartedAt(formats); err != nil {
res = append(res, err)
}
if err := m.validateUpdatedAt(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *ActionTask) validateCreatedAt(formats strfmt.Registry) error {
if swag.IsZero(m.CreatedAt) { // not required
return nil
}
if err := validate.FormatOf("created_at", "body", "date-time", m.CreatedAt.String(), formats); err != nil {
return err
}
return nil
}
func (m *ActionTask) validateRunStartedAt(formats strfmt.Registry) error {
if swag.IsZero(m.RunStartedAt) { // not required
return nil
}
if err := validate.FormatOf("run_started_at", "body", "date-time", m.RunStartedAt.String(), formats); err != nil {
return err
}
return nil
}
func (m *ActionTask) validateUpdatedAt(formats strfmt.Registry) error {
if swag.IsZero(m.UpdatedAt) { // not required
return nil
}
if err := validate.FormatOf("updated_at", "body", "date-time", m.UpdatedAt.String(), formats); err != nil {
return err
}
return nil
}
// ContextValidate validates this action task based on context it is used
func (m *ActionTask) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *ActionTask) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *ActionTask) UnmarshalBinary(b []byte) error {
var res ActionTask
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -0,0 +1,124 @@
// Code generated by go-swagger; DO NOT EDIT.
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"strconv"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// ActionTaskResponse ActionTaskResponse returns a ActionTask
//
// swagger:model ActionTaskResponse
type ActionTaskResponse struct {
// entries
Entries []*ActionTask `json:"workflow_runs"`
// total count
TotalCount int64 `json:"total_count,omitempty"`
}
// Validate validates this action task response
func (m *ActionTaskResponse) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateEntries(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *ActionTaskResponse) validateEntries(formats strfmt.Registry) error {
if swag.IsZero(m.Entries) { // not required
return nil
}
for i := 0; i < len(m.Entries); i++ {
if swag.IsZero(m.Entries[i]) { // not required
continue
}
if m.Entries[i] != nil {
if err := m.Entries[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("workflow_runs" + "." + strconv.Itoa(i))
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("workflow_runs" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
// ContextValidate validate this action task response based on the context it is used
func (m *ActionTaskResponse) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
var res []error
if err := m.contextValidateEntries(ctx, formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *ActionTaskResponse) contextValidateEntries(ctx context.Context, formats strfmt.Registry) error {
for i := 0; i < len(m.Entries); i++ {
if m.Entries[i] != nil {
if swag.IsZero(m.Entries[i]) { // not required
return nil
}
if err := m.Entries[i].ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("workflow_runs" + "." + strconv.Itoa(i))
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("workflow_runs" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
// MarshalBinary interface implementation
func (m *ActionTaskResponse) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *ActionTaskResponse) UnmarshalBinary(b []byte) error {
var res ActionTaskResponse
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -7,6 +7,7 @@ package models
import (
"context"
"encoding/json"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
@@ -38,7 +39,8 @@ type Activity struct {
// is private
IsPrivate bool `json:"is_private,omitempty"`
// op type
// the type of action
// Enum: ["create_repo","rename_repo","star_repo","watch_repo","commit_repo","create_issue","create_pull_request","transfer_repo","push_tag","comment_issue","merge_pull_request","close_issue","reopen_issue","close_pull_request","reopen_pull_request","delete_tag","delete_branch","mirror_sync_push","mirror_sync_create","mirror_sync_delete","approve_pull_request","reject_pull_request","comment_pull","publish_release","pull_review_dismissed","pull_request_ready_for_review","auto_merge_pull_request"]
OpType string `json:"op_type,omitempty"`
// ref name
@@ -68,6 +70,10 @@ func (m *Activity) Validate(formats strfmt.Registry) error {
res = append(res, err)
}
if err := m.validateOpType(formats); err != nil {
res = append(res, err)
}
if err := m.validateActUser(formats); err != nil {
res = append(res, err)
}
@@ -98,6 +104,123 @@ func (m *Activity) validateCreated(formats strfmt.Registry) error {
return nil
}
var activityTypeOpTypePropEnum []interface{}
func init() {
var res []string
if err := json.Unmarshal([]byte(`["create_repo","rename_repo","star_repo","watch_repo","commit_repo","create_issue","create_pull_request","transfer_repo","push_tag","comment_issue","merge_pull_request","close_issue","reopen_issue","close_pull_request","reopen_pull_request","delete_tag","delete_branch","mirror_sync_push","mirror_sync_create","mirror_sync_delete","approve_pull_request","reject_pull_request","comment_pull","publish_release","pull_review_dismissed","pull_request_ready_for_review","auto_merge_pull_request"]`), &res); err != nil {
panic(err)
}
for _, v := range res {
activityTypeOpTypePropEnum = append(activityTypeOpTypePropEnum, v)
}
}
const (
// ActivityOpTypeCreateRepo captures enum value "create_repo"
ActivityOpTypeCreateRepo string = "create_repo"
// ActivityOpTypeRenameRepo captures enum value "rename_repo"
ActivityOpTypeRenameRepo string = "rename_repo"
// ActivityOpTypeStarRepo captures enum value "star_repo"
ActivityOpTypeStarRepo string = "star_repo"
// ActivityOpTypeWatchRepo captures enum value "watch_repo"
ActivityOpTypeWatchRepo string = "watch_repo"
// ActivityOpTypeCommitRepo captures enum value "commit_repo"
ActivityOpTypeCommitRepo string = "commit_repo"
// ActivityOpTypeCreateIssue captures enum value "create_issue"
ActivityOpTypeCreateIssue string = "create_issue"
// ActivityOpTypeCreatePullRequest captures enum value "create_pull_request"
ActivityOpTypeCreatePullRequest string = "create_pull_request"
// ActivityOpTypeTransferRepo captures enum value "transfer_repo"
ActivityOpTypeTransferRepo string = "transfer_repo"
// ActivityOpTypePushTag captures enum value "push_tag"
ActivityOpTypePushTag string = "push_tag"
// ActivityOpTypeCommentIssue captures enum value "comment_issue"
ActivityOpTypeCommentIssue string = "comment_issue"
// ActivityOpTypeMergePullRequest captures enum value "merge_pull_request"
ActivityOpTypeMergePullRequest string = "merge_pull_request"
// ActivityOpTypeCloseIssue captures enum value "close_issue"
ActivityOpTypeCloseIssue string = "close_issue"
// ActivityOpTypeReopenIssue captures enum value "reopen_issue"
ActivityOpTypeReopenIssue string = "reopen_issue"
// ActivityOpTypeClosePullRequest captures enum value "close_pull_request"
ActivityOpTypeClosePullRequest string = "close_pull_request"
// ActivityOpTypeReopenPullRequest captures enum value "reopen_pull_request"
ActivityOpTypeReopenPullRequest string = "reopen_pull_request"
// ActivityOpTypeDeleteTag captures enum value "delete_tag"
ActivityOpTypeDeleteTag string = "delete_tag"
// ActivityOpTypeDeleteBranch captures enum value "delete_branch"
ActivityOpTypeDeleteBranch string = "delete_branch"
// ActivityOpTypeMirrorSyncPush captures enum value "mirror_sync_push"
ActivityOpTypeMirrorSyncPush string = "mirror_sync_push"
// ActivityOpTypeMirrorSyncCreate captures enum value "mirror_sync_create"
ActivityOpTypeMirrorSyncCreate string = "mirror_sync_create"
// ActivityOpTypeMirrorSyncDelete captures enum value "mirror_sync_delete"
ActivityOpTypeMirrorSyncDelete string = "mirror_sync_delete"
// ActivityOpTypeApprovePullRequest captures enum value "approve_pull_request"
ActivityOpTypeApprovePullRequest string = "approve_pull_request"
// ActivityOpTypeRejectPullRequest captures enum value "reject_pull_request"
ActivityOpTypeRejectPullRequest string = "reject_pull_request"
// ActivityOpTypeCommentPull captures enum value "comment_pull"
ActivityOpTypeCommentPull string = "comment_pull"
// ActivityOpTypePublishRelease captures enum value "publish_release"
ActivityOpTypePublishRelease string = "publish_release"
// ActivityOpTypePullReviewDismissed captures enum value "pull_review_dismissed"
ActivityOpTypePullReviewDismissed string = "pull_review_dismissed"
// ActivityOpTypePullRequestReadyForReview captures enum value "pull_request_ready_for_review"
ActivityOpTypePullRequestReadyForReview string = "pull_request_ready_for_review"
// ActivityOpTypeAutoMergePullRequest captures enum value "auto_merge_pull_request"
ActivityOpTypeAutoMergePullRequest string = "auto_merge_pull_request"
)
// prop value enum
func (m *Activity) validateOpTypeEnum(path, location string, value string) error {
if err := validate.EnumCase(path, location, value, activityTypeOpTypePropEnum, true); err != nil {
return err
}
return nil
}
func (m *Activity) validateOpType(formats strfmt.Registry) error {
if swag.IsZero(m.OpType) { // not required
return nil
}
// value enum
if err := m.validateOpTypeEnum("op_type", "body", m.OpType); err != nil {
return err
}
return nil
}
func (m *Activity) validateActUser(formats strfmt.Registry) error {
if swag.IsZero(m.ActUser) { // not required
return nil

View File

@@ -7,9 +7,12 @@ package models
import (
"context"
"encoding/json"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// AddCollaboratorOption AddCollaboratorOption options when adding a user as a collaborator of a repository
@@ -18,11 +21,66 @@ import (
type AddCollaboratorOption struct {
// permission
// Enum: ["read","write","admin"]
Permission string `json:"permission,omitempty"`
}
// Validate validates this add collaborator option
func (m *AddCollaboratorOption) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validatePermission(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
var addCollaboratorOptionTypePermissionPropEnum []interface{}
func init() {
var res []string
if err := json.Unmarshal([]byte(`["read","write","admin"]`), &res); err != nil {
panic(err)
}
for _, v := range res {
addCollaboratorOptionTypePermissionPropEnum = append(addCollaboratorOptionTypePermissionPropEnum, v)
}
}
const (
// AddCollaboratorOptionPermissionRead captures enum value "read"
AddCollaboratorOptionPermissionRead string = "read"
// AddCollaboratorOptionPermissionWrite captures enum value "write"
AddCollaboratorOptionPermissionWrite string = "write"
// AddCollaboratorOptionPermissionAdmin captures enum value "admin"
AddCollaboratorOptionPermissionAdmin string = "admin"
)
// prop value enum
func (m *AddCollaboratorOption) validatePermissionEnum(path, location string, value string) error {
if err := validate.EnumCase(path, location, value, addCollaboratorOptionTypePermissionPropEnum, true); err != nil {
return err
}
return nil
}
func (m *AddCollaboratorOption) validatePermission(formats strfmt.Registry) error {
if swag.IsZero(m.Permission) { // not required
return nil
}
// value enum
if err := m.validatePermissionEnum("permission", "body", m.Permission); err != nil {
return err
}
return nil
}

View File

@@ -25,6 +25,9 @@ type BranchProtection struct {
// approvals whitelist usernames
ApprovalsWhitelistUsernames []string `json:"approvals_whitelist_username"`
// block admin merge override
BlockAdminMergeOverride bool `json:"block_admin_merge_override,omitempty"`
// block on official review requests
BlockOnOfficialReviewRequests bool `json:"block_on_official_review_requests,omitempty"`
@@ -47,6 +50,12 @@ type BranchProtection struct {
// enable approvals whitelist
EnableApprovalsWhitelist bool `json:"enable_approvals_whitelist,omitempty"`
// enable force push
EnableForcePush bool `json:"enable_force_push,omitempty"`
// enable force push allowlist
EnableForcePushAllowlist bool `json:"enable_force_push_allowlist,omitempty"`
// enable merge whitelist
EnableMergeWhitelist bool `json:"enable_merge_whitelist,omitempty"`
@@ -59,6 +68,15 @@ type BranchProtection struct {
// enable status check
EnableStatusCheck bool `json:"enable_status_check,omitempty"`
// force push allowlist deploy keys
ForcePushAllowlistDeployKeys bool `json:"force_push_allowlist_deploy_keys,omitempty"`
// force push allowlist teams
ForcePushAllowlistTeams []string `json:"force_push_allowlist_teams"`
// force push allowlist usernames
ForcePushAllowlistUsernames []string `json:"force_push_allowlist_usernames"`
// ignore stale approvals
IgnoreStaleApprovals bool `json:"ignore_stale_approvals,omitempty"`
@@ -68,6 +86,9 @@ type BranchProtection struct {
// merge whitelist usernames
MergeWhitelistUsernames []string `json:"merge_whitelist_usernames"`
// priority
Priority int64 `json:"priority,omitempty"`
// protected file patterns
ProtectedFilePatterns string `json:"protected_file_patterns,omitempty"`

View File

@@ -24,6 +24,7 @@ type CreateAccessTokenOption struct {
Name *string `json:"name"`
// scopes
// Example: ["all","read:activitypub","read:issue","write:misc","read:notification","read:organization","read:package","read:repository","read:user"]
Scopes []string `json:"scopes"`
}

View File

@@ -23,6 +23,9 @@ type CreateBranchProtectionOption struct {
// approvals whitelist usernames
ApprovalsWhitelistUsernames []string `json:"approvals_whitelist_username"`
// block admin merge override
BlockAdminMergeOverride bool `json:"block_admin_merge_override,omitempty"`
// block on official review requests
BlockOnOfficialReviewRequests bool `json:"block_on_official_review_requests,omitempty"`
@@ -41,6 +44,12 @@ type CreateBranchProtectionOption struct {
// enable approvals whitelist
EnableApprovalsWhitelist bool `json:"enable_approvals_whitelist,omitempty"`
// enable force push
EnableForcePush bool `json:"enable_force_push,omitempty"`
// enable force push allowlist
EnableForcePushAllowlist bool `json:"enable_force_push_allowlist,omitempty"`
// enable merge whitelist
EnableMergeWhitelist bool `json:"enable_merge_whitelist,omitempty"`
@@ -53,6 +62,15 @@ type CreateBranchProtectionOption struct {
// enable status check
EnableStatusCheck bool `json:"enable_status_check,omitempty"`
// force push allowlist deploy keys
ForcePushAllowlistDeployKeys bool `json:"force_push_allowlist_deploy_keys,omitempty"`
// force push allowlist teams
ForcePushAllowlistTeams []string `json:"force_push_allowlist_teams"`
// force push allowlist usernames
ForcePushAllowlistUsernames []string `json:"force_push_allowlist_usernames"`
// ignore stale approvals
IgnoreStaleApprovals bool `json:"ignore_stale_approvals,omitempty"`
@@ -62,6 +80,9 @@ type CreateBranchProtectionOption struct {
// merge whitelist usernames
MergeWhitelistUsernames []string `json:"merge_whitelist_usernames"`
// priority
Priority int64 `json:"priority,omitempty"`
// protected file patterns
ProtectedFilePatterns string `json:"protected_file_patterns,omitempty"`

View File

@@ -25,6 +25,9 @@ type CreateOAuth2ApplicationOptions struct {
// redirect u r is
RedirectURIs []string `json:"redirect_uris"`
// skip secondary authorization
SkipSecondaryAuthorization bool `json:"skip_secondary_authorization,omitempty"`
}
// Validate validates this create o auth2 application options

View File

@@ -44,6 +44,12 @@ type CreatePullRequestOption struct {
// milestone
Milestone int64 `json:"milestone,omitempty"`
// reviewers
Reviewers []string `json:"reviewers"`
// team reviewers
TeamReviewers []string `json:"team_reviewers"`
// title
Title string `json:"title,omitempty"`
}

View File

@@ -0,0 +1,56 @@
// Code generated by go-swagger; DO NOT EDIT.
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// CreateTagProtectionOption CreateTagProtectionOption options for creating a tag protection
//
// swagger:model CreateTagProtectionOption
type CreateTagProtectionOption struct {
// name pattern
NamePattern string `json:"name_pattern,omitempty"`
// whitelist teams
WhitelistTeams []string `json:"whitelist_teams"`
// whitelist usernames
WhitelistUsernames []string `json:"whitelist_usernames"`
}
// Validate validates this create tag protection option
func (m *CreateTagProtectionOption) Validate(formats strfmt.Registry) error {
return nil
}
// ContextValidate validates this create tag protection option based on context it is used
func (m *CreateTagProtectionOption) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *CreateTagProtectionOption) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *CreateTagProtectionOption) UnmarshalBinary(b []byte) error {
var res CreateTagProtectionOption
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -23,6 +23,9 @@ type EditBranchProtectionOption struct {
// approvals whitelist usernames
ApprovalsWhitelistUsernames []string `json:"approvals_whitelist_username"`
// block admin merge override
BlockAdminMergeOverride bool `json:"block_admin_merge_override,omitempty"`
// block on official review requests
BlockOnOfficialReviewRequests bool `json:"block_on_official_review_requests,omitempty"`
@@ -38,6 +41,12 @@ type EditBranchProtectionOption struct {
// enable approvals whitelist
EnableApprovalsWhitelist bool `json:"enable_approvals_whitelist,omitempty"`
// enable force push
EnableForcePush bool `json:"enable_force_push,omitempty"`
// enable force push allowlist
EnableForcePushAllowlist bool `json:"enable_force_push_allowlist,omitempty"`
// enable merge whitelist
EnableMergeWhitelist bool `json:"enable_merge_whitelist,omitempty"`
@@ -50,6 +59,15 @@ type EditBranchProtectionOption struct {
// enable status check
EnableStatusCheck bool `json:"enable_status_check,omitempty"`
// force push allowlist deploy keys
ForcePushAllowlistDeployKeys bool `json:"force_push_allowlist_deploy_keys,omitempty"`
// force push allowlist teams
ForcePushAllowlistTeams []string `json:"force_push_allowlist_teams"`
// force push allowlist usernames
ForcePushAllowlistUsernames []string `json:"force_push_allowlist_usernames"`
// ignore stale approvals
IgnoreStaleApprovals bool `json:"ignore_stale_approvals,omitempty"`
@@ -59,6 +77,9 @@ type EditBranchProtectionOption struct {
// merge whitelist usernames
MergeWhitelistUsernames []string `json:"merge_whitelist_usernames"`
// priority
Priority int64 `json:"priority,omitempty"`
// protected file patterns
ProtectedFilePatterns string `json:"protected_file_patterns,omitempty"`

View File

@@ -0,0 +1,56 @@
// Code generated by go-swagger; DO NOT EDIT.
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// EditTagProtectionOption EditTagProtectionOption options for editing a tag protection
//
// swagger:model EditTagProtectionOption
type EditTagProtectionOption struct {
// name pattern
NamePattern string `json:"name_pattern,omitempty"`
// whitelist teams
WhitelistTeams []string `json:"whitelist_teams"`
// whitelist usernames
WhitelistUsernames []string `json:"whitelist_usernames"`
}
// Validate validates this edit tag protection option
func (m *EditTagProtectionOption) Validate(formats strfmt.Registry) error {
return nil
}
// ContextValidate validates this edit tag protection option based on context it is used
func (m *EditTagProtectionOption) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *EditTagProtectionOption) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *EditTagProtectionOption) UnmarshalBinary(b []byte) error {
var res EditTagProtectionOption
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -40,8 +40,11 @@ type IssueTemplate struct {
// title
Title string `json:"title,omitempty"`
// assignees
Assignees IssueTemplateStringSlice `json:"assignees,omitempty"`
// labels
Labels IssueTemplateLabels `json:"labels,omitempty"`
Labels IssueTemplateStringSlice `json:"labels,omitempty"`
}
// Validate validates this issue template
@@ -52,6 +55,10 @@ func (m *IssueTemplate) Validate(formats strfmt.Registry) error {
res = append(res, err)
}
if err := m.validateAssignees(formats); err != nil {
res = append(res, err)
}
if err := m.validateLabels(formats); err != nil {
res = append(res, err)
}
@@ -88,6 +95,23 @@ func (m *IssueTemplate) validateFields(formats strfmt.Registry) error {
return nil
}
func (m *IssueTemplate) validateAssignees(formats strfmt.Registry) error {
if swag.IsZero(m.Assignees) { // not required
return nil
}
if err := m.Assignees.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("assignees")
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("assignees")
}
return err
}
return nil
}
func (m *IssueTemplate) validateLabels(formats strfmt.Registry) error {
if swag.IsZero(m.Labels) { // not required
return nil
@@ -113,6 +137,10 @@ func (m *IssueTemplate) ContextValidate(ctx context.Context, formats strfmt.Regi
res = append(res, err)
}
if err := m.contextValidateAssignees(ctx, formats); err != nil {
res = append(res, err)
}
if err := m.contextValidateLabels(ctx, formats); err != nil {
res = append(res, err)
}
@@ -148,6 +176,20 @@ func (m *IssueTemplate) contextValidateFields(ctx context.Context, formats strfm
return nil
}
func (m *IssueTemplate) contextValidateAssignees(ctx context.Context, formats strfmt.Registry) error {
if err := m.Assignees.ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("assignees")
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("assignees")
}
return err
}
return nil
}
func (m *IssueTemplate) contextValidateLabels(ctx context.Context, formats strfmt.Registry) error {
if err := m.Labels.ContextValidate(ctx, formats); err != nil {

View File

@@ -0,0 +1,27 @@
// Code generated by go-swagger; DO NOT EDIT.
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"github.com/go-openapi/strfmt"
)
// IssueTemplateStringSlice issue template string slice
//
// swagger:model IssueTemplateStringSlice
type IssueTemplateStringSlice []string
// Validate validates this issue template string slice
func (m IssueTemplateStringSlice) Validate(formats strfmt.Registry) error {
return nil
}
// ContextValidate validates this issue template string slice based on context it is used
func (m IssueTemplateStringSlice) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
return nil
}

View File

@@ -23,7 +23,7 @@ type MarkdownOption struct {
// in: body
Context string `json:"Context,omitempty"`
// Mode to render (comment, gfm, markdown)
// Mode to render (markdown, comment, wiki, file)
//
// in: body
Mode string `json:"Mode,omitempty"`
@@ -33,8 +33,9 @@ type MarkdownOption struct {
// in: body
Text string `json:"Text,omitempty"`
// Is it a wiki page ?
// Is it a wiki page? (use mode=wiki instead)
//
// Deprecated: true
// in: body
Wiki bool `json:"Wiki,omitempty"`
}

View File

@@ -28,7 +28,7 @@ type MarkupOption struct {
// in: body
FilePath string `json:"FilePath,omitempty"`
// Mode to render (comment, gfm, markdown, file)
// Mode to render (markdown, comment, wiki, file)
//
// in: body
Mode string `json:"Mode,omitempty"`
@@ -38,8 +38,9 @@ type MarkupOption struct {
// in: body
Text string `json:"Text,omitempty"`
// Is it a wiki page ?
// Is it a wiki page? (use mode=wiki instead)
//
// Deprecated: true
// in: body
Wiki bool `json:"Wiki,omitempty"`
}

View File

@@ -0,0 +1,50 @@
// Code generated by go-swagger; DO NOT EDIT.
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// MergeUpstreamRequest merge upstream request
//
// swagger:model MergeUpstreamRequest
type MergeUpstreamRequest struct {
// branch
Branch string `json:"branch,omitempty"`
}
// Validate validates this merge upstream request
func (m *MergeUpstreamRequest) Validate(formats strfmt.Registry) error {
return nil
}
// ContextValidate validates this merge upstream request based on context it is used
func (m *MergeUpstreamRequest) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *MergeUpstreamRequest) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *MergeUpstreamRequest) UnmarshalBinary(b []byte) error {
var res MergeUpstreamRequest
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -0,0 +1,50 @@
// Code generated by go-swagger; DO NOT EDIT.
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// MergeUpstreamResponse merge upstream response
//
// swagger:model MergeUpstreamResponse
type MergeUpstreamResponse struct {
// merge style
MergeStyle string `json:"merge_type,omitempty"`
}
// Validate validates this merge upstream response
func (m *MergeUpstreamResponse) Validate(formats strfmt.Registry) error {
return nil
}
// ContextValidate validates this merge upstream response based on context it is used
func (m *MergeUpstreamResponse) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *MergeUpstreamResponse) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *MergeUpstreamResponse) UnmarshalBinary(b []byte) error {
var res MergeUpstreamResponse
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -21,6 +21,12 @@ import (
// swagger:model MigrateRepoOptions
type MigrateRepoOptions struct {
// a w s access key ID
AWSAccessKeyID string `json:"aws_access_key_id,omitempty"`
// a w s secret access key
AWSSecretAccessKey string `json:"aws_secret_access_key,omitempty"`
// auth password
AuthPassword string `json:"auth_password,omitempty"`

View File

@@ -40,6 +40,9 @@ type OAuth2Application struct {
// redirect u r is
RedirectURIs []string `json:"redirect_uris"`
// skip secondary authorization
SkipSecondaryAuthorization bool `json:"skip_secondary_authorization,omitempty"`
}
// Validate validates this o auth2 application

View File

@@ -99,6 +99,9 @@ type PullRequest struct {
// requested reviewers
RequestedReviewers []*User `json:"requested_reviewers"`
// requested reviewers teams
RequestedReviewersTeams []*Team `json:"requested_reviewers_teams"`
// number of review comments made on the diff of a PR review (not including comments on commits or issues in a PR)
ReviewComments int64 `json:"review_comments,omitempty"`
@@ -166,6 +169,10 @@ func (m *PullRequest) Validate(formats strfmt.Registry) error {
res = append(res, err)
}
if err := m.validateRequestedReviewersTeams(formats); err != nil {
res = append(res, err)
}
if err := m.validateUpdated(formats); err != nil {
res = append(res, err)
}
@@ -330,6 +337,32 @@ func (m *PullRequest) validateRequestedReviewers(formats strfmt.Registry) error
return nil
}
func (m *PullRequest) validateRequestedReviewersTeams(formats strfmt.Registry) error {
if swag.IsZero(m.RequestedReviewersTeams) { // not required
return nil
}
for i := 0; i < len(m.RequestedReviewersTeams); i++ {
if swag.IsZero(m.RequestedReviewersTeams[i]) { // not required
continue
}
if m.RequestedReviewersTeams[i] != nil {
if err := m.RequestedReviewersTeams[i].Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("requested_reviewers_teams" + "." + strconv.Itoa(i))
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("requested_reviewers_teams" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
func (m *PullRequest) validateUpdated(formats strfmt.Registry) error {
if swag.IsZero(m.Updated) { // not required
return nil
@@ -489,6 +522,10 @@ func (m *PullRequest) ContextValidate(ctx context.Context, formats strfmt.Regist
res = append(res, err)
}
if err := m.contextValidateRequestedReviewersTeams(ctx, formats); err != nil {
res = append(res, err)
}
if err := m.contextValidateAssignee(ctx, formats); err != nil {
res = append(res, err)
}
@@ -598,6 +635,31 @@ func (m *PullRequest) contextValidateRequestedReviewers(ctx context.Context, for
return nil
}
func (m *PullRequest) contextValidateRequestedReviewersTeams(ctx context.Context, formats strfmt.Registry) error {
for i := 0; i < len(m.RequestedReviewersTeams); i++ {
if m.RequestedReviewersTeams[i] != nil {
if swag.IsZero(m.RequestedReviewersTeams[i]) { // not required
return nil
}
if err := m.RequestedReviewersTeams[i].ContextValidate(ctx, formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("requested_reviewers_teams" + "." + strconv.Itoa(i))
} else if ce, ok := err.(*errors.CompositeError); ok {
return ce.ValidateName("requested_reviewers_teams" + "." + strconv.Itoa(i))
}
return err
}
}
}
return nil
}
func (m *PullRequest) contextValidateAssignee(ctx context.Context, formats strfmt.Registry) error {
if m.Assignee != nil {

View File

@@ -23,6 +23,9 @@ type Repository struct {
// allow fast forward only
AllowFastForwardOnly bool `json:"allow_fast_forward_only_merge,omitempty"`
// allow manual merge
AllowManualMerge bool `json:"allow_manual_merge,omitempty"`
// allow merge
AllowMerge bool `json:"allow_merge_commits,omitempty"`
@@ -45,6 +48,9 @@ type Repository struct {
// Format: date-time
ArchivedAt strfmt.DateTime `json:"archived_at,omitempty"`
// autodetect manual merge
AutodetectManualMerge bool `json:"autodetect_manual_merge,omitempty"`
// avatar URL
AvatarURL string `json:"avatar_url,omitempty"`
@@ -121,6 +127,9 @@ type Repository struct {
// languages URL
LanguagesURL string `json:"languages_url,omitempty"`
// licenses
Licenses []string `json:"licenses"`
// link
Link string `json:"link,omitempty"`
@@ -171,6 +180,9 @@ type Repository struct {
// template
Template bool `json:"template,omitempty"`
// topics
Topics []string `json:"topics"`
// URL
URL string `json:"url,omitempty"`

View File

@@ -0,0 +1,106 @@
// Code generated by go-swagger; DO NOT EDIT.
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// TagProtection TagProtection represents a tag protection
//
// swagger:model TagProtection
type TagProtection struct {
// created
// Format: date-time
Created strfmt.DateTime `json:"created_at,omitempty"`
// ID
ID int64 `json:"id,omitempty"`
// name pattern
NamePattern string `json:"name_pattern,omitempty"`
// updated
// Format: date-time
Updated strfmt.DateTime `json:"updated_at,omitempty"`
// whitelist teams
WhitelistTeams []string `json:"whitelist_teams"`
// whitelist usernames
WhitelistUsernames []string `json:"whitelist_usernames"`
}
// Validate validates this tag protection
func (m *TagProtection) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateCreated(formats); err != nil {
res = append(res, err)
}
if err := m.validateUpdated(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *TagProtection) validateCreated(formats strfmt.Registry) error {
if swag.IsZero(m.Created) { // not required
return nil
}
if err := validate.FormatOf("created_at", "body", "date-time", m.Created.String(), formats); err != nil {
return err
}
return nil
}
func (m *TagProtection) validateUpdated(formats strfmt.Registry) error {
if swag.IsZero(m.Updated) { // not required
return nil
}
if err := validate.FormatOf("updated_at", "body", "date-time", m.Updated.String(), formats); err != nil {
return err
}
return nil
}
// ContextValidate validates this tag protection based on context it is used
func (m *TagProtection) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *TagProtection) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *TagProtection) UnmarshalBinary(b []byte) error {
var res TagProtection
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -0,0 +1,50 @@
// Code generated by go-swagger; DO NOT EDIT.
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
)
// UpdateBranchProtectionPriories UpdateBranchProtectionPriories a list to update the branch protection rule priorities
//
// swagger:model UpdateBranchProtectionPriories
type UpdateBranchProtectionPriories struct {
// i ds
IDs []int64 `json:"ids"`
}
// Validate validates this update branch protection priories
func (m *UpdateBranchProtectionPriories) Validate(formats strfmt.Registry) error {
return nil
}
// ContextValidate validates this update branch protection priories based on context it is used
func (m *UpdateBranchProtectionPriories) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *UpdateBranchProtectionPriories) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *UpdateBranchProtectionPriories) UnmarshalBinary(b []byte) error {
var res UpdateBranchProtectionPriories
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -0,0 +1,71 @@
// Code generated by go-swagger; DO NOT EDIT.
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"context"
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// UpdateBranchRepoOption UpdateBranchRepoOption options when updating a branch in a repository
//
// swagger:model UpdateBranchRepoOption
type UpdateBranchRepoOption struct {
// New branch name
// Required: true
Name *string `json:"name"`
}
// Validate validates this update branch repo option
func (m *UpdateBranchRepoOption) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateName(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *UpdateBranchRepoOption) validateName(formats strfmt.Registry) error {
if err := validate.Required("name", "body", m.Name); err != nil {
return err
}
return nil
}
// ContextValidate validates this update branch repo option based on context it is used
func (m *UpdateBranchRepoOption) ContextValidate(ctx context.Context, formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *UpdateBranchRepoOption) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *UpdateBranchRepoOption) UnmarshalBinary(b []byte) error {
var res UpdateBranchRepoOption
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -29,7 +29,6 @@ import (
"path"
"path/filepath"
"slices"
"strings"
"time"
transport "github.com/go-openapi/runtime/client"
@@ -67,8 +66,16 @@ const (
ReviewStateUnknown models.ReviewStateType = ""
)
type GiteaTimelineFetcher interface {
GetTimeline(org, repo string, idx int64) ([]*models.TimelineComment, error)
}
type GiteaComment interface {
AddComment(pr *models.PullRequest, comment string) (error)
AddComment(pr *models.PullRequest, comment string) error
}
type GiteaSetRepoOptions interface {
SetRepoOptions(owner, repo string, manual_merge bool) (*models.Repository, error)
}
type GiteaMaintainershipReader interface {
@@ -78,20 +85,43 @@ type GiteaMaintainershipReader interface {
type GiteaPRFetcher interface {
GetPullRequest(org, project string, num int64) (*models.PullRequest, error)
GetAssociatedPrjGitPR(prjGitOrg, prjGitRepo, refOrg, refRepo string, Index int64) (*models.PullRequest, error)
}
type GiteaPRUpdater interface {
UpdatePullRequest(org, repo string, num int64, options *models.EditPullRequestOption) (*models.PullRequest, error)
}
type GiteaPRTimelineFetcher interface {
GiteaPRFetcher
GiteaTimelineFetcher
}
type GiteaCommitFetcher interface {
GetCommit(org, repo, sha string) (*models.Commit, error)
}
type GiteaReviewFetcher interface {
GetPullRequestReviews(org, project string, PRnum int64) ([]*models.PullReview, error)
}
type GiteaPRChecker interface {
type GiteaCommentFetcher interface {
GetIssueComments(org, project string, issueNo int64) ([]*models.Comment, error)
}
type GiteaReviewTimelineFetcher interface {
GiteaReviewFetcher
GiteaTimelineFetcher
}
type GiteaPRChecker interface {
GiteaReviewTimelineFetcher
GiteaCommentFetcher
GiteaMaintainershipReader
}
type GiteaReviewFetcherAndRequester interface {
GiteaReviewFetcher
GiteaReviewTimelineFetcher
GiteaCommentFetcher
GiteaReviewRequester
}
@@ -99,6 +129,10 @@ type GiteaReviewRequester interface {
RequestReviews(pr *models.PullRequest, reviewer ...string) ([]*models.PullReview, error)
}
type GiteaReviewUnrequester interface {
UnrequestReview(org, repo string, id int64, reviwers ...string) error
}
type GiteaReviewer interface {
AddReviewComment(pr *models.PullRequest, state models.ReviewStateType, comment string) (*models.PullReview, error)
}
@@ -111,26 +145,51 @@ type GiteaFileContentReader interface {
GetRepositoryFileContent(org, repo, hash, path string) ([]byte, string, error)
}
const (
CommitStatus_Pending = "pending"
CommitStatus_Success = "success"
CommitStatus_Fail = "failure"
CommitStatus_Error = "error"
)
type GiteaCommitStatusSetter interface {
SetCommitStatus(org, repo, hash string, status *models.CommitStatus) (*models.CommitStatus, error)
}
type GiteaCommitStatusGetter interface {
GetCommitStatus(org, repo, hash string) ([]*models.CommitStatus, error)
}
type Gitea interface {
GiteaComment
GiteaRepoFetcher
GiteaReviewRequester
GiteaReviewUnrequester
GiteaReviewer
GiteaPRFetcher
GiteaPRUpdater
GiteaCommitFetcher
GiteaReviewFetcher
GiteaCommentFetcher
GiteaTimelineFetcher
GiteaMaintainershipReader
GiteaFileContentReader
GiteaCommitStatusGetter
GiteaCommitStatusSetter
GiteaSetRepoOptions
GiteaTimelineFetcher
GetPullNotifications(since *time.Time) ([]*models.NotificationThread, error)
GetNotifications(Type string, since *time.Time) ([]*models.NotificationThread, error)
GetDoneNotifications(Type string, page int64) ([]*models.NotificationThread, error)
SetNotificationRead(notificationId int64) error
GetOrganization(orgName string) (*models.Organization, error)
GetOrganizationRepositories(orgName string) ([]*models.Repository, error)
CreateRepositoryIfNotExist(git Git, org, repoName string) (*models.Repository, error)
CreatePullRequestIfNotExist(repo *models.Repository, srcId, targetId, title, body string) (*models.PullRequest, error)
GetAssociatedPrjGitPR(prjGitOrg, prjGitRepo, refOrg, refRepo string, Index int64) (*models.PullRequest, error)
GetPullRequestFileContent(pr *models.PullRequest, path string) ([]byte, string, error)
GetRecentPullRequests(org, repo string) ([]*models.PullRequest, error)
GetRecentPullRequests(org, repo, branch string) ([]*models.PullRequest, error)
GetRecentCommits(org, repo, branch string, commitNo int64) ([]*models.Commit, error)
GetPullRequests(org, project string) ([]*models.PullRequest, error)
GetCurrentUser() (*models.User, error)
}
@@ -148,7 +207,7 @@ func AllocateGiteaTransport(giteaUrl string) Gitea {
log.Panicln("Failed to parse gitea url:", err)
}
r.transport = transport.New(url.Hostname(), apiclient.DefaultBasePath, [](string){url.Scheme})
r.transport = transport.New(url.Host, apiclient.DefaultBasePath, [](string){url.Scheme})
r.transport.DefaultAuthentication = transport.BearerToken(giteaToken)
r.client = apiclient.New(r.transport, nil)
@@ -177,9 +236,103 @@ func (gitea *GiteaTransport) GetPullRequest(org, project string, num int64) (*mo
return pr.Payload, err
}
func (gitea *GiteaTransport) UpdatePullRequest(org, repo string, num int64, options *models.EditPullRequestOption) (*models.PullRequest, error) {
pr, err := gitea.client.Repository.RepoEditPullRequest(
repository.NewRepoEditPullRequestParams().
WithOwner(org).
WithRepo(repo).
WithIndex(num).
WithBody(options),
gitea.transport.DefaultAuthentication,
)
return pr.Payload, err
}
func (gitea *GiteaTransport) GetPullRequests(org, repo string) ([]*models.PullRequest, error) {
var page, limit int64
prs := make([]*models.PullRequest, 0)
limit = 20
state := "open"
for {
page++
req, err := gitea.client.Repository.RepoListPullRequests(
repository.
NewRepoListPullRequestsParams().
WithDefaults().
WithOwner(org).
WithRepo(repo).
WithState(&state).
WithPage(&page).
WithLimit(&limit),
gitea.transport.DefaultAuthentication)
if err != nil {
return nil, fmt.Errorf("cannot fetch PR list for %s / %s : %w", org, repo, err)
}
prs = slices.Concat(prs, req.Payload)
if len(req.Payload) < int(limit) {
break
}
}
return prs, nil
}
func (gitea *GiteaTransport) GetCommitStatus(org, repo, hash string) ([]*models.CommitStatus, error) {
page := int64(1)
limit := int64(10)
var res []*models.CommitStatus
for {
r, err := gitea.client.Repository.RepoListStatuses(
repository.NewRepoListStatusesParams().WithDefaults().WithOwner(org).WithRepo(repo).WithSha(hash).WithPage(&page).WithLimit(&limit),
gitea.transport.DefaultAuthentication)
if err != nil {
return res, err
}
res = append(res, r.Payload...)
if len(r.Payload) < int(limit) {
break
}
}
return res, nil
}
func (gitea *GiteaTransport) SetCommitStatus(org, repo, hash string, status *models.CommitStatus) (*models.CommitStatus, error) {
res, err := gitea.client.Repository.RepoCreateStatus(
repository.NewRepoCreateStatusParams().
WithDefaults().
WithOwner(org).
WithRepo(repo).
WithSha(hash).
WithBody(&models.CreateStatusOption{
TargetURL: status.TargetURL,
Description: status.Description,
Context: status.Context,
State: models.CommitStatusState(status.Status),
}),
gitea.transport.DefaultAuthentication,
)
if err != nil {
return nil, err
}
return res.Payload, err
}
func (gitea *GiteaTransport) GetRepository(org, pkg string) (*models.Repository, error) {
repo, err := gitea.client.Repository.RepoGet(repository.NewRepoGetParams().WithDefaults().WithOwner(org).WithRepo(pkg), gitea.transport.DefaultAuthentication)
if err != nil {
switch err.(type) {
case *repository.RepoGetNotFound:
return nil, nil
}
return nil, err
}
@@ -217,25 +370,116 @@ func (gitea *GiteaTransport) GetPullRequestReviews(org, project string, PRnum in
return allReviews, nil
}
func (gitea *GiteaTransport) GetPullNotifications(since *time.Time) ([]*models.NotificationThread, error) {
bigLimit := int64(100000)
func (gitea *GiteaTransport) GetCommit(org, repo, sha string) (*models.Commit, error) {
f := false
params := notification.NewNotifyGetListParams().
WithDefaults().
WithSubjectType([]string{"Pull"}).
WithStatusTypes([]string{"unread"}).
WithLimit(&bigLimit)
r, err := gitea.client.Repository.RepoGetSingleCommit(
repository.NewRepoGetSingleCommitParams().
WithOwner(org).
WithRepo(repo).
WithSha(sha).
WithStat(&f).
WithFiles(&f).
WithVerification(&f),
gitea.transport.DefaultAuthentication)
if since != nil {
s := strfmt.DateTime(*since)
params.SetSince(&s)
if err != nil {
return nil, err
}
return r.Payload, nil
}
func (gitea *GiteaTransport) GetIssueComments(org, project string, issueNo int64) ([]*models.Comment, error) {
// limit := int64(20)
// var page int64
// var allComments []*models.Comment
// for {
c, err := gitea.client.Issue.IssueGetComments(
issue.NewIssueGetCommentsParams().
WithDefaults().
WithOwner(org).
WithRepo(project).
WithIndex(issueNo),
gitea.transport.DefaultAuthentication)
list, err := gitea.client.Notification.NotifyGetList(params, gitea.transport.DefaultAuthentication)
if err != nil {
return nil, err
}
return c.Payload, nil
// if len(c.Payload) < int(limit)
// }
}
func (gitea *GiteaTransport) SetRepoOptions(owner, repo string, manual_merge bool) (*models.Repository, error) {
ok, err := gitea.client.Repository.RepoEdit(repository.NewRepoEditParams().WithOwner(owner).WithRepo(repo).WithBody(
&models.EditRepoOption{
AllowManualMerge: manual_merge,
AutodetectManualMerge: manual_merge,
}), gitea.transport.DefaultAuthentication)
if err != nil {
return nil, err
}
return ok.Payload, err
}
const (
GiteaNotificationType_Pull = "Pull"
)
func (gitea *GiteaTransport) GetNotifications(Type string, since *time.Time) ([]*models.NotificationThread, error) {
bigLimit := int64(20)
ret := make([]*models.NotificationThread, 0, 100)
for page := int64(1); ; page++ {
params := notification.NewNotifyGetListParams().
WithDefaults().
WithSubjectType([]string{Type}).
WithStatusTypes([]string{"unread"}).
WithLimit(&bigLimit).
WithPage(&page)
if since != nil {
s := strfmt.DateTime(*since)
params.SetSince(&s)
}
list, err := gitea.client.Notification.NotifyGetList(params, gitea.transport.DefaultAuthentication)
if err != nil {
return nil, err
}
ret = slices.Concat(ret, list.Payload)
if len(list.Payload) < int(bigLimit) {
break
}
}
return ret, nil
}
func (gitea *GiteaTransport) GetDoneNotifications(Type string, page int64) ([]*models.NotificationThread, error) {
limit := int64(20)
t := true
if page <= 0 {
return nil, fmt.Errorf("Page is 1-base positive int...")
}
list, err := gitea.client.Notification.NotifyGetList(
notification.NewNotifyGetListParams().
WithAll(&t).
WithSubjectType([]string{Type}).
WithStatusTypes([]string{"read"}).
WithLimit(&limit).
WithPage(&page),
gitea.transport.DefaultAuthentication)
if err != nil {
return nil, err
}
return list.Payload, nil
}
@@ -292,6 +536,7 @@ func (gitea *GiteaTransport) GetOrganizationRepositories(orgName string) ([]*mod
}
func (gitea *GiteaTransport) CreateRepositoryIfNotExist(git Git, org, repoName string) (*models.Repository, error) {
log.Println(org, repoName)
repo, err := gitea.client.Repository.RepoGet(
repository.NewRepoGetParams().WithDefaults().WithOwner(org).WithRepo(repoName),
gitea.transport.DefaultAuthentication)
@@ -299,6 +544,7 @@ func (gitea *GiteaTransport) CreateRepositoryIfNotExist(git Git, org, repoName s
if err != nil {
switch err.(type) {
case *repository.RepoGetNotFound:
log.Println("not found", err)
repo, err := gitea.client.Organization.CreateOrgRepo(
organization.NewCreateOrgRepoParams().WithDefaults().WithBody(
&models.CreateRepoOption{
@@ -357,14 +603,14 @@ func (gitea *GiteaTransport) CreateRepositoryIfNotExist(git Git, org, repoName s
func (gitea *GiteaTransport) CreatePullRequestIfNotExist(repo *models.Repository, srcId, targetId, title, body string) (*models.PullRequest, error) {
prOptions := models.CreatePullRequestOption{
Base: repo.DefaultBranch,
Base: targetId,
Head: srcId,
Title: title,
Body: body,
}
if pr, err := gitea.client.Repository.RepoGetPullRequestByBaseHead(
repository.NewRepoGetPullRequestByBaseHeadParams().WithOwner(repo.Owner.UserName).WithRepo(repo.Name).WithBase(repo.DefaultBranch).WithHead(srcId),
repository.NewRepoGetPullRequestByBaseHeadParams().WithOwner(repo.Owner.UserName).WithRepo(repo.Name).WithBase(targetId).WithHead(srcId),
gitea.transport.DefaultAuthentication,
); err == nil {
return pr.Payload, nil
@@ -387,46 +633,6 @@ func (gitea *GiteaTransport) CreatePullRequestIfNotExist(repo *models.Repository
return pr.GetPayload(), nil
}
func (gitea *GiteaTransport) GetAssociatedPrjGitPR(prjGitOrg, prjGitRepo, refOrg, refRepo string, Index int64) (*models.PullRequest, error) {
var page int64
state := "open"
for {
page++
prs, err := gitea.client.Repository.RepoListPullRequests(
repository.
NewRepoListPullRequestsParams().
WithDefaults().
WithOwner(prjGitOrg).
WithRepo(prjGitRepo).
WithState(&state).
WithPage(&page),
gitea.transport.DefaultAuthentication)
if err != nil {
return nil, fmt.Errorf("cannot fetch PR list for %s / %s : %w", prjGitOrg, prjGitRepo, err)
}
prLine := fmt.Sprintf(PrPattern, refOrg, refRepo, Index)
// payload_processing:
for _, pr := range prs.Payload {
lines := strings.Split(pr.Body, "\n")
for _, line := range lines {
if strings.TrimSpace(line) == prLine {
return pr, nil
}
}
}
if len(prs.Payload) < 10 {
break
}
}
return nil, nil
}
func (gitea *GiteaTransport) RequestReviews(pr *models.PullRequest, reviewers ...string) ([]*models.PullReview, error) {
reviewOptions := models.PullReviewRequestOptions{
Reviewers: reviewers,
@@ -449,6 +655,14 @@ func (gitea *GiteaTransport) RequestReviews(pr *models.PullRequest, reviewers ..
return review.GetPayload(), nil
}
func (gitea *GiteaTransport) UnrequestReview(org, repo string, id int64, reviwers ...string) error {
_, err := gitea.client.Repository.RepoDeletePullReviewRequests(
repository.NewRepoDeletePullReviewRequestsParams().WithOwner(org).WithRepo(repo).WithIndex(id).WithBody(&models.PullReviewRequestOptions{
Reviewers: reviwers,
}), gitea.transport.DefaultAuthentication)
return err
}
func (gitea *GiteaTransport) AddReviewComment(pr *models.PullRequest, state models.ReviewStateType, comment string) (*models.PullReview, error) {
c, err := gitea.client.Repository.RepoCreatePullReview(
repository.NewRepoCreatePullReviewParams().
@@ -484,7 +698,7 @@ func (gitea *GiteaTransport) AddReviewComment(pr *models.PullRequest, state mode
return c.Payload, nil
}
func (gitea *GiteaTransport) AddComment(pr *models.PullRequest, comment string) (error) {
func (gitea *GiteaTransport) AddComment(pr *models.PullRequest, comment string) error {
_, err := gitea.client.Issue.IssueCreateComment(
issue.NewIssueCreateCommentParams().
WithDefaults().
@@ -503,6 +717,41 @@ func (gitea *GiteaTransport) AddComment(pr *models.PullRequest, comment string)
return nil
}
func (gitea *GiteaTransport) GetTimeline(org, repo string, idx int64) ([]*models.TimelineComment, error) {
limit := int64(20)
page := int64(1)
resCount := limit
retData := []*models.TimelineComment{}
for resCount == limit {
res, err := gitea.client.Issue.IssueGetCommentsAndTimeline(
issue.NewIssueGetCommentsAndTimelineParams().
WithOwner(org).
WithRepo(repo).
WithIndex(idx).
WithPage(&page).
WithLimit(&limit),
gitea.transport.DefaultAuthentication,
)
if err != nil {
return nil, err
}
resCount = int64(len(res.Payload))
page++
retData = append(retData, res.Payload...)
}
slices.SortFunc(retData, func(a, b *models.TimelineComment) int {
return time.Time(b.Created).Compare(time.Time(a.Created))
})
return retData, nil
}
func (gitea *GiteaTransport) GetRepositoryFileContent(org, repo, hash, path string) ([]byte, string, error) {
params := repository.NewRepoGetContentsParams().WithOwner(org).WithRepo(repo).WithFilepath(path)
if len(hash) > 0 {
@@ -524,7 +773,7 @@ func (gitea *GiteaTransport) GetRepositoryFileContent(org, repo, hash, path stri
}
data := make([]byte, content.Payload.Size)
n, err := base64.StdEncoding.Decode(data, []byte(content.Payload.Content))
n, err := base64.StdEncoding.Decode(data, []byte(content.Payload.Content))
if err != nil {
log.Println(content.Payload.Content[239])
log.Println(len(content.Payload.Content))
@@ -545,12 +794,13 @@ func (gitea *GiteaTransport) GetPullRequestFileContent(pr *models.PullRequest, p
return gitea.GetRepositoryFileContent(pr.Head.Repo.Owner.UserName, pr.Head.Repo.Name, pr.Head.Sha, path)
}
func (gitea *GiteaTransport) GetRecentPullRequests(org, repo string) ([]*models.PullRequest, error) {
func (gitea *GiteaTransport) GetRecentPullRequests(org, repo, branch string) ([]*models.PullRequest, error) {
prs := make([]*models.PullRequest, 0, 10)
var page int64
page = 1
sort := "recentupdate"
endPrs:
for {
res, err := gitea.client.Repository.RepoListPullRequests(
repository.NewRepoListPullRequestsParams().
@@ -563,15 +813,21 @@ func (gitea *GiteaTransport) GetRecentPullRequests(org, repo string) ([]*models.
return nil, err
}
prs = append(prs, res.Payload...)
n := len(res.Payload)
if n < 10 {
if len(res.Payload) == 0 {
break
}
// if pr is closed for more than a week, assume that we are done too
if time.Since(time.Time(res.Payload[n-1].Updated)) > 7*24*time.Hour {
break
for _, pr := range res.Payload {
if pr.Base.Name != branch {
continue
}
// if pr is closed for more than a week, assume that we are done too
if pr.State == "closed" && time.Since(time.Time(pr.Updated)) > 7*24*time.Hour {
break endPrs
}
prs = append(prs, pr)
}
page++
@@ -583,20 +839,26 @@ func (gitea *GiteaTransport) GetRecentPullRequests(org, repo string) ([]*models.
func (gitea *GiteaTransport) GetRecentCommits(org, repo, branch string, commitNo int64) ([]*models.Commit, error) {
not := false
var page int64 = 1
commits, err := gitea.client.Repository.RepoGetAllCommits(
repository.NewRepoGetAllCommitsParams().
WithOwner(org).
WithRepo(repo).
WithSha(&branch).
WithPage(&page).
WithStat(&not).
WithFiles(&not).
WithVerification(&not).
WithLimit(&commitNo),
gitea.transport.DefaultAuthentication,
)
params := repository.NewRepoGetAllCommitsParams().
WithOwner(org).
WithRepo(repo).
WithPage(&page).
WithStat(&not).
WithFiles(&not).
WithVerification(&not).
WithLimit(&commitNo)
if len(branch) > 0 {
params = params.WithSha(&branch)
}
commits, err := gitea.client.Repository.RepoGetAllCommits(params, gitea.transport.DefaultAuthentication)
if err != nil {
switch err.(type) {
case *repository.RepoGetAllCommitsNotFound:
return nil, nil
}
return nil, err
}

View File

@@ -21,7 +21,6 @@ package common
import (
"crypto/tls"
"fmt"
"log"
"net/url"
"runtime/debug"
"slices"
@@ -78,18 +77,18 @@ func (l *ListenDefinitions) processTopicChanges(ch *rabbitmq.Channel, queueName
return
}
log.Println(" topic change:", topic)
LogDebug(" topic change:", topic)
switch topic[0] {
case '+':
if err := ch.QueueBind(queueName, topic[1:], "pubsub", false, nil); err != nil {
log.Println(err)
LogError(err)
}
case '-':
if err := ch.QueueUnbind(queueName, topic[1:], "pubsub", nil); err != nil {
log.Println(err)
LogError(err)
}
default:
log.Println("Ignoring topic change.")
LogInfo("Ignoring unknown topic change:", topic)
}
}
}
@@ -126,7 +125,7 @@ func (l *ListenDefinitions) processRabbitMQ(msgCh chan<- RabbitMessage) error {
} else {
q, err = ch.QueueDeclarePassive(queueName, true, false, true, false, nil)
if err != nil {
log.Printf("queue not found .. trying to create it: %v\n", err)
LogInfo("queue not found .. trying to create it:", err)
if ch.IsClosed() {
ch, err = connection.Channel()
if err != nil {
@@ -136,7 +135,7 @@ func (l *ListenDefinitions) processRabbitMQ(msgCh chan<- RabbitMessage) error {
q, err = ch.QueueDeclare(queueName, true, false, true, false, nil)
if err != nil {
log.Printf("can't create persistent queue ... falling back to temporaty queue: %v\n", err)
LogInfo("can't create persistent queue ... falling back to temporaty queue:", err)
if ch.IsClosed() {
ch, err = connection.Channel()
return fmt.Errorf("Channel cannot be re-opened. Err: %w", err)
@@ -150,7 +149,7 @@ func (l *ListenDefinitions) processRabbitMQ(msgCh chan<- RabbitMessage) error {
}
// log.Printf("queue: %s:%d", q.Name, q.Consumers)
log.Println(" -- listening to topics:")
LogDebug(" -- listening to topics:")
l.topicSubChanges = make(chan string)
defer close(l.topicSubChanges)
go l.processTopicChanges(ch, q.Name)
@@ -175,29 +174,29 @@ func (l *ListenDefinitions) processRabbitMQ(msgCh chan<- RabbitMessage) error {
}
}
func (l *ListenDefinitions) connectAndProcessRabbitMQ(log *log.Logger, ch chan<- RabbitMessage) {
func (l *ListenDefinitions) connectAndProcessRabbitMQ(ch chan<- RabbitMessage) {
defer func() {
if r := recover(); r != nil {
log.Println(r)
log.Println("'crash' RabbitMQ worker. Recovering... reconnecting...")
LogError(r)
LogError("'crash' RabbitMQ worker. Recovering... reconnecting...")
time.Sleep(5 * time.Second)
go l.connectAndProcessRabbitMQ(log, ch)
go l.connectAndProcessRabbitMQ(ch)
}
}()
for {
err := l.processRabbitMQ(ch)
if err != nil {
log.Printf("Error in RabbitMQ connection. %#v", err)
log.Println("Reconnecting in 2 seconds...")
LogError("Error in RabbitMQ connection. %#v", err)
LogInfo("Reconnecting in 2 seconds...")
time.Sleep(2 * time.Second)
}
}
}
func (l *ListenDefinitions) connectToRabbitMQ(log *log.Logger) chan RabbitMessage {
func (l *ListenDefinitions) connectToRabbitMQ() chan RabbitMessage {
ch := make(chan RabbitMessage, 100)
go l.connectAndProcessRabbitMQ(log, ch)
go l.connectAndProcessRabbitMQ(ch)
return ch
}
@@ -205,16 +204,16 @@ func (l *ListenDefinitions) connectToRabbitMQ(log *log.Logger) chan RabbitMessag
func ProcessEvent(f RequestProcessor, request *Request) {
defer func() {
if r := recover(); r != nil {
log.Println("panic caught")
LogError("panic caught")
if err, ok := r.(error); !ok {
log.Println(err)
LogError(err)
}
log.Println(string(debug.Stack()))
LogError(string(debug.Stack()))
}
}()
if err := f.ProcessFunc(request); err != nil {
log.Println(err)
LogError(err)
}
}
@@ -265,15 +264,23 @@ next_new_topic:
l.topicSubChanges <- "+" + topic
}
}
for j < len(l.topics) {
l.topicSubChanges <- "-" + l.topics[j]
j++
}
l.topics = newTopics
}
func (l *ListenDefinitions) ProcessRabbitMQEvents() error {
log.Println("RabbitMQ connection:", l.RabbitURL.String())
log.Println(len(l.Handlers), len(l.Orgs))
LogInfo("RabbitMQ connection:", l.RabbitURL.String())
LogDebug("# Handlers:", len(l.Handlers))
LogDebug("# Orgs:", len(l.Orgs))
l.RabbitURL.User = url.UserPassword(rabbitUser, rabbitPassword)
l.topics = l.generateTopics()
ch := l.connectToRabbitMQ(log.Default())
ch := l.connectToRabbitMQ()
for {
msg, ok := <-ch
@@ -281,7 +288,7 @@ func (l *ListenDefinitions) ProcessRabbitMQEvents() error {
return nil
}
log.Println("event:", msg.RoutingKey)
LogDebug("event:", msg.RoutingKey)
route := strings.Split(msg.RoutingKey, ".")
if len(route) > 3 {
@@ -289,11 +296,11 @@ func (l *ListenDefinitions) ProcessRabbitMQEvents() error {
org := route[2]
if !slices.Contains(l.Orgs, org) {
log.Println("Got event for unhandeled org:", org)
LogInfo("Got event for unhandeled org:", org)
continue
}
log.Println("org:", org, "type:", reqType)
LogDebug("org:", org, "type:", reqType)
if handler, found := l.Handlers[reqType]; found {
/* h, err := CreateRequestHandler()
if err != nil {
@@ -303,10 +310,10 @@ func (l *ListenDefinitions) ProcessRabbitMQEvents() error {
*/
req, err := ParseRequestJSON(reqType, msg.Body)
if err != nil {
log.Println("Error parsing request JSON:", err)
LogError("Error parsing request JSON:", err)
continue
} else {
log.Println("processing req", req.Type)
LogDebug("processing req", req.Type)
// h.Request = req
ProcessEvent(handler, req)

View File

@@ -2,6 +2,7 @@ package common
import (
"net/url"
"slices"
"testing"
)
@@ -20,8 +21,29 @@ func TestListenDefinitionsTopicUpdate(t *testing.T) {
{
name: "adding one org",
handlers: []string{"foo"},
orgs2: []string{"newOrg"},
topicDelta: []string{"+suse"},
orgs2: []string{"NewOrg"},
topicDelta: []string{"+suse.src.NewOrg.foo.#"},
},
{
name: "adding two orgs",
handlers: []string{"foo", "bar"},
orgs1: []string{"old"},
orgs2: []string{"old", "NewOrg", "NewOrg2"},
topicDelta: []string{"+suse.src.NewOrg.foo.#", "+suse.src.NewOrg2.foo.#", "+suse.src.NewOrg.bar.#", "+suse.src.NewOrg2.bar.#"},
},
{
name: "adding one org and removing old one",
handlers: []string{"foo", "bar"},
orgs1: []string{"old"},
orgs2: []string{"NewOrg"},
topicDelta: []string{"+suse.src.NewOrg.foo.#", "+suse.src.NewOrg.bar.#", "-suse.src.old.foo.#", "-suse.src.old.bar.#"},
},
{
name: "adding one org and removing old one",
handlers: []string{"foo", "bar"},
orgs1: []string{"NewOrg"},
orgs2: []string{"old"},
topicDelta: []string{"-suse.src.NewOrg.foo.#", "-suse.src.NewOrg.bar.#", "+suse.src.old.foo.#", "+suse.src.old.bar.#"},
},
}
@@ -35,13 +57,42 @@ func TestListenDefinitionsTopicUpdate(t *testing.T) {
RabbitURL: u,
}
slices.Sort(test.topicDelta)
for _, r := range test.handlers {
l.Handlers[r] = nil
}
changes := []string{}
l.UpdateTopics()
if len(l.topicSubChanges) != len(test.topicDelta) {
t.Fatal("topicSubChanges != topicDelta")
a:
for {
select {
case c := <-l.topicSubChanges:
changes = append(changes, c)
default:
changes = []string{}
break a
}
}
l.Orgs = test.orgs2
l.UpdateTopics()
changes = []string{}
b:
for {
select {
case c := <-l.topicSubChanges:
changes = append(changes, c)
default:
slices.Sort(changes)
break b
}
}
if !slices.Equal(changes, test.topicDelta) {
t.Error("got:", changes, " expected:", test.topicDelta)
}
})
}

View File

@@ -36,6 +36,64 @@ func CreateStdoutLogger(stdout, stderr io.Writer) (*log.Logger, *log.Logger) {
func PanicOnError(err error) {
if err != nil {
LogError(err)
panic(err)
}
}
func PanicOnErrorWithMsg(err error, msg ...any) {
if err != nil {
LogError(msg...)
panic(err)
}
}
type LogLevel int
const (
LogLevelNone = 0
LogLevelError = 2
LogLevelInfo = 5
LogLevelDebug = 10
)
var logLevel LogLevel = LogLevelInfo
func SetLoggingLevel(ll LogLevel) {
logLevel = ll
}
func SetLoggingLevelFromString(ll string) error {
switch ll {
case "info":
SetLoggingLevel(LogLevelInfo)
case "debug":
SetLoggingLevel(LogLevelDebug)
case "error":
SetLoggingLevel(LogLevelError)
case "none":
SetLoggingLevel(LogLevelNone)
default:
return fmt.Errorf("Unknown logging level: %s", ll)
}
return nil
}
func LogError(params ...any) {
if logLevel >= LogLevelError {
log.Println(append([]any{"[E]"}, params...)...)
}
}
func LogDebug(params ...any) {
if logLevel >= LogLevelDebug {
log.Println(append([]any{"[D]"}, params...)...)
}
}
func LogInfo(params ...any) {
if logLevel >= LogLevelInfo {
log.Println(append([]any{"[I]"}, params...)...)
}
}

View File

@@ -16,7 +16,7 @@ type MaintainershipData interface {
ListProjectMaintainers() []string
ListPackageMaintainers(pkg string) []string
IsApproved(pkg string, reviews []*models.PullReview) bool
IsApproved(pkg string, reviews []*models.PullReview, submitter string) bool
}
const ProjectKey = ""
@@ -44,12 +44,13 @@ func FetchProjectMaintainershipData(gitea GiteaMaintainershipReader, org, prjGit
dir := true
if err != nil || data == nil {
dir = false
if _, notFound := err.(*repository.RepoGetRawFileNotFound); !notFound {
if _, notFound := err.(*repository.RepoGetContentsNotFound); !notFound {
return nil, err
}
LogDebug("Falling back to maintainership file")
data, _, err = gitea.FetchMaintainershipFile(org, prjGit, branch)
if err != nil || data == nil {
if _, notFound := err.(*repository.RepoGetRawFileNotFound); !notFound {
if _, notFound := err.(*repository.RepoGetContentsNotFound); !notFound {
return nil, err
}
@@ -62,7 +63,7 @@ func FetchProjectMaintainershipData(gitea GiteaMaintainershipReader, org, prjGit
if m != nil {
m.IsDir = dir
m.FetchPackage = func(pkg string) ([]byte, error) {
data , _, err := gitea.FetchMaintainershipDirFile(org, prjGit, branch, pkg)
data, _, err := gitea.FetchMaintainershipDirFile(org, prjGit, branch, pkg)
return data, err
}
}
@@ -125,27 +126,27 @@ prjMaintainer:
return pkgMaintainers
}
func (data *MaintainershipMap) IsApproved(pkg string, reviews []*models.PullReview) bool {
reviewers, found := data.Data[pkg]
if !found {
if pkg != ProjectKey && data.IsDir {
r, err := data.FetchPackage(pkg)
if err != nil {
return false
}
reviewers = parsePkgDirData(pkg, r)
data.Data[pkg] = reviewers
} else {
return true
}
func (data *MaintainershipMap) IsApproved(pkg string, reviews []*models.PullReview, submitter string) bool {
var reviewers []string
if pkg != ProjectKey {
reviewers = data.ListPackageMaintainers(pkg)
} else {
reviewers = data.ListProjectMaintainers()
}
if len(reviewers) == 0 {
return true
}
LogDebug("Looking for review by:", reviewers)
if slices.Contains(reviewers, submitter) {
LogDebug("Submitter is maintainer. Approving.")
return true
}
for _, review := range reviews {
if !review.Stale && review.State == ReviewStateApproved && slices.Contains(reviewers, review.User.UserName) {
LogDebug("Reviewed by", review.User.UserName)
return true
}
@@ -183,7 +184,7 @@ func (data *MaintainershipMap) WriteMaintainershipFile(writer io.StringWriter) e
keys = slices.Delete(keys, i, len(keys))
}
slices.Sort(keys)
for i, pkg := range(keys) {
for i, pkg := range keys {
eol := ","
if i == len(keys)-1 {
eol = ""

View File

@@ -120,7 +120,7 @@ func TestMaintainership(t *testing.T) {
},
}
notFoundError := repository.NewRepoGetRawFileNotFound()
notFoundError := repository.NewRepoGetContentsNotFound()
for _, test := range packageTests {
runTests := func(t *testing.T, mi common.GiteaMaintainershipReader) {
maintainers, err := common.FetchProjectMaintainershipData(mi, config.Organization, config.GitProjectName, config.Branch)

View File

@@ -25,17 +25,27 @@ import (
"errors"
"fmt"
"io"
"log"
"net/http"
"net/url"
"os/exec"
"regexp"
"slices"
"strings"
"syscall"
"time"
)
//go:generate mockgen -source=obs_utils.go -destination=mock/obs_utils.go -typed
type BuildResultOptions struct {
BinaryList bool
OldState string
LastBuild bool
}
type ObsStatusFetcherWithState interface {
BuildStatusWithState(project string, opts *BuildResultOptions, packages ...string) (*BuildResultList, error)
}
type ObsClient struct {
baseUrl *url.URL
client *http.Client
@@ -48,7 +58,7 @@ type ObsClient struct {
}
func NewObsClient(host string) (*ObsClient, error) {
baseUrl, err := url.Parse("https://" + host)
baseUrl, err := url.Parse(host)
if err != nil {
return nil, err
}
@@ -146,6 +156,34 @@ type GroupMeta struct {
Persons PersonGroup `xml:"person"`
}
type RequestStateMeta struct {
XMLName xml.Name `xml:"state"`
State string `xml:"name,attr"`
}
type RequestActionTarget struct {
XMLName xml.Name
Project string `xml:"project,attr"`
Package string `xml:"package,attr"`
Revision *string `xml:"rev,attr,optional"`
}
type RequestActionMeta struct {
XMLName xml.Name `xml:"action"`
Type string `xml:"type,attr"`
Source *RequestActionTarget `xml:"source,optional"`
Target *RequestActionTarget `xml:"target,optional"`
}
type RequestMeta struct {
XMLName xml.Name `xml:"request"`
Id int `xml:"id,attr"`
Creator string `xml:"creator,attr"`
Action *RequestActionMeta `xml:"action"`
State RequestStateMeta `xml:"state"`
}
func parseProjectMeta(data []byte) (*ProjectMeta, error) {
var meta ProjectMeta
err := xml.Unmarshal(data, &meta)
@@ -156,8 +194,83 @@ func parseProjectMeta(data []byte) (*ProjectMeta, error) {
return &meta, nil
}
const (
RequestStatus_Unknown = "unknown"
RequestStatus_Accepted = "accepted"
RequestStatus_Superseded = "superseded"
RequestStatus_Declined = "declined"
RequestStatus_Revoked = "revoked"
RequestStatus_New = "new"
RequestStatus_Review = "review"
)
func (status *RequestStateMeta) IsFinal() bool {
switch status.State {
case RequestStatus_Declined, RequestStatus_Revoked, RequestStatus_Accepted, RequestStatus_Superseded:
return true
}
return false
}
func parseRequestXml(data []byte) (*RequestMeta, error) {
ret := RequestMeta{}
LogDebug("parsing: ", string(data))
if err := xml.Unmarshal(data, &ret); err != nil {
return nil, err
}
return &ret, nil
}
func (c *ObsClient) CreateSubmitRequest(sourcePrj, sourcePkg, targetPrj string) (*RequestMeta, error) {
url := c.baseUrl.JoinPath("request")
query := url.Query()
query.Add("cmd", "create")
url.RawQuery = query.Encode()
request := `<request>
<action type="submit">
<source project="` + sourcePrj + `" package="` + sourcePkg + `">
</source>
<target project="` + targetPrj + `" package="` + sourcePkg + `">
</target>
</action>
</request>`
res, err := c.ObsRequestRaw("POST", url.String(), strings.NewReader(request))
if err != nil {
return nil, err
} else if res.StatusCode != 200 {
return nil, fmt.Errorf("Unexpected return code: %d", res.StatusCode)
}
data, err := io.ReadAll(res.Body)
if err != nil {
return nil, err
}
return parseRequestXml(data)
}
func (c *ObsClient) RequestStatus(requestID int) (*RequestMeta, error) {
res, err := c.ObsRequest("GET", []string{"request", fmt.Sprint(requestID)}, nil)
if err != nil {
return nil, err
}
if res.StatusCode != 200 {
return nil, fmt.Errorf("Unexpected return code: %d", res.StatusCode)
}
data, err := io.ReadAll(res.Body)
if err != nil {
return nil, err
}
return parseRequestXml(data)
}
func (c *ObsClient) GetGroupMeta(gid string) (*GroupMeta, error) {
res, err := c.ObsRequest("GET", c.baseUrl.JoinPath("group", gid).String(), nil)
res, err := c.ObsRequest("GET", []string{"group", gid}, nil)
if err != nil {
return nil, err
}
@@ -175,6 +288,7 @@ func (c *ObsClient) GetGroupMeta(gid string) (*GroupMeta, error) {
if err != nil {
return nil, err
}
defer res.Body.Close()
var meta GroupMeta
err = xml.Unmarshal(data, &meta)
@@ -186,7 +300,7 @@ func (c *ObsClient) GetGroupMeta(gid string) (*GroupMeta, error) {
}
func (c *ObsClient) GetUserMeta(uid string) (*UserMeta, error) {
res, err := c.ObsRequest("GET", c.baseUrl.JoinPath("person", uid).String(), nil)
res, err := c.ObsRequest("GET", []string{"person", uid}, nil)
if err != nil {
return nil, err
}
@@ -204,6 +318,7 @@ func (c *ObsClient) GetUserMeta(uid string) (*UserMeta, error) {
if err != nil {
return nil, err
}
defer res.Body.Close()
var meta UserMeta
err = xml.Unmarshal(data, &meta)
@@ -214,7 +329,11 @@ func (c *ObsClient) GetUserMeta(uid string) (*UserMeta, error) {
return &meta, nil
}
func (c *ObsClient) ObsRequest(method string, url string, body io.Reader) (*http.Response, error) {
func (c *ObsClient) ObsRequest(method string, url_path []string, body io.Reader) (*http.Response, error) {
return c.ObsRequestRaw(method, c.baseUrl.JoinPath(url_path...).String(), body)
}
func (c *ObsClient) ObsRequestRaw(method string, url string, body io.Reader) (*http.Response, error) {
req, err := http.NewRequest(method, url, body)
if err != nil {
@@ -227,6 +346,12 @@ func (c *ObsClient) ObsRequest(method string, url string, body io.Reader) (*http
req.Header.Add("cookie", c.cookie)
}
res, err := c.client.Do(req)
if err != nil && res == nil {
LogDebug("No res headers:", err)
return res, err
}
if err == nil && res.StatusCode == 200 {
auth_cookie := res.Header.Get("set-cookie")
if auth_cookie != "" {
@@ -236,8 +361,8 @@ func (c *ObsClient) ObsRequest(method string, url string, body io.Reader) (*http
}
if res.StatusCode == 401 {
// log.Printf("new authentication is needed ...")
if c.sshkey == "" {
LogDebug("setting basic auth")
req.SetBasicAuth(c.user, c.password)
} else {
www := res.Header.Get("www-authenticate")
@@ -248,25 +373,19 @@ func (c *ObsClient) ObsRequest(method string, url string, body io.Reader) (*http
return nil, errors.New("No realm found")
}
realm := string(match[1])
sshKeygenPath, err := exec.LookPath("ssh-keygen")
if err != nil {
fmt.Println("ssh-keygen not found")
}
// SSH Sign
cmd := exec.Command(sshKeygenPath, "-Y", "sign", "-f", c.sshkeyfile, "-n", realm, "-q")
cmd := exec.Command("ssh-keygen", "-Y", "sign", "-f", c.sshkeyfile, "-n", realm, "-q")
now := time.Now().Unix()
sigdata := fmt.Sprintf("(created): %d", now)
cmd.Stdin = strings.NewReader(sigdata)
stdout, err := cmd.Output()
if err != nil {
log.Panicln("SSH sign error:", cmd.Stderr)
if exitError, ok := err.(*exec.ExitError); ok {
waitStatus := exitError.Sys().(syscall.WaitStatus)
exitCode := waitStatus.ExitStatus()
return nil, errors.New(fmt.Sprintf("ssh-keygen signature creation failed: %d", exitCode))
exitCode := -1337
if cmd.ProcessState != nil {
exitCode = cmd.ProcessState.ExitCode()
}
return nil, errors.New("ssh-keygen signature creation failed")
return nil, errors.New(fmt.Sprintf("ssh-keygen signature creation failed: %d", exitCode))
}
reg := regexp.MustCompile("(?s)-----BEGIN SSH SIGNATURE-----\n(.*?)\n-----END SSH SIGNATURE-----")
match = reg.FindStringSubmatch(string(stdout))
@@ -274,7 +393,7 @@ func (c *ObsClient) ObsRequest(method string, url string, body io.Reader) (*http
return nil, errors.New("could not extract ssh signature")
}
signature, err := base64.StdEncoding.DecodeString(string(match[1]))
signature, err := base64.StdEncoding.DecodeString(match[1])
if err != nil {
return nil, err
}
@@ -283,31 +402,35 @@ func (c *ObsClient) ObsRequest(method string, url string, body io.Reader) (*http
authorization := fmt.Sprintf(`keyId="%s",algorithm="ssh",headers="(created)",created=%d,signature="%s"`,
c.user, now, signatureBase64)
// log.Printf("Add Authorization Signature ", authorization)
// log.Printf("Add Authorization Signature ", authorization)
req.Header.Add("Authorization", "Signature "+authorization)
}
// Another time with authentification header
LogDebug("Trying again with authorization for", req.URL.String())
res, err = c.client.Do(req)
if err != nil {
if res != nil {
LogError("Authentification failed:", res.StatusCode)
}
return nil, err
}
}
// Another time with authentification header
// log.Printf("Trying again with authorization: %s", req.Header.Get("Authorization"))
res, err = c.client.Do(req)
if err != nil {
log.Panicln("Authentification failed:", res.StatusCode)
return nil, err
}
// Store the cookie for next call
auth_cookie := res.Header.Get("set-cookie")
if auth_cookie != "" {
c.cookie = auth_cookie
if err == nil {
// Store the cookie for next call
auth_cookie := res.Header.Get("set-cookie")
if auth_cookie != "" {
c.cookie = auth_cookie
}
}
return res, err
}
func (c *ObsClient) GetProjectMeta(project string) (*ProjectMeta, error) {
res, err := c.ObsRequest("GET", c.baseUrl.JoinPath("source", project, "_meta").String(), nil)
req := []string{"source", project, "_meta"}
res, err := c.ObsRequest("GET", req, nil)
if err != nil {
return nil, err
@@ -319,7 +442,7 @@ func (c *ObsClient) GetProjectMeta(project string) (*ProjectMeta, error) {
case 404:
return nil, nil
default:
return nil, fmt.Errorf("Unexpected return code: %d", res.StatusCode)
return nil, fmt.Errorf("Unexpected return code: %d %s %w", res.StatusCode, req, err)
}
data, err := io.ReadAll(res.Body)
@@ -327,11 +450,12 @@ func (c *ObsClient) GetProjectMeta(project string) (*ProjectMeta, error) {
return nil, err
}
defer res.Body.Close()
return parseProjectMeta(data)
}
func (c *ObsClient) GetPackageMeta(project, pkg string) (*PackageMeta, error) {
res, err := c.ObsRequest("GET", c.baseUrl.JoinPath("source", project, pkg, "_meta").String(), nil)
res, err := c.ObsRequest("GET", []string{"source", project, pkg, "_meta"}, nil)
if err != nil {
return nil, err
@@ -350,6 +474,7 @@ func (c *ObsClient) GetPackageMeta(project, pkg string) (*PackageMeta, error) {
if err != nil {
return nil, err
}
defer res.Body.Close()
var meta PackageMeta
err = xml.Unmarshal(data, &meta)
@@ -404,10 +529,11 @@ func (c *ObsClient) SetProjectMeta(meta *ProjectMeta) error {
return err
}
res, err := c.ObsRequest("PUT", c.baseUrl.JoinPath("source", meta.Name, "_meta").String(), io.NopCloser(bytes.NewReader(xml)))
res, err := c.ObsRequest("PUT", []string{"source", meta.Name, "_meta"}, io.NopCloser(bytes.NewReader(xml)))
if err != nil {
return err
}
defer res.Body.Close()
switch res.StatusCode {
case 200:
@@ -420,10 +546,15 @@ func (c *ObsClient) SetProjectMeta(meta *ProjectMeta) error {
}
func (c *ObsClient) DeleteProject(project string) error {
res, err := c.ObsRequest("DELETE", c.baseUrl.JoinPath("source", project).String(), nil)
url := c.baseUrl.JoinPath("source", project)
query := url.Query()
query.Add("force", "1")
url.RawQuery = query.Encode()
res, err := c.ObsRequestRaw("DELETE", url.String(), nil)
if err != nil {
return err
}
defer res.Body.Close()
if res.StatusCode != 200 {
return fmt.Errorf("Unexpected return code: %d", res.StatusCode)
@@ -445,6 +576,8 @@ type BuildResult struct {
Arch string `xml:"arch,attr"`
Code string `xml:"code,attr"`
Dirty bool `xml:"dirty,attr"`
ScmSync string `xml:"scmsync"`
ScmInfo string `xml:"scminfo"`
Status []PackageBuildStatus `xml:"status"`
Binaries []BinaryList `xml:"binarylist"`
}
@@ -462,20 +595,27 @@ type BinaryList struct {
type BuildResultList struct {
XMLName xml.Name `xml:"resultlist"`
State string `xml:"state,attr"`
Result []BuildResult `xml:"result"`
isLastBuild bool
}
func (r *BuildResultList) GetPackageList() []string {
pkgList := make([]string, 0, 16)
for _, res := range r.Result {
// TODO: enough to iterate over one result set?
pkgList := make([]string, 0, 3*len(r.Result[0].Status)/2)
for ridx, res := range r.Result {
for _, status := range res.Status {
if !slices.Contains(pkgList, status.Package) {
if ridx == 0 {
pkgList = append(pkgList, status.Package)
} else if idx, found := slices.BinarySearch(pkgList, status.Package); !found {
pkgList = slices.Insert(pkgList, idx, status.Package)
}
}
if ridx == 0 {
slices.Sort(pkgList)
}
}
return pkgList
@@ -483,7 +623,7 @@ func (r *BuildResultList) GetPackageList() []string {
func (r *BuildResultList) BuildResultSummary() (success, finished bool) {
if r == nil {
return true, true
return false, false
}
finished = len(r.Result) > 0 && len(r.Result[0].Status) > 0
@@ -496,7 +636,7 @@ func (r *BuildResultList) BuildResultSummary() (success, finished bool) {
panic("Unknown repo result code: " + resultSet.Code)
}
finished = repoDetail.Finished
finished = r.isLastBuild || repoDetail.Finished
if !finished || resultSet.Dirty {
return
}
@@ -507,6 +647,11 @@ func (r *BuildResultList) BuildResultSummary() (success, finished bool) {
if !ok {
panic("Unknown result code: " + result.Code)
}
if r.isLastBuild && result.Code == "unknown" {
// it means the package has never build yet,
// but we don't know the reason
detail.Finished = true
}
finished = finished && detail.Finished
success = success && detail.Success
@@ -602,9 +747,14 @@ var ObsBuildStatusDetails map[string]ObsBuildStatusDetail = map[string]ObsBuildS
},
"unknown": ObsBuildStatusDetail{
Code: "unknown",
Description: "The scheduler has not yet evaluated this package. Should be a short intermediate state for new packages.",
Description: "The scheduler has not yet evaluated this package. Should be a short intermediate state for new packages. When used for lastbuild state it means it was never possible to attempt a build",
Finished: false,
},
"error": ObsBuildStatusDetail{
Code: "Error",
Description: "Unknown status code",
},
}
var ObsRepoStatusDetails map[string]ObsBuildStatusDetail = map[string]ObsBuildStatusDetail{
// repo status
@@ -674,14 +824,13 @@ func (obs ObsProjectNotFound) Error() string {
}
func (c *ObsClient) ProjectConfig(project string) (string, error) {
u := c.baseUrl.JoinPath("source", project, "_config")
res, err := c.ObsRequest("GET", u.String(), nil)
res, err := c.ObsRequest("GET", []string{"source", project, "_config"}, nil)
if err != nil {
return "", err
}
if data, err := io.ReadAll(res.Body); err == nil {
defer res.Body.Close()
return string(data), nil
} else {
return "", err
@@ -689,19 +838,34 @@ func (c *ObsClient) ProjectConfig(project string) (string, error) {
}
func (c *ObsClient) BuildStatus(project string, packages ...string) (*BuildResultList, error) {
return c.BuildStatusWithState(project, &BuildResultOptions{}, packages...)
}
func (c *ObsClient) LastBuildResults(project string, packages ...string) (*BuildResultList, error) {
return c.BuildStatusWithState(project, &BuildResultOptions{LastBuild: true}, packages...)
}
func (c *ObsClient) BuildStatusWithState(project string, opts *BuildResultOptions, packages ...string) (*BuildResultList, error) {
u := c.baseUrl.JoinPath("build", project, "_result")
query := u.Query()
query.Add("view", "status")
query.Add("view", "binarylist")
if opts.BinaryList {
query.Add("view", "binarylist")
}
query.Add("multibuild", "1")
if len(packages) > 0 {
if len(opts.OldState) > 0 {
query.Add("oldstate", opts.OldState)
}
if opts.LastBuild {
query.Add("lastbuild", "1")
}
if len(packages) > 0 {
for _, pkg := range packages {
query.Add("package", pkg)
}
}
u.RawQuery = query.Encode()
res, err := c.ObsRequest("GET", u.String(), nil)
res, err := c.ObsRequestRaw("GET", u.String(), nil)
if err != nil {
return nil, err
}
@@ -719,5 +883,10 @@ func (c *ObsClient) BuildStatus(project string, packages ...string) (*BuildResul
if err != nil {
return nil, err
}
return parseBuildResults(data)
defer res.Body.Close()
ret, err := parseBuildResults(data)
if ret != nil {
ret.isLastBuild = opts.LastBuild
}
return ret, err
}

View File

@@ -55,6 +55,52 @@ func TestParsingOfBuildResults(t *testing.T) {
}
}
func TestParsingRequestResults(t *testing.T) {
res, err := parseRequestXml([]byte(metaRequestData))
if err != nil {
t.Fatal(err)
}
if res.Id != 42 ||
res.Action.Source.Project != "home:foo-user" ||
res.Action.Source.Package != "obs-server" ||
*res.Action.Source.Revision != "521e" ||
res.Action.Target.Project != "OBS:Unstable" ||
res.Action.Target.Revision != nil {
t.Fatal(res)
}
}
const metaRequestData = `<?xml version="1.0" encoding="UTF-8"?>
<request id="42" creator="foo-user">
<action type="submit">
<source project="home:foo-user" package="obs-server" rev="521e">
</source>
<target project="OBS:Unstable" package="obs-server">
</target>
<options>
<sourceupdate>cleanup</sourceupdate>
</options>
</action>
<state name="accepted" who="bar-user" when="2021-01-15T13:39:43">
<comment>allright</comment>
</state>
<review state="accepted" when="2021-01-15T15:49:32" who="obs-maintainer" by_user="obs-maintainer">
</review>
<review state="accepted" when="2021-01-15T15:49:32" who="obs-maintainer" by_group="obs-group">
</review>
<review state="accepted" when="2021-01-15T15:49:32" who="obs-maintainer" by_project="OBS:Unstable">
</review>
<review state="accepted" when="2021-01-15T15:49:32" who="obs-maintainer" by_package="obs-server">
</review>
<history who="foo" when="2021-01-15T13:39:43">
<description>Request created</description>
<comment>Please review sources</comment>
</history>
<description>A little version update</description>
</request>`
const metaPrjData = `
<project name="home:adamm">
<title>Adam's Home Projects</title>

View File

@@ -13,25 +13,29 @@ import (
)
type PRInfo struct {
PR *models.PullRequest
Reviews *PRReviews
PR *models.PullRequest
Reviews *PRReviews
RemoteName string
}
type PRSet struct {
PRs []PRInfo
PRs []*PRInfo
Config *AutogitConfig
BotUser string
}
func readPRData(gitea GiteaPRFetcher, pr *models.PullRequest, currentSet []PRInfo, config *AutogitConfig) ([]PRInfo, error) {
func readPRData(gitea GiteaPRFetcher, pr *models.PullRequest, currentSet []*PRInfo, config *AutogitConfig) ([]*PRInfo, error) {
for _, p := range currentSet {
if pr.Index == p.PR.Index && pr.Base.Repo.Name == p.PR.Base.Repo.Name && pr.Base.Repo.Owner.UserName == p.PR.Base.Repo.Owner.UserName {
return nil, nil
}
}
retSet := []PRInfo{PRInfo{PR: pr}}
retSet := []*PRInfo{&PRInfo{PR: pr}}
// only need to extact there on PrjGit PR
if pr.Base.Repo.Name == config.GitProjectName && pr.Base.Repo.Owner.UserName == config.Organization {
org, repo, _ := config.GetPrjGit()
if pr.Base.Repo.Name == repo && pr.Base.Repo.Owner.UserName == org {
_, refPRs := ExtractDescriptionAndPRs(bufio.NewScanner(strings.NewReader(pr.Body)))
for _, prdata := range refPRs {
pr, err := gitea.GetPullRequest(prdata.Org, prdata.Repo, prdata.Num)
@@ -49,12 +53,52 @@ func readPRData(gitea GiteaPRFetcher, pr *models.PullRequest, currentSet []PRInf
return retSet, nil
}
func FetchPRSet(gitea GiteaPRFetcher, org, repo string, num int64, config *AutogitConfig) (*PRSet, error) {
var Timeline_RefIssueNotFound error = errors.New("RefIssue not found on the timeline")
func LastPrjGitRefOnTimeline(gitea GiteaPRTimelineFetcher, org, repo string, num int64, prjGitOrg, prjGitRepo string) (*models.PullRequest, error) {
prRefLine := fmt.Sprintf(PrPattern, org, repo, num)
timeline, err := gitea.GetTimeline(org, repo, num)
if err != nil {
LogError("Failed to fetch timeline for", org, repo, "#", num, err)
return nil, err
}
for idx := len(timeline) - 1; idx >= 0; idx-- {
item := timeline[idx]
issue := item.RefIssue
if item.Type == TimelineCommentType_PullRequestRef &&
issue != nil &&
issue.Repository != nil &&
issue.Repository.Owner == prjGitOrg &&
issue.Repository.Name == prjGitRepo {
lines := SplitLines(item.RefIssue.Body)
for _, line := range lines {
if strings.TrimSpace(line) == prRefLine {
LogDebug("Found PrjGit PR in Timeline:", issue.Index)
// found prjgit PR in timeline. Return it
return gitea.GetPullRequest(prjGitOrg, prjGitRepo, issue.Index)
}
}
}
}
LogDebug("PrjGit RefIssue not found on timeline in", org, repo, num)
return nil, Timeline_RefIssueNotFound
}
func FetchPRSet(user string, gitea GiteaPRTimelineFetcher, org, repo string, num int64, config *AutogitConfig) (*PRSet, error) {
var pr *models.PullRequest
var err error
if org != config.Organization || repo != config.GitProjectName {
if pr, err = gitea.GetAssociatedPrjGitPR(config.Organization, config.GitProjectName, org, repo, num); err != nil {
prjGitOrg, prjGitRepo, _ := config.GetPrjGit()
if prjGitOrg == org && prjGitRepo == repo {
if pr, err = gitea.GetPullRequest(org, repo, num); err != nil {
return nil, err
}
} else {
if pr, err = LastPrjGitRefOnTimeline(gitea, org, repo, num, prjGitOrg, prjGitRepo); err != nil && err != Timeline_RefIssueNotFound {
return nil, err
}
@@ -63,10 +107,6 @@ func FetchPRSet(gitea GiteaPRFetcher, org, repo string, num int64, config *Autog
return nil, err
}
}
} else {
if pr, err = gitea.GetPullRequest(org, repo, num); err != nil {
return nil, err
}
}
prs, err := readPRData(gitea, pr, nil, config)
@@ -74,22 +114,53 @@ func FetchPRSet(gitea GiteaPRFetcher, org, repo string, num int64, config *Autog
return nil, err
}
return &PRSet{PRs: prs, Config: config}, nil
return &PRSet{
PRs: prs,
Config: config,
BotUser: user,
}, nil
}
func (rs *PRSet) Contains(pr *models.PullRequest) bool {
for _, p := range rs.PRs {
if p.PR.Base.RepoID == pr.Base.RepoID &&
p.PR.Head.Sha == pr.Head.Sha &&
p.PR.Base.Name == pr.Base.Name {
return true
}
}
return false
}
func (rs *PRSet) AddPR(pr *models.PullRequest) error {
if rs.Contains(pr) {
return nil
}
rs.PRs = append(rs.PRs, &PRInfo{
PR: pr,
})
return nil
}
func (rs *PRSet) IsPrjGitPR(pr *models.PullRequest) bool {
return pr.Base.Repo.Name == rs.Config.GitProjectName && pr.Base.Repo.Owner.UserName == rs.Config.Organization
org, repo, branch := rs.Config.GetPrjGit()
return pr.Base.Name == branch && pr.Base.Repo.Name == repo && pr.Base.Repo.Owner.UserName == org
}
func (rs *PRSet) GetPrjGitPR() (*models.PullRequest, error) {
var ret *models.PullRequest
var PRSet_PrjGitMissing error = errors.New("No PrjGit PR found")
var PRSet_MultiplePrjGit error = errors.New("Multiple PrjGit PRs in one review set")
func (rs *PRSet) GetPrjGitPR() (*PRInfo, error) {
var ret *PRInfo
for _, prinfo := range rs.PRs {
if rs.IsPrjGitPR(prinfo.PR) {
if ret == nil {
ret = prinfo.PR
ret = prinfo
} else {
return nil, errors.New("Multiple PrjGit PRs in one review set")
return nil, PRSet_MultiplePrjGit
}
}
}
@@ -98,21 +169,28 @@ func (rs *PRSet) GetPrjGitPR() (*models.PullRequest, error) {
return ret, nil
}
return nil, errors.New("No PrjGit PR found")
return nil, PRSet_PrjGitMissing
}
func (rs *PRSet) IsConsistent() bool {
prjpr, err := rs.GetPrjGitPR()
prjpr_info, err := rs.GetPrjGitPR()
if err != nil {
return false
}
prjpr := prjpr_info.PR
_, prjpr_set := ExtractDescriptionAndPRs(bufio.NewScanner(strings.NewReader(prjpr.Body)))
if len(prjpr_set) != len(rs.PRs)-1 { // 1 to many mapping
LogDebug("Number of PR from links:", len(prjpr_set), "is not what's expected", len(rs.PRs)-1)
return false
}
next_rs:
for _, prinfo := range rs.PRs {
if prinfo.PR.State != "open" {
return false
}
if prjpr == prinfo.PR {
continue
}
@@ -132,24 +210,33 @@ func (rs *PRSet) AssignReviewers(gitea GiteaReviewFetcherAndRequester, maintaine
for _, pr := range rs.PRs {
reviewers := []string{}
if rs.IsPrjGitPR(pr.PR) {
reviewers = configReviewers.Prj
reviewers = slices.Concat(configReviewers.Prj, configReviewers.PrjOptional)
LogDebug("PrjGit submitter:", pr.PR.User.UserName)
if len(rs.PRs) == 1 {
reviewers = slices.Concat(reviewers, maintainers.ListProjectMaintainers())
}
} else {
pkg := pr.PR.Base.Repo.Name
reviewers = slices.Concat(configReviewers.Pkg, maintainers.ListProjectMaintainers(), maintainers.ListPackageMaintainers(pkg))
reviewers = slices.Concat(configReviewers.Pkg, maintainers.ListProjectMaintainers(), maintainers.ListPackageMaintainers(pkg), configReviewers.PkgOptional)
}
slices.Sort(reviewers)
reviewers = slices.Compact(reviewers)
// submitters do not need to review their own work
if idx := slices.Index(reviewers, pr.PR.User.UserName); idx != -1 {
reviewers = slices.Delete(reviewers, idx, idx+1)
}
LogDebug("PR: ", pr.PR.Base.Repo.Name, pr.PR.Index)
LogDebug("reviewers for PR:", reviewers)
// remove reviewers that were already requested and are not stale
reviews, err := FetchGiteaReviews(gitea, reviewers, pr.PR.Base.Repo.Owner.UserName, pr.PR.Base.Repo.Name, pr.PR.Index)
if err != nil {
LogError("Error fetching reviews:", err)
return err
}
@@ -157,6 +244,7 @@ func (rs *PRSet) AssignReviewers(gitea GiteaReviewFetcherAndRequester, maintaine
user := reviewers[idx]
if reviews.HasPendingReviewBy(user) || reviews.IsReviewedBy(user) {
reviewers = slices.Delete(reviewers, idx, idx+1)
LogDebug("removing reviewer:", user)
} else {
idx++
}
@@ -164,8 +252,13 @@ func (rs *PRSet) AssignReviewers(gitea GiteaReviewFetcherAndRequester, maintaine
// get maintainers associated with the PR too
if len(reviewers) > 0 {
if _, err := gitea.RequestReviews(pr.PR, reviewers...); err != nil {
return fmt.Errorf("Cannot create reviews on %s/%s#%d for [%s]: %w", pr.PR.Base.Repo.Owner.UserName, pr.PR.Base.Repo.Name, pr.PR.Index, strings.Join(reviewers, ", "), err)
LogDebug("Requesting reviews from:", reviewers)
if !IsDryRun {
for _, r := range reviewers {
if _, err := gitea.RequestReviews(pr.PR, r); err != nil {
LogError("Cannot create reviews on", fmt.Sprintf("%s/%s#%d for [%s]", pr.PR.Base.Repo.Owner.UserName, pr.PR.Base.Repo.Name, pr.PR.Index, strings.Join(reviewers, ", ")), err)
}
}
}
}
}
@@ -175,7 +268,54 @@ func (rs *PRSet) AssignReviewers(gitea GiteaReviewFetcherAndRequester, maintaine
func (rs *PRSet) IsApproved(gitea GiteaPRChecker, maintainers MaintainershipData) bool {
configReviewers := ParseReviewers(rs.Config.Reviewers)
is_reviewed := false
is_manually_reviewed_ok := false
if need_manual_review := rs.Config.ManualMergeOnly || rs.Config.ManualMergeProject; need_manual_review {
prjgit, err := rs.GetPrjGitPR()
if err == nil && prjgit != nil {
reviewers := slices.Concat(configReviewers.Prj, maintainers.ListProjectMaintainers())
LogDebug("Fetching reviews for", prjgit.PR.Base.Repo.Owner.UserName, prjgit.PR.Base.Repo.Name, prjgit.PR.Index)
r, err := FetchGiteaReviews(gitea, reviewers, prjgit.PR.Base.Repo.Owner.UserName, prjgit.PR.Base.Repo.Name, prjgit.PR.Index)
if err != nil {
LogError("Cannot fetch gita reaviews for PR:", err)
return false
}
prjgit.Reviews = r
if prjgit.Reviews.IsManualMergeOK() {
is_manually_reviewed_ok = true
}
}
if !is_manually_reviewed_ok && !rs.Config.ManualMergeProject {
for _, pr := range rs.PRs {
if rs.IsPrjGitPR(pr.PR) {
continue
}
pkg := pr.PR.Base.Repo.Name
reviewers := slices.Concat(configReviewers.Pkg, maintainers.ListPackageMaintainers(pkg))
LogDebug("Fetching reviews for", pr.PR.Base.Repo.Owner.UserName, pr.PR.Base.Repo.Name, pr.PR.Index)
r, err := FetchGiteaReviews(gitea, reviewers, pr.PR.Base.Repo.Owner.UserName, pr.PR.Base.Repo.Name, pr.PR.Index)
if err != nil {
LogError("Cannot fetch gita reaviews for PR:", err)
return false
}
pr.Reviews = r
if !pr.Reviews.IsManualMergeOK() {
LogInfo("Not approved manual merge")
return false
}
}
is_manually_reviewed_ok = true
}
if !is_manually_reviewed_ok {
LogInfo("manual merge not ok")
return false
}
}
for _, pr := range rs.PRs {
var reviewers []string
var pkg string
@@ -187,48 +327,60 @@ func (rs *PRSet) IsApproved(gitea GiteaPRChecker, maintainers MaintainershipData
pkg = pr.PR.Base.Repo.Name
}
if strings.HasPrefix(pr.PR.Title, "WIP:") {
LogInfo("WIP PR. Ignoring")
return false
}
r, err := FetchGiteaReviews(gitea, reviewers, pr.PR.Base.Repo.Owner.UserName, pr.PR.Base.Repo.Name, pr.PR.Index)
if err != nil {
return false
}
is_reviewed = r.IsApproved()
if !is_reviewed {
LogError("Cannot fetch gita reaviews for PR:", err)
return false
}
if is_reviewed = maintainers.IsApproved(pkg, r.reviews); !is_reviewed {
is_manually_reviewed_ok = r.IsApproved()
LogDebug(pr.PR.Base.Repo.Name, is_manually_reviewed_ok)
if !is_manually_reviewed_ok {
return false
}
if need_maintainer_review := !rs.IsPrjGitPR(pr.PR) || pr.PR.User.UserName != rs.BotUser; need_maintainer_review {
if is_manually_reviewed_ok = maintainers.IsApproved(pkg, r.reviews, pr.PR.User.UserName); !is_manually_reviewed_ok {
LogDebug(" not approved?", pkg)
return false
}
} else {
LogDebug("PrjGit PR -- bot created, no need for review")
}
}
return is_reviewed
return is_manually_reviewed_ok
}
func (rs *PRSet) Merge(author, email string) error {
prjgit, err := rs.GetPrjGitPR()
func (rs *PRSet) Merge(gitea GiteaReviewUnrequester, git Git) error {
prjgit_info, err := rs.GetPrjGitPR()
if err != nil {
return err
}
prjgit := prjgit_info.PR
gh := GitHandlerGeneratorImpl{}
git, err := gh.CreateGitHandler(author, email, prjgit.Base.Name)
if err != nil {
return err
}
git.GitExecOrPanic("", "clone", "--depth", "1", prjgit.Base.Repo.SSHURL, DefaultGitPrj)
git.GitExecOrPanic(DefaultGitPrj, "fetch", "origin", prjgit.Base.Sha, prjgit.Head.Sha)
remote, err := git.GitClone(DefaultGitPrj, rs.Config.Branch, prjgit.Base.Repo.SSHURL)
PanicOnError(err)
git.GitExecOrPanic(DefaultGitPrj, "fetch", remote, prjgit.Head.Sha)
// if other changes merged, check if we have conflicts
rev := strings.TrimSpace(git.GitExecWithOutputOrPanic(DefaultGitPrj, "merge-base", "HEAD", prjgit.Base.Sha, prjgit.Head.Sha))
if rev != prjgit.Base.Sha {
return fmt.Errorf("Base.Sha (%s) not yet merged into project-git. Aborting merge.", prjgit.Base.Sha)
}
/*
rev := strings.TrimSpace(git.GitExecWithOutputOrPanic(DefaultGitPrj, "merge-base", "HEAD", prjgit.Base.Sha, prjgit.Head.Sha))
if rev != prjgit.Base.Sha {
return fmt.Errorf("Base.Sha (%s) not yet merged into project-git. Aborting merge.", prjgit.Base.Sha)
}
*/
/*
rev := git.GitExecWithOutputOrPanic(common.DefaultGitPrj, "rev-list", "-1", "HEAD")
if rev != prjgit.Base.Sha {
panic("FIXME")
}
*/
msg := "merging"
msg := fmt.Sprintf("Merging\n\nPR: %s/%s#%d", prjgit.Base.Repo.Owner.UserName, prjgit.Base.Repo.Name, prjgit.Index)
err = git.GitExec(DefaultGitPrj, "merge", "--no-ff", "-m", msg, prjgit.Head.Sha)
if err != nil {
@@ -302,31 +454,58 @@ func (rs *PRSet) Merge(author, email string) error {
return fmt.Errorf("Can't close .gitmodules: %w", err)
}
os.CopyFS("/tmp/test", os.DirFS(git.GetPath()))
git.GitExecOrPanic(DefaultGitPrj, "add", ".gitmodules")
git.GitExecOrPanic(DefaultGitPrj, "-c", "core.editor=true", "merge", "--continue")
}
}
}
// FF all non-prj git
// FF all non-prj git and unrequest reviews.
for _, prinfo := range rs.PRs {
// remove pending review requests
repo := prinfo.PR.Base.Repo
head := prinfo.PR.Head
id := prinfo.PR.Index
reviewers := make([]string, len(prinfo.PR.RequestedReviewers))
for idx := range prinfo.PR.RequestedReviewers {
r := prinfo.PR.RequestedReviewers[idx]
if r != nil {
reviewers[idx] = r.UserName
}
}
if err := gitea.UnrequestReview(repo.Owner.UserName, repo.Name, id, reviewers...); err != nil {
LogError("Cannot unrequest reviews in PR:", repo.Owner.UserName, repo.Name, id, reviewers, ": ", err)
}
// PrjGit already merged above, so skip here.
if rs.IsPrjGitPR(prinfo.PR) {
continue
}
git.GitExecOrPanic("", "clone", prinfo.PR.Base.Repo.SSHURL, prinfo.PR.Base.Name)
git.GitExecOrPanic(prinfo.PR.Base.Name, "fetch", "origin", prinfo.PR.Head.Sha)
git.GitExecOrPanic(prinfo.PR.Base.Name, "merge", "--ff", prinfo.PR.Head.Sha)
prinfo.RemoteName, err = git.GitClone(repo.Name, rs.Config.Branch, repo.SSHURL)
PanicOnError(err)
git.GitExecOrPanic(repo.Name, "fetch", prinfo.RemoteName, head.Sha)
git.GitExecOrPanic(repo.Name, "merge", "--ff", head.Sha)
}
// push changes
git.GitExecOrPanic(DefaultGitPrj, "push", "origin")
if !IsDryRun {
git.GitExecOrPanic(DefaultGitPrj, "push", remote)
} else {
LogInfo("*** WOULD push", DefaultGitPrj, "changes to", remote)
}
for _, prinfo := range rs.PRs {
if rs.IsPrjGitPR(prinfo.PR) {
continue
}
git.GitExecOrPanic(prinfo.PR.Base.Name, "push", "origin")
repo := prinfo.PR.Base.Repo
if !IsDryRun {
git.GitExecOrPanic(repo.Name, "push", prinfo.RemoteName)
} else {
LogInfo("*** WOULD push", repo.Name, "to", prinfo.RemoteName)
}
}
return nil

View File

@@ -6,6 +6,7 @@ import (
"os"
"os/exec"
"path"
"slices"
"strings"
"testing"
@@ -15,6 +16,21 @@ import (
mock_common "src.opensuse.org/autogits/common/mock"
)
func reviewsToTimeline(reviews []*models.PullReview) []*models.TimelineComment {
timeline := make([]*models.TimelineComment, len(reviews))
for idx, review := range reviews {
if review.ID == 0 {
review.ID = int64(idx) + 100
}
timeline[idx] = &models.TimelineComment{
Type: common.TimelineCommentType_Review,
ReviewID: review.ID,
}
}
return timeline
}
func TestPR(t *testing.T) {
baseConfig := common.AutogitConfig{
Reviewers: []string{"+super1", "*super2", "m1", "-m2"},
@@ -27,6 +43,7 @@ func TestPR(t *testing.T) {
pr *models.PullRequest
pr_err error
reviews []*models.PullReview
timeline []*models.TimelineComment
review_error error
}
@@ -40,26 +57,26 @@ func TestPR(t *testing.T) {
consistentSet bool
prjGitPRIndex int
reviewSetFetcher func(*mock_common.MockGiteaPRFetcher) (*common.PRSet, error)
reviewSetFetcher func(*mock_common.MockGiteaPRTimelineFetcher) (*common.PRSet, error)
}{
{
name: "Error fetching PullRequest",
data: []prdata{
{pr: &models.PullRequest{Body: "", Index: 42, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "repo", Owner: &models.User{UserName: "test"}}}}, pr_err: errors.New("Missing PR")},
{pr: &models.PullRequest{Body: "", Index: 42, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "repo", Owner: &models.User{UserName: "test"}}}, State: "opened"}, pr_err: errors.New("Missing PR")},
},
prjGitPRIndex: -1,
},
{
name: "Error fetching PullRequest in PrjGit",
data: []prdata{
{pr: &models.PullRequest{Body: "PR: foo/barPrj#22", Index: 42, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "repo", Owner: &models.User{UserName: "test"}}}}, pr_err: errors.New("missing PR")},
{pr: &models.PullRequest{Body: "", Index: 22, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "barPrj", Owner: &models.User{UserName: "foo"}}}}},
{pr: &models.PullRequest{Body: "PR: foo/barPrj#22", Index: 42, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "repo", Owner: &models.User{UserName: "test"}}}, State: "opened"}, pr_err: errors.New("missing PR")},
{pr: &models.PullRequest{Body: "", Index: 22, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "barPrj", Owner: &models.User{UserName: "foo"}}}, State: "opened"}},
},
},
{
name: "Error fetching prjgit",
data: []prdata{
{pr: &models.PullRequest{Body: "", Index: 42, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "repo", Owner: &models.User{UserName: "test"}}}}},
{pr: &models.PullRequest{Body: "", Index: 42, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "repo", Owner: &models.User{UserName: "test"}}}, State: "opened"}},
},
resLen: 1,
prjGitPRIndex: -1,
@@ -67,8 +84,8 @@ func TestPR(t *testing.T) {
{
name: "Review set is consistent",
data: []prdata{
{pr: &models.PullRequest{Body: "", Index: 42, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "repo", Owner: &models.User{UserName: "test"}}}}},
{pr: &models.PullRequest{Body: "PR: test/repo#42", Index: 22, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "barPrj", Owner: &models.User{UserName: "foo"}}}}},
{pr: &models.PullRequest{Body: "", Index: 42, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "repo", Owner: &models.User{UserName: "test"}}}, State: "opened"}},
{pr: &models.PullRequest{Body: "PR: test/repo#42", Index: 22, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "barPrj", Owner: &models.User{UserName: "foo"}}}, State: "opened"}},
},
resLen: 2,
prjGitPRIndex: 1,
@@ -78,8 +95,8 @@ func TestPR(t *testing.T) {
{
name: "Review set is consistent: 1pkg",
data: []prdata{
{pr: &models.PullRequest{Body: "PR: foo/barPrj#22", Index: 42, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "repo", Owner: &models.User{UserName: "test"}}}}},
{pr: &models.PullRequest{Body: "PR: test/repo#42", Index: 22, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "barPrj", Owner: &models.User{UserName: "foo"}}}}},
{pr: &models.PullRequest{Body: "PR: foo/barPrj#22", Index: 42, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "repo", Owner: &models.User{UserName: "test"}}}, State: "opened"}},
{pr: &models.PullRequest{Body: "PR: test/repo#42", Index: 22, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "barPrj", Owner: &models.User{UserName: "foo"}}}, State: "opened"}},
},
resLen: 2,
prjGitPRIndex: 1,
@@ -88,9 +105,9 @@ func TestPR(t *testing.T) {
{
name: "Review set is consistent: 2pkg",
data: []prdata{
{pr: &models.PullRequest{Body: "some desc", Index: 42, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "repo", Owner: &models.User{UserName: "test"}}}}},
{pr: &models.PullRequest{Body: "PR: test/repo#42\nPR: test/repo2#41", Index: 22, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "barPrj", Owner: &models.User{UserName: "foo"}}}}},
{pr: &models.PullRequest{Body: "some other desc\nPR: foo/fer#33", Index: 41, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "repo2", Owner: &models.User{UserName: "test"}}}}},
{pr: &models.PullRequest{Body: "some desc", Index: 42, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "repo", Owner: &models.User{UserName: "test"}}}, State: "opened"}},
{pr: &models.PullRequest{Body: "PR: test/repo#42\nPR: test/repo2#41", Index: 22, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "barPrj", Owner: &models.User{UserName: "foo"}}}, State: "opened"}},
{pr: &models.PullRequest{Body: "some other desc\nPR: foo/fer#33", Index: 41, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "repo2", Owner: &models.User{UserName: "test"}}}, State: "opened"}},
},
resLen: 3,
prjGitPRIndex: 1,
@@ -100,7 +117,7 @@ func TestPR(t *testing.T) {
name: "Review set of prjgit PR is consistent",
data: []prdata{
{
pr: &models.PullRequest{Body: "", Index: 42, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "barPrj", Owner: &models.User{UserName: "foo"}}}},
pr: &models.PullRequest{Body: "", Index: 42, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "barPrj", Owner: &models.User{UserName: "foo"}}}, User: &models.User{UserName: "submitter"}, State: "opened"},
reviews: []*models.PullReview{
{Body: "LGTM", User: &models.User{UserName: "m2"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: "super2"}, State: common.ReviewStateApproved},
@@ -112,38 +129,385 @@ func TestPR(t *testing.T) {
prjGitPRIndex: 0,
consistentSet: true,
reviewed: true,
reviewSetFetcher: func(mock *mock_common.MockGiteaPRFetcher) (*common.PRSet, error) {
return common.FetchPRSet(mock, "foo", "barPrj", 42, &baseConfig)
reviewSetFetcher: func(mock *mock_common.MockGiteaPRTimelineFetcher) (*common.PRSet, error) {
return common.FetchPRSet("test", mock, "foo", "barPrj", 42, &baseConfig)
},
},
{
name: "Review set is consistent: 2pkg",
data: []prdata{
{pr: &models.PullRequest{Body: "PR: foo/barPrj#222", Index: 42, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "repo", Owner: &models.User{UserName: "test"}}}}},
{pr: &models.PullRequest{Body: "PR: test/repo2#41", Index: 20, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "barPrj", Owner: &models.User{UserName: "foo"}}}}},
{pr: &models.PullRequest{Body: "PR: test/repo#42\nPR: test/repo2#41", Index: 22, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "barPrj", Owner: &models.User{UserName: "foo"}}}}},
{pr: &models.PullRequest{Body: "PR: foo/barPrj#20", Index: 41, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "repo2", Owner: &models.User{UserName: "test"}}}}},
{pr: &models.PullRequest{Body: "PR: foo/barPrj#222", Index: 42, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "repo", Owner: &models.User{UserName: "test"}}}, State: "opened"}},
{pr: &models.PullRequest{Body: "PR: test/repo2#41", Index: 20, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "barPrj", Owner: &models.User{UserName: "foo"}}}, State: "opened"}},
{pr: &models.PullRequest{Body: "PR: test/repo#42\nPR: test/repo2#41", Index: 22, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "barPrj", Owner: &models.User{UserName: "foo"}}}, State: "opened"}},
{pr: &models.PullRequest{Body: "PR: foo/barPrj#20", Index: 41, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "repo2", Owner: &models.User{UserName: "test"}}}, State: "opened"}},
},
resLen: 3,
prjGitPRIndex: 2,
consistentSet: true,
},
{
name: "WIP PR is not approved",
data: []prdata{
{
pr: &models.PullRequest{Body: "", Title: "WIP: some title", Index: 42, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "barPrj", Owner: &models.User{UserName: "foo"}}}, User: &models.User{UserName: "submitter"}, State: "opened"},
reviews: []*models.PullReview{
{Body: "LGTM", User: &models.User{UserName: "m2"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: "super2"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: common.Bot_BuildReview}, State: common.ReviewStateApproved},
},
},
},
resLen: 1,
prjGitPRIndex: 0,
consistentSet: true,
reviewed: false,
reviewSetFetcher: func(mock *mock_common.MockGiteaPRTimelineFetcher) (*common.PRSet, error) {
return common.FetchPRSet("test", mock, "foo", "barPrj", 42, &baseConfig)
},
},
{
name: "Manual review is missing",
data: []prdata{
{
pr: &models.PullRequest{Body: "PR: foo/repo#20", Index: 42, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "barPrj", Owner: &models.User{UserName: "foo"}}}, User: &models.User{UserName: "submitter"}, State: "opened"},
reviews: []*models.PullReview{
{Body: "LGTM", User: &models.User{UserName: "m2"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: "super2"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: common.Bot_BuildReview}, State: common.ReviewStateApproved},
},
},
{
pr: &models.PullRequest{Body: "PR: foo/barPrj#42", Index: 20, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "repo", Owner: &models.User{UserName: "foo"}}}, User: &models.User{UserName: "submitter"}, State: "opened"},
reviews: []*models.PullReview{
{Body: "LGTM", User: &models.User{UserName: "m1"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: "super1"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: "super2"}, State: common.ReviewStateApproved},
},
},
},
resLen: 2,
prjGitPRIndex: 0,
consistentSet: true,
reviewed: false,
reviewSetFetcher: func(mock *mock_common.MockGiteaPRTimelineFetcher) (*common.PRSet, error) {
return common.FetchPRSet("test", mock, "foo", "barPrj", 42, &common.AutogitConfig{
Reviewers: []string{"+super1", "*super2", "m1", "-m2"},
Branch: "branch",
Organization: "foo",
GitProjectName: "barPrj",
ManualMergeOnly: true,
})
},
},
{
name: "Manual review is done, via PrjGit",
data: []prdata{
{
pr: &models.PullRequest{Body: "PR: foo/repo#20", Index: 42, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "barPrj", Owner: &models.User{UserName: "foo"}}}, User: &models.User{UserName: "submitter"}, State: "opened"},
reviews: []*models.PullReview{
{Body: "merge ok", User: &models.User{UserName: "m2"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: "super2"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: common.Bot_BuildReview}, State: common.ReviewStateApproved},
},
},
{
pr: &models.PullRequest{Body: "PR: foo/barPrj#42", Index: 20, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "repo", Owner: &models.User{UserName: "foo"}}}, User: &models.User{UserName: "submitter"}, State: "opened"},
reviews: []*models.PullReview{
{Body: "LGTM", User: &models.User{UserName: "m1"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: "super1"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: "super2"}, State: common.ReviewStateApproved},
},
},
},
resLen: 2,
prjGitPRIndex: 0,
consistentSet: true,
reviewed: true,
reviewSetFetcher: func(mock *mock_common.MockGiteaPRTimelineFetcher) (*common.PRSet, error) {
return common.FetchPRSet("test", mock, "foo", "barPrj", 42, &common.AutogitConfig{
Reviewers: []string{"+super1", "*super2", "m1", "-m2"},
Branch: "branch",
Organization: "foo",
GitProjectName: "barPrj",
ManualMergeOnly: true,
})
},
},
{
name: "Manual review is done, via PrjGit",
data: []prdata{
{
pr: &models.PullRequest{Body: "PR: foo/repo#20", Index: 42, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "barPrj", Owner: &models.User{UserName: "foo"}}}, User: &models.User{UserName: "submitter"}, State: "opened"},
reviews: []*models.PullReview{
{Body: "merge ok", User: &models.User{UserName: "m2"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: "super2"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: common.Bot_BuildReview}, State: common.ReviewStateApproved},
},
},
{
pr: &models.PullRequest{Body: "PR: foo/barPrj#42", Index: 20, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "repo", Owner: &models.User{UserName: "foo"}}}, User: &models.User{UserName: "submitter"}, State: "opened"},
reviews: []*models.PullReview{
{Body: "LGTM", User: &models.User{UserName: "m1"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: "super1"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: "super2"}, State: common.ReviewStateApproved},
},
},
},
resLen: 2,
prjGitPRIndex: 0,
consistentSet: true,
reviewed: true,
reviewSetFetcher: func(mock *mock_common.MockGiteaPRTimelineFetcher) (*common.PRSet, error) {
return common.FetchPRSet("test", mock, "foo", "barPrj", 42, &common.AutogitConfig{
Reviewers: []string{"+super1", "*super2", "m1", "-m2"},
Branch: "branch",
Organization: "foo",
GitProjectName: "barPrj",
ManualMergeOnly: true,
ManualMergeProject: true,
})
},
},
{
name: "Manual review is not done, via PrjGit",
data: []prdata{
{
pr: &models.PullRequest{Body: "PR: foo/repo#20", Index: 42, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "barPrj", Owner: &models.User{UserName: "foo"}}}, User: &models.User{UserName: "submitter"}, State: "opened"},
reviews: []*models.PullReview{
{Body: "merge ok", User: &models.User{UserName: "notm2"}, State: common.ReviewStateApproved},
{Body: "merge not ok", User: &models.User{UserName: "m2"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: "super2"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: common.Bot_BuildReview}, State: common.ReviewStateApproved},
},
},
{
pr: &models.PullRequest{Body: "PR: foo/barPrj#42", Index: 20, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "repo", Owner: &models.User{UserName: "foo"}}}, User: &models.User{UserName: "submitter"}, State: "opened"},
reviews: []*models.PullReview{
{Body: "LGTM", User: &models.User{UserName: "m1"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: "super1"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: "super2"}, State: common.ReviewStateApproved},
},
},
},
resLen: 2,
prjGitPRIndex: 0,
consistentSet: true,
reviewed: false,
reviewSetFetcher: func(mock *mock_common.MockGiteaPRTimelineFetcher) (*common.PRSet, error) {
return common.FetchPRSet("test", mock, "foo", "barPrj", 42, &common.AutogitConfig{
Reviewers: []string{"+super1", "*super2", "m1", "-m2"},
Branch: "branch",
Organization: "foo",
GitProjectName: "barPrj",
ManualMergeOnly: true,
ManualMergeProject: true,
})
},
},
{
name: "Manual review is done via PackageGit",
data: []prdata{
{
pr: &models.PullRequest{Body: "PR: foo/repo#20", Index: 42, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "barPrj", Owner: &models.User{UserName: "foo"}}}, User: &models.User{UserName: "submitter"}, State: "opened"},
reviews: []*models.PullReview{
{Body: "LGTM", User: &models.User{UserName: "m2"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: "super2"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: common.Bot_BuildReview}, State: common.ReviewStateApproved},
},
},
{
pr: &models.PullRequest{Body: "PR: foo/barPrj#42", Index: 20, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "repo", Owner: &models.User{UserName: "foo"}}}, User: &models.User{UserName: "submitter"}, State: "opened"},
reviews: []*models.PullReview{
{Body: "LGTM", User: &models.User{UserName: "m1"}, State: common.ReviewStateApproved},
{Body: "Merge ok", User: &models.User{UserName: "super1"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: "super2"}, State: common.ReviewStateApproved},
},
},
},
resLen: 2,
prjGitPRIndex: 0,
consistentSet: true,
reviewed: true,
reviewSetFetcher: func(mock *mock_common.MockGiteaPRTimelineFetcher) (*common.PRSet, error) {
return common.FetchPRSet("test", mock, "foo", "barPrj", 42, &common.AutogitConfig{
Reviewers: []string{"+super1", "*super2", "m1", "-m2"},
Branch: "branch",
Organization: "foo",
GitProjectName: "barPrj",
ManualMergeOnly: true,
})
},
},
{
name: "Manual review done via PkgGits",
data: []prdata{
{
pr: &models.PullRequest{Body: "PR: foo/repo#20\nPR: foo/repo#21", Index: 42, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "barPrj", Owner: &models.User{UserName: "foo"}}}, User: &models.User{UserName: "submitter"}, State: "opened"},
reviews: []*models.PullReview{
{Body: "LGTM", User: &models.User{UserName: "m2"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: "super2"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: common.Bot_BuildReview}, State: common.ReviewStateApproved},
},
},
{
pr: &models.PullRequest{Body: "PR: foo/barPrj#42", Index: 20, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "repo", Owner: &models.User{UserName: "foo"}}}, User: &models.User{UserName: "submitter"}, State: "opened"},
reviews: []*models.PullReview{
{Body: "LGTM", User: &models.User{UserName: "m1"}, State: common.ReviewStateApproved},
{Body: "Merge OK!", User: &models.User{UserName: "super1"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: "super2"}, State: common.ReviewStateApproved},
},
},
{
pr: &models.PullRequest{Body: "PR: foo/barPrj#42", Index: 21, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "repo", Owner: &models.User{UserName: "foo"}}}, User: &models.User{UserName: "submitter"}, State: "opened"},
reviews: []*models.PullReview{
{Body: "LGTM", User: &models.User{UserName: "m1"}, State: common.ReviewStateApproved},
{Body: "merge ok", User: &models.User{UserName: "super1"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: "super2"}, State: common.ReviewStateApproved},
},
},
},
resLen: 3,
prjGitPRIndex: 0,
consistentSet: true,
reviewed: true,
reviewSetFetcher: func(mock *mock_common.MockGiteaPRTimelineFetcher) (*common.PRSet, error) {
return common.FetchPRSet("test", mock, "foo", "barPrj", 42, &common.AutogitConfig{
Reviewers: []string{"+super1", "*super2", "m1", "-m2"},
Branch: "branch",
Organization: "foo",
GitProjectName: "barPrj",
ManualMergeOnly: true,
})
},
},
{
name: "Manual review done via PkgGits not allowed",
data: []prdata{
{
pr: &models.PullRequest{Body: "PR: foo/repo#20\nPR: foo/repo#21", Index: 42, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "barPrj", Owner: &models.User{UserName: "foo"}}}, User: &models.User{UserName: "submitter"}, State: "opened"},
reviews: []*models.PullReview{
{Body: "LGTM", User: &models.User{UserName: "m2"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: "super2"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: common.Bot_BuildReview}, State: common.ReviewStateApproved},
},
},
{
pr: &models.PullRequest{Body: "PR: foo/barPrj#42", Index: 20, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "repo", Owner: &models.User{UserName: "foo"}}}, User: &models.User{UserName: "submitter"}, State: "opened"},
reviews: []*models.PullReview{
{Body: "LGTM", User: &models.User{UserName: "m1"}, State: common.ReviewStateApproved},
{Body: "Merge OK!", User: &models.User{UserName: "super1"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: "super2"}, State: common.ReviewStateApproved},
},
},
{
pr: &models.PullRequest{Body: "PR: foo/barPrj#42", Index: 21, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "repo", Owner: &models.User{UserName: "foo"}}}, User: &models.User{UserName: "submitter"}, State: "opened"},
reviews: []*models.PullReview{
{Body: "LGTM", User: &models.User{UserName: "m1"}, State: common.ReviewStateApproved},
{Body: "merge ok", User: &models.User{UserName: "super1"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: "super2"}, State: common.ReviewStateApproved},
},
},
},
resLen: 3,
prjGitPRIndex: 0,
consistentSet: true,
reviewed: false,
reviewSetFetcher: func(mock *mock_common.MockGiteaPRTimelineFetcher) (*common.PRSet, error) {
return common.FetchPRSet("test", mock, "foo", "barPrj", 42, &common.AutogitConfig{
Reviewers: []string{"+super1", "*super2", "m1", "-m2"},
Branch: "branch",
Organization: "foo",
GitProjectName: "barPrj",
ManualMergeOnly: true,
ManualMergeProject: true,
})
},
},
{
name: "Manual review is is missing on one PR",
data: []prdata{
{
pr: &models.PullRequest{Body: "PR: foo/repo#20\nPR: foo/repo#21", Index: 42, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "barPrj", Owner: &models.User{UserName: "foo"}}}, User: &models.User{UserName: "submitter"}, State: "opened"},
reviews: []*models.PullReview{
{Body: "LGTM", User: &models.User{UserName: "m2"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: "super2"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: common.Bot_BuildReview}, State: common.ReviewStateApproved},
},
},
{
pr: &models.PullRequest{Body: "PR: foo/barPrj#42", Index: 20, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "repo", Owner: &models.User{UserName: "foo"}}}, User: &models.User{UserName: "submitter"}, State: "opened"},
reviews: []*models.PullReview{
{Body: "LGTM", User: &models.User{UserName: "m1"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: "super1"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: "super2"}, State: common.ReviewStateApproved},
},
},
{
pr: &models.PullRequest{Body: "PR: foo/barPrj#42", Index: 21, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "repo", Owner: &models.User{UserName: "foo"}}}, User: &models.User{UserName: "submitter"}, State: "opened"},
reviews: []*models.PullReview{
{Body: "LGTM", User: &models.User{UserName: "m1"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: "super1"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: "super2"}, State: common.ReviewStateApproved},
},
},
},
resLen: 3,
prjGitPRIndex: 0,
consistentSet: true,
reviewed: false,
reviewSetFetcher: func(mock *mock_common.MockGiteaPRTimelineFetcher) (*common.PRSet, error) {
return common.FetchPRSet("test", mock, "foo", "barPrj", 42, &common.AutogitConfig{
Reviewers: []string{"+super1", "*super2", "m1", "-m2"},
Branch: "branch",
Organization: "foo",
GitProjectName: "barPrj",
ManualMergeOnly: true,
})
},
},
{
name: "PR is approved with negative optional review",
data: []prdata{
{
pr: &models.PullRequest{Body: "", Index: 42, Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "barPrj", Owner: &models.User{UserName: "foo"}}}, User: &models.User{UserName: "submitter"}, State: "opened"},
reviews: []*models.PullReview{
{Body: "LGTM", User: &models.User{UserName: "m2"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: "super2"}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: common.Bot_BuildReview}, State: common.ReviewStateApproved},
{Body: "LGTM", User: &models.User{UserName: "bot"}, State: common.ReviewStateRequestChanges},
},
},
},
resLen: 1,
prjGitPRIndex: 0,
consistentSet: true,
reviewed: true,
reviewSetFetcher: func(mock *mock_common.MockGiteaPRTimelineFetcher) (*common.PRSet, error) {
config := common.AutogitConfig{
Reviewers: []string{"+super1", "*super2", "m1", "-m2", "~*bot"},
Branch: "branch",
Organization: "foo",
GitProjectName: "barPrj",
}
return common.FetchPRSet("test", mock, "foo", "barPrj", 42, &config)
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
ctl := gomock.NewController(t)
pr_mock := mock_common.NewMockGiteaPRFetcher(ctl)
pr_mock := mock_common.NewMockGiteaPRTimelineFetcher(ctl)
review_mock := mock_common.NewMockGiteaPRChecker(ctl)
// reviewer_mock := mock_common.NewMockGiteaReviewRequester(ctl)
if test.reviewSetFetcher == nil { // if we are fetching the prjgit directly, the these mocks are not called
if test.prjGitPRIndex >= 0 {
pr_mock.EXPECT().GetAssociatedPrjGitPR(baseConfig.Organization, baseConfig.GitProjectName, test.data[0].pr.Base.Repo.Owner.UserName, test.data[0].pr.Base.Repo.Name, test.data[0].pr.Index).
pr_mock.EXPECT().GetPullRequest(baseConfig.Organization, baseConfig.GitProjectName, test.prjGitPRIndex).
Return(test.data[test.prjGitPRIndex].pr, test.data[test.prjGitPRIndex].pr_err)
} else if test.prjGitPRIndex < 0 {
// no prjgit PR
pr_mock.EXPECT().GetAssociatedPrjGitPR(baseConfig.Organization, baseConfig.GitProjectName, test.data[0].pr.Base.Repo.Owner.UserName, test.data[0].pr.Base.Repo.Name, test.data[0].pr.Index).
pr_mock.EXPECT().GetPullRequest(baseConfig.Organization, baseConfig.GitProjectName, gomock.Any()).
Return(nil, nil)
}
}
@@ -155,6 +519,10 @@ func TestPR(t *testing.T) {
test_err = data.pr_err
}
review_mock.EXPECT().GetPullRequestReviews(data.pr.Base.Repo.Owner.UserName, data.pr.Base.Repo.Name, data.pr.Index).Return(data.reviews, data.review_error).AnyTimes()
if data.timeline == nil {
data.timeline = reviewsToTimeline(data.reviews)
}
review_mock.EXPECT().GetTimeline(data.pr.Base.Repo.Owner.UserName, data.pr.Base.Repo.Name, data.pr.Index).Return(data.timeline, nil).AnyTimes()
}
var res *common.PRSet
@@ -163,7 +531,7 @@ func TestPR(t *testing.T) {
if test.reviewSetFetcher != nil {
res, err = test.reviewSetFetcher(pr_mock)
} else {
res, err = common.FetchPRSet(pr_mock, "test", "repo", 42, &baseConfig)
res, err = common.FetchPRSet("test", pr_mock, "test", "repo", 42, &baseConfig)
}
if err == nil {
@@ -198,7 +566,7 @@ func TestPR(t *testing.T) {
pr_found := false
if test.prjGitPRIndex >= 0 {
for i := range test.data {
if PrjGitPR == test.data[i].pr && i == test.prjGitPRIndex {
if PrjGitPR.PR == test.data[i].pr && i == test.prjGitPRIndex {
t.Log("found at index", i)
pr_found = true
}
@@ -222,7 +590,9 @@ func TestPR(t *testing.T) {
*/
maintainers := mock_common.NewMockMaintainershipData(ctl)
maintainers.EXPECT().IsApproved(gomock.Any(), gomock.Any()).Return(true).AnyTimes()
maintainers.EXPECT().ListPackageMaintainers(gomock.Any()).Return([]string{}).AnyTimes()
maintainers.EXPECT().ListProjectMaintainers().Return([]string{}).AnyTimes()
maintainers.EXPECT().IsApproved(gomock.Any(), gomock.Any(), gomock.Any()).Return(true).AnyTimes()
if isApproved := res.IsApproved(review_mock, maintainers); isApproved != test.reviewed {
t.Error("expected reviewed to be NOT", isApproved)
@@ -242,8 +612,10 @@ func TestPRAssignReviewers(t *testing.T) {
reviewer string
}
pkgReviews []*models.PullReview
prjReviews []*models.PullReview
pkgReviews []*models.PullReview
pkgTimeline []*models.TimelineComment
prjReviews []*models.PullReview
prjTimeline []*models.TimelineComment
expectedReviewerCall [2][]string
}{
@@ -331,8 +703,8 @@ func TestPRAssignReviewers(t *testing.T) {
},
pkgReviews: []*models.PullReview{
{
State: common.ReviewStateApproved,
User: &models.User{UserName: "user2"},
State: common.ReviewStateApproved,
User: &models.User{UserName: "user2"},
},
{
State: common.ReviewStatePending,
@@ -353,15 +725,59 @@ func TestPRAssignReviewers(t *testing.T) {
},
expectedReviewerCall: [2][]string{{"user1", "autogits_obs_staging_bot"}, {"pkgmaintainer"}},
},
{
name: "Stale optional review is not done, re-request it",
config: common.AutogitConfig{
GitProjectName: "repo",
Organization: "org",
Branch: "main",
Reviewers: []string{"-user1", "user2", "~bot"},
},
pkgReviews: []*models.PullReview{
{
State: common.ReviewStateApproved,
User: &models.User{UserName: "bot"},
Stale: true,
},
{
State: common.ReviewStateApproved,
User: &models.User{UserName: "user2"},
},
{
State: common.ReviewStatePending,
User: &models.User{UserName: "prjmaintainer"},
},
},
prjReviews: []*models.PullReview{
{
State: common.ReviewStateRequestChanges,
User: &models.User{UserName: "user1"},
Stale: true,
},
{
State: common.ReviewStateRequestReview,
Stale: true,
User: &models.User{UserName: "autogits_obs_staging_bot"},
},
},
expectedReviewerCall: [2][]string{{"user1", "autogits_obs_staging_bot"}, {"pkgmaintainer", "bot"}},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
ctl := gomock.NewController(t)
pr_mock := mock_common.NewMockGiteaPRFetcher(ctl)
pr_mock := mock_common.NewMockGiteaPRTimelineFetcher(ctl)
review_mock := mock_common.NewMockGiteaReviewFetcherAndRequester(ctl)
maintainership_mock := mock_common.NewMockMaintainershipData(ctl)
if test.pkgTimeline == nil {
test.pkgTimeline = reviewsToTimeline(test.pkgReviews)
}
if test.prjTimeline == nil {
test.prjTimeline = reviewsToTimeline(test.prjReviews)
}
pr_mock.EXPECT().GetPullRequest("other", "pkgrepo", int64(1)).Return(&models.PullRequest{
Body: "Some description is here",
User: &models.User{UserName: "submitter"},
@@ -371,7 +787,8 @@ func TestPRAssignReviewers(t *testing.T) {
Index: 1,
}, nil)
review_mock.EXPECT().GetPullRequestReviews("other", "pkgrepo", int64(1)).Return(test.pkgReviews, nil)
pr_mock.EXPECT().GetAssociatedPrjGitPR("org", "repo", "other", "pkgrepo", int64(1)).Return(&models.PullRequest{
review_mock.EXPECT().GetTimeline("other", "pkgrepo", int64(1)).Return(test.pkgTimeline, nil)
pr_mock.EXPECT().GetPullRequest("org", "repo", int64(1)).Return(&models.PullRequest{
Body: fmt.Sprintf(common.PrPattern, "other", "pkgrepo", 1),
User: &models.User{UserName: "bot1"},
RequestedReviewers: []*models.User{{UserName: "main_reviewer"}},
@@ -380,11 +797,12 @@ func TestPRAssignReviewers(t *testing.T) {
Index: 42,
}, nil)
review_mock.EXPECT().GetPullRequestReviews("org", "repo", int64(42)).Return(test.prjReviews, nil)
review_mock.EXPECT().GetTimeline("org", "repo", int64(42)).Return(test.prjTimeline, nil)
maintainership_mock.EXPECT().ListProjectMaintainers().Return([]string{"prjmaintainer"}).AnyTimes()
maintainership_mock.EXPECT().ListPackageMaintainers("pkgrepo").Return([]string{"pkgmaintainer"}).AnyTimes()
prs, _ := common.FetchPRSet(pr_mock, "other", "pkgrepo", int64(1), &test.config)
prs, _ := common.FetchPRSet("test", pr_mock, "other", "pkgrepo", int64(1), &test.config)
if len(prs.PRs) != 2 {
t.Fatal("PRs not fetched")
}
@@ -393,8 +811,9 @@ func TestPRAssignReviewers(t *testing.T) {
if !prs.IsPrjGitPR(pr.PR) {
r = test.expectedReviewerCall[1]
}
if len(r) > 0 {
review_mock.EXPECT().RequestReviews(pr.PR, r).Return(nil, nil)
slices.Sort(r)
for _, reviewer := range r {
review_mock.EXPECT().RequestReviews(pr.PR, reviewer).Return(nil, nil)
}
}
prs.AssignReviewers(review_mock, maintainership_mock)
@@ -428,7 +847,7 @@ func TestPRAssignReviewers(t *testing.T) {
for _, test := range prjgit_tests {
t.Run(test.name, func(t *testing.T) {
ctl := gomock.NewController(t)
pr_mock := mock_common.NewMockGiteaPRFetcher(ctl)
pr_mock := mock_common.NewMockGiteaPRTimelineFetcher(ctl)
review_mock := mock_common.NewMockGiteaReviewFetcherAndRequester(ctl)
maintainership_mock := mock_common.NewMockMaintainershipData(ctl)
@@ -441,10 +860,11 @@ func TestPRAssignReviewers(t *testing.T) {
Index: 1,
}, nil)
review_mock.EXPECT().GetPullRequestReviews("org", "repo", int64(1)).Return(test.prjReviews, nil)
review_mock.EXPECT().GetTimeline("org", "repo", int64(1)).Return(nil, nil)
maintainership_mock.EXPECT().ListProjectMaintainers().Return([]string{"prjmaintainer"}).AnyTimes()
prs, _ := common.FetchPRSet(pr_mock, "org", "repo", int64(1), &test.config)
prs, _ := common.FetchPRSet("test", pr_mock, "org", "repo", int64(1), &test.config)
if len(prs.PRs) != 1 {
t.Fatal("PRs not fetched")
}
@@ -453,8 +873,8 @@ func TestPRAssignReviewers(t *testing.T) {
if !prs.IsPrjGitPR(pr.PR) {
t.Fatal("only prjgit pr here")
}
if len(r) > 0 {
review_mock.EXPECT().RequestReviews(pr.PR, r).Return(nil, nil)
for _, reviewer := range r {
review_mock.EXPECT().RequestReviews(pr.PR, reviewer).Return(nil, nil)
}
}
prs.AssignReviewers(review_mock, maintainership_mock)
@@ -463,9 +883,11 @@ func TestPRAssignReviewers(t *testing.T) {
}
func TestPRMerge(t *testing.T) {
repoDir := t.TempDir()
cwd, _ := os.Getwd()
cmd := exec.Command("/usr/bin/bash", path.Join(cwd, "test_repo_setup.sh"))
cmd.Dir = t.TempDir()
cmd := exec.Command(path.Join(cwd, "test_repo_setup.sh"))
cmd.Dir = repoDir
if out, err := cmd.CombinedOutput(); err != nil {
t.Fatal(string(out))
}
@@ -504,7 +926,7 @@ func TestPRMerge(t *testing.T) {
Owner: &models.User{
UserName: "org",
},
SSHURL: path.Join(cmd.Dir, "prjgit"),
SSHURL: "file://" + path.Join(repoDir, "prjgit"),
},
},
Head: &models.PRBranchInfo{
@@ -514,7 +936,7 @@ func TestPRMerge(t *testing.T) {
mergeError: "Aborting merge",
},
{
name: "Merge conflict in modules",
name: "Merge conflict in modules, auto-resolved",
pr: &models.PullRequest{
Base: &models.PRBranchInfo{
@@ -524,7 +946,7 @@ func TestPRMerge(t *testing.T) {
Owner: &models.User{
UserName: "org",
},
SSHURL: path.Join(cmd.Dir, "prjgit"),
SSHURL: "file://" + path.Join(cmd.Dir, "prjgit"),
},
},
Head: &models.PRBranchInfo{
@@ -537,18 +959,79 @@ func TestPRMerge(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
ctl := gomock.NewController(t)
mock := mock_common.NewMockGiteaPRFetcher(ctl)
mock := mock_common.NewMockGiteaPRTimelineFetcher(ctl)
reviewUnrequestMock := mock_common.NewMockGiteaReviewUnrequester(ctl)
reviewUnrequestMock.EXPECT().UnrequestReview(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
testDir := t.TempDir()
t.Log("dir:", testDir)
mock.EXPECT().GetPullRequest("org", "prj", int64(1)).Return(test.pr, nil)
set, err := common.FetchPRSet(mock, "org", "prj", 1, config)
set, err := common.FetchPRSet("test", mock, "org", "prj", 1, config)
if err != nil {
t.Fatal(err)
}
if err = set.Merge("test", "test@example.com"); err != nil && (test.mergeError == "" || (len(test.mergeError) > 0 && !strings.Contains(err.Error(), test.mergeError))) {
gh, _ := common.AllocateGitWorkTree(testDir, "", "")
git, err := gh.CreateGitHandler("org")
err = set.Merge(reviewUnrequestMock, git)
if err != nil && (test.mergeError == "" || (len(test.mergeError) > 0 && !strings.Contains(err.Error(), test.mergeError))) {
os.CopyFS("/tmp/upstream", os.DirFS(repoDir))
os.CopyFS("/tmp/out", os.DirFS(testDir))
t.Fatal(err)
}
})
}
}
func TestPRChanges(t *testing.T) {
tests := []struct {
name string
PRs []*models.PullRequest
PrjPRs *models.PullRequest
}{
{
name: "Pkg PR is closed",
PRs: []*models.PullRequest{
{
Base: &models.PRBranchInfo{Repo: &models.Repository{Owner: &models.User{UserName: "org"}, Name: "repo"}},
Index: 42,
State: "merged",
},
},
PrjPRs: &models.PullRequest{
Title: "some PR",
Base: &models.PRBranchInfo{Repo: &models.Repository{Name: "prjgit", Owner: &models.User{UserName: "org"}}},
Body: "PR: org/repo#42",
State: "opened",
},
},
}
config := common.AutogitConfig{
Branch: "main",
GitProjectName: "org/prjgit#branch",
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
ctl := gomock.NewController(t)
mock_fetcher := mock_common.NewMockGiteaPRTimelineFetcher(ctl)
mock_fetcher.EXPECT().GetPullRequest("org", "prjgit", int64(42)).Return(test.PrjPRs, nil)
for _, pr := range test.PRs {
mock_fetcher.EXPECT().GetPullRequest(pr.Base.Repo.Owner.UserName, pr.Base.Repo.Name, pr.Index).Return(pr, nil)
}
PRs, err := common.FetchPRSet("user", mock_fetcher, "org", "repo", 42, &config)
if err != nil {
t.Fatal(err)
}
if PRs.IsConsistent() {
t.Fatal("Inconsistent set!")
}
})
}
}

View File

@@ -28,9 +28,14 @@ import (
type Commit struct {
Id string
Message string
Added []string
Removed []string
Modified []string
}
type PushWebhookEvent struct {
Ref string
Total_Commits int
Head_Commit Commit
Commits []Commit

View File

@@ -7,21 +7,33 @@ import (
type Reviewers struct {
Prj []string
Pkg []string
PrjOptional []string
PkgOptional []string
}
func ParseReviewers(input []string) *Reviewers {
r := &Reviewers{}
for _, reviewer := range input {
pkg := &r.Pkg
prj := &r.Prj
if reviewer[0] == '~' {
pkg = &r.PkgOptional
prj = &r.PrjOptional
reviewer = reviewer[1:]
}
switch reviewer[0] {
case '*':
r.Prj = append(r.Prj, reviewer[1:])
r.Pkg = append(r.Pkg, reviewer[1:])
*prj = append(*prj, reviewer[1:])
*pkg = append(*pkg, reviewer[1:])
case '-':
r.Prj = append(r.Prj, reviewer[1:])
*prj = append(*prj, reviewer[1:])
case '+':
r.Pkg = append(r.Pkg, reviewer[1:])
*pkg = append(*pkg, reviewer[1:])
default:
r.Pkg = append(r.Pkg, reviewer)
*pkg = append(*pkg, reviewer)
}
}

View File

@@ -12,8 +12,10 @@ func TestReviewers(t *testing.T) {
name string
input []string
prj []string
pkg []string
prj []string
pkg []string
pkg_optional []string
prj_optional []string
}{
{
name: "project and package reviewers",
@@ -22,6 +24,15 @@ func TestReviewers(t *testing.T) {
prj: []string{"5", "7", common.Bot_BuildReview},
pkg: []string{"1", "2", "3", "5", "6"},
},
{
name: "optional project and package reviewers",
input: []string{"~1", "2", "3", "~*5", "+6", "-7"},
prj: []string{"7", common.Bot_BuildReview},
pkg: []string{"2", "3", "6"},
prj_optional: []string{"5"},
pkg_optional: []string{"1", "5"},
},
}
for _, test := range tests {
@@ -31,7 +42,13 @@ func TestReviewers(t *testing.T) {
t.Error("unexpected return of ForProject():", reviewers.Prj)
}
if !slices.Equal(reviewers.Pkg, test.pkg) {
t.Error("unexpected return of ForProject():", reviewers.Pkg)
t.Error("unexpected return of ForPackage():", reviewers.Pkg)
}
if !slices.Equal(reviewers.PrjOptional, test.prj_optional) {
t.Error("unexpected return of ForProjectOptional():", reviewers.Prj)
}
if !slices.Equal(reviewers.PkgOptional, test.pkg_optional) {
t.Error("unexpected return of ForPackageOptional():", reviewers.Pkg)
}
})
}

View File

@@ -1,7 +1,9 @@
package common
import (
"regexp"
"slices"
"strings"
"src.opensuse.org/autogits/common/gitea-generated/models"
)
@@ -9,27 +11,96 @@ import (
type PRReviews struct {
reviews []*models.PullReview
reviewers []string
comments []*models.TimelineComment
}
func FetchGiteaReviews(rf GiteaReviewFetcher, reviewers []string, org, repo string, no int64) (*PRReviews, error) {
reviews, err := rf.GetPullRequestReviews(org, repo, no)
func FetchGiteaReviews(rf GiteaReviewTimelineFetcher, reviewers []string, org, repo string, no int64) (*PRReviews, error) {
timeline, err := rf.GetTimeline(org, repo, no)
if err != nil {
return nil, err
}
rawReviews, err := rf.GetPullRequestReviews(org, repo, no)
if err != nil {
return nil, err
}
reviews := make([]*models.PullReview, 0, 10)
var comments []*models.TimelineComment
for idx, item := range timeline {
if item.Type == TimelineCommentType_Review {
for _, r := range rawReviews {
if r.ID == item.ReviewID {
reviews = append(reviews, r)
break
}
}
} else if item.Type == TimelineCommentType_Comment {
comments = append(comments, item)
} else if item.Type == TimelineCommentType_PushPull {
timeline = timeline[0:idx]
break
} else {
LogDebug("Unhandled timeline type:", item.Type)
}
}
return &PRReviews{
reviews: reviews,
reviewers: reviewers,
comments: comments,
}, nil
}
const ManualMergeOK = "^merge\\s+ok(\\W|$)"
var merge_ok_regex *regexp.Regexp = regexp.MustCompile(ManualMergeOK)
func bodyCommandManualMergeOK(body string) bool {
lines := SplitLines(body)
for _, line := range lines {
if merge_ok_regex.MatchString(strings.ToLower(line)) {
return true
}
}
return false
}
func (r *PRReviews) IsManualMergeOK() bool {
for _, c := range r.comments {
if c.Updated != c.Created {
continue
}
if slices.Contains(r.reviewers, c.User.UserName) {
if bodyCommandManualMergeOK(c.Body) {
return true
}
}
}
for _, c := range r.reviews {
if c.Updated != c.Submitted {
continue
}
if slices.Contains(r.reviewers, c.User.UserName) {
if bodyCommandManualMergeOK(c.Body) {
return true
}
}
}
return false
}
func (r *PRReviews) IsApproved() bool {
goodReview := false
goodReview := true
for _, reviewer := range r.reviewers {
goodReview = false
for _, review := range r.reviews {
if review.User.UserName == reviewer && review.State == ReviewStateApproved && !review.Stale && !review.Dismissed {
LogDebug(" -- found review: ", review.User.UserName)
goodReview = true
break
}

View File

@@ -14,6 +14,7 @@ func TestReviews(t *testing.T) {
tests := []struct {
name string
reviews []*models.PullReview
timeline []*models.TimelineComment
reviewers []string
fetchErr error
isApproved bool
@@ -21,21 +22,21 @@ func TestReviews(t *testing.T) {
isPendingByTest1 bool
}{
{
name: "Reviews of unreviews PR",
isApproved: false,
name: "Reviews of PR with no review requirements",
isApproved: true,
},
{
name: "Single reviewer done",
reviews: []*models.PullReview{&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user1"}}},
reviewers: []string{"user1"},
isApproved: true,
name: "Single reviewer done",
reviews: []*models.PullReview{&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user1"}}},
reviewers: []string{"user1"},
isApproved: true,
isReviewedByTest1: true,
},
{
name: "Two reviewer, one not approved",
reviews: []*models.PullReview{&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user1"}}},
reviewers: []string{"user1", "user2"},
isApproved: false,
name: "Two reviewer, one not approved",
reviews: []*models.PullReview{&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user1"}}},
reviewers: []string{"user1", "user2"},
isApproved: false,
isReviewedByTest1: true,
},
{
@@ -44,8 +45,8 @@ func TestReviews(t *testing.T) {
&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user1"}},
&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user2"}, Stale: true},
},
reviewers: []string{"user1", "user2"},
isApproved: false,
reviewers: []string{"user1", "user2"},
isApproved: false,
isReviewedByTest1: true,
},
{
@@ -54,8 +55,8 @@ func TestReviews(t *testing.T) {
&models.PullReview{State: common.ReviewStateRequestReview, User: &models.User{UserName: "user1"}},
&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user2"}},
},
reviewers: []string{"user1", "user2"},
isApproved: false,
reviewers: []string{"user1", "user2"},
isApproved: false,
isPendingByTest1: true,
},
{
@@ -63,9 +64,9 @@ func TestReviews(t *testing.T) {
reviews: []*models.PullReview{
&models.PullReview{State: common.ReviewStateRequestReview, User: &models.User{UserName: "user1"}, Stale: true},
},
reviewers: []string{"user1", "user2"},
isApproved: false,
isPendingByTest1: false,
reviewers: []string{"user1", "user2"},
isApproved: false,
isPendingByTest1: false,
isReviewedByTest1: false,
},
{
@@ -74,8 +75,8 @@ func TestReviews(t *testing.T) {
&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user1"}},
&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user2"}},
},
reviewers: []string{"user1", "user2"},
isApproved: true,
reviewers: []string{"user1", "user2"},
isApproved: true,
isReviewedByTest1: true,
},
{
@@ -84,8 +85,8 @@ func TestReviews(t *testing.T) {
&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user1"}},
&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user2"}, Dismissed: true},
},
reviewers: []string{"user1", "user2"},
isApproved: false,
reviewers: []string{"user1", "user2"},
isApproved: false,
isReviewedByTest1: true,
},
{
@@ -94,9 +95,9 @@ func TestReviews(t *testing.T) {
&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user1"}},
&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user2"}},
},
reviewers: []string{"user1", "user2"},
fetchErr: errors.New("System error fetching reviews."),
isApproved: true,
reviewers: []string{"user1", "user2"},
fetchErr: errors.New("System error fetching reviews."),
isApproved: true,
isReviewedByTest1: true,
},
{
@@ -106,8 +107,23 @@ func TestReviews(t *testing.T) {
&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user4"}},
&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user2"}},
},
reviewers: []string{"user1", "user2"},
isApproved: true,
reviewers: []string{"user1", "user2"},
isApproved: true,
isReviewedByTest1: true,
},
{
name: "Review ignored before push",
reviews: []*models.PullReview{
&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user1"}, ID: 1001},
&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user2"}, ID: 1000},
},
timeline: []*models.TimelineComment{
&models.TimelineComment{Type: common.TimelineCommentType_Review, ReviewID: 1001},
&models.TimelineComment{Type: common.TimelineCommentType_PushPull},
&models.TimelineComment{Type: common.TimelineCommentType_Review, ReviewID: 1000},
},
reviewers: []string{"user1", "user2"},
isApproved: false,
isReviewedByTest1: true,
},
}
@@ -115,8 +131,12 @@ func TestReviews(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
ctl := gomock.NewController(t)
rf := mock_common.NewMockGiteaReviewFetcher(ctl)
rf := mock_common.NewMockGiteaReviewTimelineFetcher(ctl)
if test.timeline == nil {
test.timeline = reviewsToTimeline(test.reviews)
}
rf.EXPECT().GetTimeline("test", "pr", int64(1)).Return(test.timeline, nil)
rf.EXPECT().GetPullRequestReviews("test", "pr", int64(1)).Return(test.reviews, test.fetchErr)
reviews, err := common.FetchGiteaReviews(rf, test.reviewers, "test", "pr", 1)

63
common/timeline.go Normal file
View File

@@ -0,0 +1,63 @@
package common
import (
"encoding/json"
"slices"
"src.opensuse.org/autogits/common/gitea-generated/models"
)
const (
TimelineCommentType_ReviewRequested = "review_request"
TimelineCommentType_Review = "review"
TimelineCommentType_PushPull = "pull_push"
TimelineCommentType_PullRequestRef = "pull_ref"
TimelineCommentType_DismissReview = "dismiss_review"
TimelineCommentType_Comment = "comment"
)
func FetchTimelineSinceLastPush(gitea GiteaTimelineFetcher, headSha, org, repo string, id int64) ([]*models.TimelineComment, error) {
timeline, err := gitea.GetTimeline(org, repo, id)
if err != nil {
return nil, err
}
//{"is_force_push":true,"commit_ids":["36e43509be1b13a1a8fc63a4361405de04cc621ab16935f88968c46193221bb6","732246a48fbc6bac9df16c0b0ca23ce0f6fbabd9990795863b6d1f0ef3f242c8"]}
type PullPushData struct {
IsForcePush bool `json:"is_force_push"`
CommitIds []string `json:"commit_ids"`
}
// trim timeline to last push update or last time review request was requested
for i, e := range timeline {
if e.Type == TimelineCommentType_PushPull {
var push PullPushData
if err := json.Unmarshal([]byte(e.Body), &push); err != nil {
LogError(err)
}
if slices.Contains(push.CommitIds, headSha) {
return timeline[0:i], nil
}
}
}
return timeline, nil
}
func FetchTimelineSinceReviewRequestOrPush(gitea GiteaTimelineFetcher, groupName, headSha, org, repo string, id int64) ([]*models.TimelineComment, error) {
timeline, err := FetchTimelineSinceLastPush(gitea, headSha, org, repo, id)
if err != nil {
return nil, err
}
// trim timeline to last push update or last time review request was requested
for i, e := range timeline {
if e.Type == TimelineCommentType_ReviewRequested && e.Assignee != nil && e.Assignee.UserName == groupName {
// review request is cut-off for reviews too
return timeline[0:i], nil
}
}
return timeline, nil
}

View File

@@ -19,11 +19,22 @@ package common
*/
import (
"bufio"
"errors"
"fmt"
"net/http"
"net/url"
"regexp"
"slices"
"strings"
"src.opensuse.org/autogits/common/gitea-generated/models"
)
func SplitLines(str string) []string {
return SplitStringNoEmpty(str, "\n")
}
func SplitStringNoEmpty(str, sep string) []string {
ret := slices.DeleteFunc(strings.Split(str, sep), func(s string) bool {
return len(strings.TrimSpace(s)) == 0
@@ -35,16 +46,131 @@ func SplitStringNoEmpty(str, sep string) []string {
}
func TranslateHttpsToSshUrl(url string) (string, error) {
const url1 = "https://src.opensuse.org/"
const url2 = "https://src.suse.de/"
const (
url1 = "https://src.opensuse.org/"
url2 = "https://src.suse.de/"
if len(url) > len(url1) && url[0:len(url1)] == url1 {
return "gitea@src.opensuse.org:" + url[len(url1):], nil
url1_len = len(url1)
url2_len = len(url2)
)
if len(url) > url1_len && url[0:url1_len] == url1 {
return "ssh://gitea@src.opensuse.org/" + url[url1_len:], nil
}
if len(url) > len(url2) && url[0:len(url2)] == url2 {
return "gitea@src.suse.de:" + url[len(url2):], nil
if len(url) > url2_len && url[0:url2_len] == url2 {
return "ssh://gitea@src.suse.de/" + url[url2_len:], nil
}
return "", fmt.Errorf("Unknown input url %s", url)
}
func TranslateSshNativeToUrl(urlString string) (string, error) {
rx := regexp.MustCompile("^([^:@]+)@?([^:]*):(.+)$")
m := rx.FindAllStringSubmatch(urlString, -1)
if m == nil {
return "", fmt.Errorf("Cannot match expected native SSH schema: %s", urlString)
}
if len(m[0][2]) > 0 {
// with user
return "ssh://" + m[0][1] + "@" + m[0][2] + "/" + m[0][3], nil
}
// without user
return "ssh://" + m[0][1] + "/" + m[0][3], nil
}
type GitUrl struct {
Org string
Repo string
Commit string
}
var valid_schemas []string = []string{"https", "ssh", "http", "file"}
func ParseGitRemoteUrl(urlString string) (*GitUrl, error) {
url, err := url.Parse(urlString)
if url != nil && url.Scheme == "file" && err == nil {
return nil, nil
}
if err != nil || !slices.Contains(valid_schemas, url.Scheme) {
u, err := TranslateSshNativeToUrl(urlString)
if err != nil {
return nil, fmt.Errorf("Unable to parse url: %w", err)
}
return ParseGitRemoteUrl(u)
}
e := SplitStringNoEmpty(url.Path, "/")
if len(e) != 2 {
return nil, fmt.Errorf("Unexpected format for Gitea URL: %s", e)
}
org := e[0]
repo := strings.TrimSuffix(e[1], ".git")
u := GitUrl{
Org: org,
Repo: repo,
Commit: url.Fragment,
}
return &u, nil
}
func (giturl *GitUrl) RemoteName() string {
if giturl == nil || len(giturl.Org) == 0 || len(giturl.Repo) == 0 {
return "origin"
}
return strings.ToLower(giturl.Org) + "_" + strings.ToLower(giturl.Repo)
}
func PRtoString(pr *models.PullRequest) string {
if pr == nil {
return "(null)"
}
return fmt.Sprintf("%s/%s#%d", pr.Base.Repo.Owner.UserName, pr.Base.Repo.Name, pr.Index)
}
type DevelProject struct {
Project, Package string
}
type DevelProjects []*DevelProject
func FetchDevelProjects() (DevelProjects, error) {
res, err := http.Get("https://src.opensuse.org/openSUSE/Factory/raw/branch/main/pkgs/_meta/devel_packages")
if err != nil {
return nil, err
}
defer res.Body.Close()
scanner := bufio.NewScanner(res.Body)
ret := []*DevelProject{}
for scanner.Scan() {
d := SplitStringNoEmpty(scanner.Text(), " ")
if len(d) == 2 {
ret = append(ret, &DevelProject{
Project: d[1],
Package: d[0],
})
}
}
return ret, nil
}
var DevelProjectNotFound = errors.New("Devel project not found")
func (d DevelProjects) GetDevelProject(pkg string) (string, error) {
for _, item := range d {
if item.Package == pkg {
return item.Project, nil
}
}
return "", DevelProjectNotFound
}

167
common/utils_test.go Normal file
View File

@@ -0,0 +1,167 @@
package common_test
import (
"testing"
"src.opensuse.org/autogits/common"
)
func TestGitUrlParse(t *testing.T) {
tests := []struct {
name string
inputUrl string
url common.GitUrl
error bool
}{
{
name: "Empty string",
error: true,
},
{
name: "OpenSUSE HTTPS Url",
url: common.GitUrl{
Org: "foo",
Repo: "b",
},
inputUrl: "https://src.opensuse.org/foo/b.git",
},
{
name: "OpenSUSE HTTPS Url",
url: common.GitUrl{
Org: "a",
Repo: "b",
},
inputUrl: "https://src.opensuse.org/a/b",
},
{
name: "OpenSUSE HTTPS Url",
url: common.GitUrl{
Org: "foo",
Repo: "bar",
Commit: "main",
},
inputUrl: "https://src.opensuse.org/foo/bar.git#main",
},
{
name: "invalid OpenSUSE HTTPS Url",
inputUrl: "https://src.opensuse.org/bar.git#main",
error: true,
},
{
name: "OpenSUSE SSH Url",
url: common.GitUrl{
Org: "foo",
Repo: "bar",
Commit: "main",
},
inputUrl: "ssh://src.opensuse.org/foo/bar.git#main",
},
{
name: "SSH native OpenSUSE Url",
inputUrl: "gitea@src.opensuse.org:foo/bar.git#main",
url: common.GitUrl{
Org: "foo",
Repo: "bar",
Commit: "main",
},
},
{
name: "SSH native OpenSUSE Url without user",
inputUrl: "src.opensuse.org:foo/bar.git#main",
url: common.GitUrl{
Org: "foo",
Repo: "bar",
Commit: "main",
},
},
{
name: "invalid SSH native OpenSUSE Url without user",
inputUrl: "src.opensuse.org:/br.it",
error: true,
},
{
name: "SSH native OpenSUSE Url without user",
inputUrl: "src.opensuse.org:foo/bar#main",
url: common.GitUrl{
Org: "foo",
Repo: "bar",
Commit: "main",
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
url, err := common.ParseGitRemoteUrl(test.inputUrl)
if test.error && err != nil {
return
}
if test.error && err == nil {
t.Fatal("Expected an error but received", *url)
} else if !test.error && err != nil {
t.Error(err)
}
if url == nil {
t.Fatal("Recieved nil. Expected", test.url)
} else if *url != test.url {
t.Fatalf("Expected %v but received %v", test.url, *url)
}
})
}
}
func TestRemoteName(t *testing.T) {
tests := []struct {
name string
giturl *common.GitUrl
remotename string
}{
{
name: "empty",
remotename: "origin",
},
{
name: "regular repo",
giturl: &common.GitUrl{
Org: "org1",
Repo: "repo2",
Commit: "main",
},
remotename: "org1_repo2",
},
{
name: "regular repo with upper case",
giturl: &common.GitUrl{
Org: "Org1",
Repo: "REPO2",
},
remotename: "org1_repo2",
},
{
name: "no org",
giturl: &common.GitUrl{
Repo: "REPO2",
},
remotename: "origin",
},
{
name: "no repo",
giturl: &common.GitUrl{
Org: "ORG2",
},
remotename: "origin",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
n := test.giturl.RemoteName()
if n != test.remotename {
t.Errorf("Expected '%s' but received '%s'", test.remotename, n)
}
})
}
}

View File

@@ -5,9 +5,12 @@ if [ "x$1" = 'x' ]; then
exit 1
fi
files=$(find .. -maxdepth 2 -name \*.go -and \! -wholename \*/gitea-generated/\*)
while true; do
go test --run "$1"
inotifywait --exclude 'node_modules' -qqr -e close_write .. && clear
inotifywait -qqr -e close_write $files
clear
sleep 0.2
done

View File

@@ -1 +1,4 @@
devel-importer
Factory
git
git-migrated

View File

@@ -0,0 +1,50 @@
#!/usr/bin/bash
# Factory meta data checked-out
export DEVEL_PACKAGES=$PWD/Factory/pkgs/_meta/devel_packages
devel=$PWD/devel_update.sh
function getorg {
osc meta prj $1 | grep scmsync | sed -e's,^.*src\.opensuse\.org/,,' -e 's,/_ObsPrj.*$,,'
}
function factory {
$devel get $1
}
function message {
org=$1
pkg=$2
dprj=$3
echo "This package is developed in git at https://src.opensuse.org/${org}/${pkg} for OBS package ${dprj}/${pkg} -- see https://en.opensuse.org/openSUSE:OBS_to_Git"
}
obs=$1
if [ -z "$1" ]; then
obs=$(cat migrated_projects)
fi
for p in $obs; do
org=$(getorg $p)
if [ -z "$org" ]; then
echo $p is not in git!
continue
fi
packages=$(osc ls $p)
for pkg in $packages; do
dprj=$(factory $pkg)
if [ "$dprj" != "$p" ]; then
# not devel project
continue
fi
msg=$(message $org $pkg $dprj)
if [ -n "$msg" ]; then
echo $msg
osc meta attribute openSUSE:Factory $pkg --attribute OBS:RejectBranch --set "$msg" > /dev/null || exit 1
fi
done
done

127
devel-importer/devel_update.sh Executable file
View File

@@ -0,0 +1,127 @@
#!/usr/bin/bash
#
# Updates devel_packages in https://src.opensuse.org/openSUSE/Factory/src/branch/main/pkgs/_meta/devel_packages
#
# syntax:
# get <pkg>
# set <prj> <pkg>
# rm <prj> <pkg>
# sync
#
# DEVEL_PACKAGES env should point to the devel_packages clone from
# repo above, otherwise will look in CWD
#
set +e
function getdevel {
local pkg="$1"
awk "{ if ( \$1 == \"$pkg\" ) print \$2 }" "$DEVEL_PACKAGES"
}
function setdevel {
local prj="$1"
local pkg="$2"
if [ x"$prj" == "x" ] || [ x"$pkg" == "x" ]; then
echo "devel_update set <prj> <pkg>"
exit 10
fi
cat <(awk "{ if ( \$1 != \"$pkg\" ) print }" "$DEVEL_PACKAGES") <(echo $pkg $prj) | sort -d > "$DEVEL_PACKAGES".$$
mv "$DEVEL_PACKAGES".$$ "$DEVEL_PACKAGES"
}
function rmdevel {
local prj="$1"
local pkg="$2"
if [ x"$prj" == "x" ] || [ x"$pkg" == "x" ]; then
echo "devel_update rm <prj> <pkg>"
exit 10
fi
awk "{ if ( ! ( \$1 == \"$pkg\" && \$2 == \"$prj\" ) ) print }" "$DEVEL_PACKAGES" > "$DEVEL_PACKAGES".$$
mv "$DEVEL_PACKAGES".$$ "$DEVEL_PACKAGES"
}
if [ -z "$DEVEL_PACKAGES" ]; then
DEVEL_PACKAGES=./devel_packages
fi
if ! [ -w "$DEVEL_PACKAGES" ] || ! [ -e "$DEVEL_PACKAGES" ] ; then
echo "The DEVEL_PACKAGES ($DEVEL_PACKAGES) file is not writable or doesn't exist"
exit 0
fi
case "$1" in
get)
shift
getdevel "$@"
;;
set)
shift
setdevel "$@"
;;
rm)
shift
rmdevel "$@"
;;
sync)
warning=0
badpkgs=""
pkgs=$(osc ls openSUSE:Factory)
# add new packages
for pkg in $pkgs; do
if [ "${pkg/*:*/IGNORE}" == "IGNORE" ]; then
continue
fi
grep -q "^$pkg\( \|\$\)" "$DEVEL_PACKAGES"
if [ $? -ne 0 ]; then
echo -n "$pkg -> "
devel=$(osc develproject openSUSE:Factory $pkg 2> /dev/null)
devel=${devel/\/*/}
if [ -z "$devel" ]; then
devel=$(osc rq list -s accepted -P openSUSE:Factory -p $pkg -t submit | grep "^\s*submit:.* -> openSUSE:Factory\$" | sed -e "s,^\s*submit:\s*\([^/]\+\)/${pkg}@.*,\1," | uniq)
c=$(echo "$devel" | grep -c .)
if [ $c -ne 1 ]; then
badpkgs="$badpkgs $pkg"
warning=1
devel="***** UNKNOWN"
fi
fi
setdevel "$devel" "$pkg"
echo "$devel"
fi
done
# remove deleted packages
for pkg in $(awk '{ print $1 }' < "$DEVEL_PACKAGES"); do
if [[ " $pkgs " != *[[:space:]]"$pkg"[[:space:]]* ]]; then
echo "removing $pkg"
d=$(getdevel "$pkg")
if [ -n "$d" ]; then
rmdevel "$d" "$pkg"
fi
fi
done
# set devel change in last 10 days
osc rq list -t change_devel -D 10 -P openSUSE:Factory -s accepted |
grep 'change_devel:\s\+openSUSE:Factory/' |
sed -e 's,^\s*change_devel:\s*openSUSE:Factory/\([a-zA-Z0-9_+-]\+\)\s*developed in \([a-zA-Z0-9_+:-]\+\)/\1\s*$,\2 \1,' |
while read line; do
setdevel ${line/ */} ${line/* /};
done
if [ $warning -ne 0 ]; then
echo " **** WARNING ****" > /dev/stderr
echo "Could not fix some packages. Manual intervention required:$badpkgs" > /dev/stderr
fi
;;
*)
echo " devel_update (get,set,rm,sync) ...."
esac

View File

@@ -168,13 +168,14 @@ func gitImporter(prj, pkg string) error {
func cloneDevel(git common.Git, gitDir, outName, urlString string) error {
url, err := url.Parse(urlString)
branch := url.Fragment
// branch := url.Fragment
url.Fragment = ""
params := []string{"clone"}
if len(branch) > 0 {
params = append(params, "-b", branch)
}
/* if len(branch) > 0 {
params = append(params, "-b", branch)
}
*/
params = append(params, url.String(), outName)
if err != nil {
@@ -206,6 +207,15 @@ func importRepos(packages []string) {
}
}
log.Println("Num repos found:", len(factoryRepos))
if len(develProjectPackages) > 0 {
log.Println("Num of repos that need to create:", len(develProjectPackages))
log.Println("Create the following packages in pool to continue:", strings.Join(develProjectPackages, " "))
if forceNonPoolPackages {
log.Println(" IGNORING and will create these as non-pool packages!")
} else {
os.Exit(1)
}
}
oldPackageNames := make([]string, 0, len(factoryRepos))
for _, repo := range factoryRepos {
@@ -241,15 +251,11 @@ func importRepos(packages []string) {
}
// scmsync?
devel_project, err := runObsCommand("develproject", "openSUSE:Factory", pkg.Name)
if err != nil || len(devel_project) != 1 {
log.Panicln("devel project len:", len(devel_project), "for", pkg.Name, "err:", err)
devel_project, err := devel_projects.GetDevelProject(pkg.Name)
if err != nil {
log.Panicln("devel project not found for", pkg.Name, "err:", err)
}
d := strings.Split(devel_project[0], "/")
if len(d) != 2 {
log.Panicln("expected devel project/package. got:", d)
}
meta, _ := obs.GetPackageMeta(d[0], d[1])
meta, _ := obs.GetPackageMeta(devel_project, pkg.Name)
if len(meta.ScmSync) > 0 {
if err2 := cloneDevel(git, "", pkg.Name, meta.ScmSync); err != nil {
log.Panicln(err2)
@@ -329,7 +335,7 @@ func importRepos(packages []string) {
break
} else {
log.Panicln(" *** factory has no branches", branches)
}
}
}
pool_branch := "factory"
@@ -457,15 +463,16 @@ func importRepos(packages []string) {
// branchName := repo.DefaultBranch
remotes := common.SplitStringNoEmpty(git.GitExecWithOutputOrPanic(pkg.Name, "remote", "show"), "\n")
if !slices.Contains(remotes, "devel") {
git.GitExecOrPanic(pkg.Name, "remote", "add", "devel", repo.SSHURL)
if !slices.Contains(remotes, "develorigin") {
git.GitExecOrPanic(pkg.Name, "remote", "add", "develorigin", repo.SSHURL)
// git.GitExecOrPanic(pkg.Name, "fetch", "devel")
}
if slices.Contains(remotes, "origin") {
git.GitExecOrPanic(pkg.Name, "lfs", "fetch", "--all")
git.GitExecOrPanic(pkg.Name, "lfs", "push", "devel", "--all")
git.GitExecOrPanic(pkg.Name, "lfs", "push", "develorigin", "--all")
}
git.GitExecOrPanic(pkg.Name, "push", "devel", "main", "-f")
git.GitExecOrPanic(pkg.Name, "push", "develorigin", "main", "-f")
git.GitExec(pkg.Name, "push", "develorigin", "--delete", "factory", "devel")
// git.GitExecOrPanic(pkg.Name, "checkout", "-B", "main", "devel/main")
_, err := client.Repository.RepoEdit(repository.NewRepoEditParams().WithOwner(org).WithRepo(repo.Name).WithBody(&models.EditRepoOption{
DefaultBranch: "main",
@@ -479,7 +486,8 @@ func importRepos(packages []string) {
AllowSquash: false,
AllowFastForwardOnly: true,
AllowRebaseUpdate: false,
AllowManualMerge: false,
AllowManualMerge: true,
AutodetectManualMerge: true,
AllowRebase: false,
DefaultAllowMaintainerEdit: true,
}), r.DefaultAuthentication)
@@ -517,7 +525,8 @@ func importRepos(packages []string) {
AllowSquash: false,
AllowFastForwardOnly: true,
AllowRebaseUpdate: false,
AllowManualMerge: false,
AllowManualMerge: true,
AutodetectManualMerge: true,
DefaultMergeStyle: "fast-forward-only",
AllowRebase: false,
DefaultAllowMaintainerEdit: true,
@@ -535,14 +544,15 @@ func importRepos(packages []string) {
}
remotes := common.SplitStringNoEmpty(git.GitExecWithOutputOrPanic(pkg, "remote", "show"), "\n")
if !slices.Contains(remotes, "devel") {
git.GitExecOrPanic(pkg, "remote", "add", "devel", repo.SSHURL)
if !slices.Contains(remotes, "develorigin") {
git.GitExecOrPanic(pkg, "remote", "add", "develorigin", repo.SSHURL)
}
if slices.Contains(remotes, "origin") {
git.GitExecOrPanic(pkg, "lfs", "fetch", "--all")
git.GitExecOrPanic(pkg, "lfs", "push", "devel", "--all")
git.GitExecOrPanic(pkg, "lfs", "push", "develorigin", "--all")
}
git.GitExecOrPanic(pkg, "push", "devel", "main", "-f")
git.GitExecOrPanic(pkg, "push", "develorigin", "main", "-f")
git.GitExec(pkg, "push", "develorigin", "--delete", "factory", "devel")
_, err := client.Repository.RepoEdit(repository.NewRepoEditParams().WithOwner(org).WithRepo(pkg).WithBody(&models.EditRepoOption{
DefaultBranch: "main",
@@ -696,6 +706,10 @@ func syncMaintainersToGitea(pkgs []string) {
devs := []string{}
for _, group := range prjMeta.Groups {
if group.GroupID == "factory-maintainers" {
log.Println("Ignoring factory-maintainers")
continue
}
teamMembers, err := obs.GetGroupMeta(group.GroupID)
if err != nil {
log.Panicln("failed to get group", err)
@@ -791,13 +805,20 @@ func createPrjGit() {
git.GitExecOrPanic(common.DefaultGitPrj, "add", "_config")
}
file, err = os.Create(path.Join(git.GetPath(), common.DefaultGitPrj, "project.build"))
file, err = os.Create(path.Join(git.GetPath(), common.DefaultGitPrj, "staging.config"))
if err != nil {
log.Panicln(err)
}
file.Write([]byte(prj))
file.WriteString("{\n // Reference build project\n \"ObsProject\": \""+prj+"\",\n}\n")
file.Close()
git.GitExecOrPanic(common.DefaultGitPrj, "add", "project.build")
git.GitExecOrPanic(common.DefaultGitPrj, "add", "staging.config")
if file, err = os.Create(path.Join(git.GetPath(), common.DefaultGitPrj, "workflow.config")); err != nil {
log.Panicln(err)
}
file.WriteString("{\n \"Workflows\": [\"direct\", \"pr\"],\n \"Organization\": \""+org+"\",\n}\n")
file.Close()
git.GitExecOrPanic(common.DefaultGitPrj, "add", "workflow.config")
}
}
}
@@ -808,6 +829,8 @@ var git common.Git
var obs *common.ObsClient
var prj, org string
var forceBadPool bool
var forceNonPoolPackages bool
var devel_projects common.DevelProjects
func main() {
if err := common.RequireGiteaSecretToken(); err != nil {
@@ -824,6 +847,7 @@ func main() {
flags.SetOutput(helpString)
//workflowConfig := flag.String("config", "", "Repository and workflow definition file")
giteaHost := flags.String("gitea", "src.opensuse.org", "Gitea instance")
obsUrl := flags.String("obs-url", "https://api.opensuse.org", "OBS API Url")
//rabbitUrl := flag.String("url", "amqps://rabbit.opensuse.org", "URL for RabbitMQ instance")
flags.BoolVar(&DebugMode, "debug", false, "Extra debugging information")
// revNew := flag.Int("nrevs", 20, "Number of new revisions in factory branch. Indicator of broken history import")
@@ -832,6 +856,7 @@ func main() {
getMaintainers := flags.Bool("maintainers-only", false, "Get maintainers only and exit")
syncMaintainers := flags.Bool("sync-maintainers-only", false, "Sync maintainers to Gitea and exit")
flags.BoolVar(&forceBadPool, "bad-pool", false, "Force packages if pool has no branches due to bad import")
flags.BoolVar(&forceNonPoolPackages, "non-pool", false, "Allow packages that are not in pool to be created. WARNING: Can't add to factory later!")
if help := flags.Parse(os.Args[1:]); help == flag.ErrHelp || flags.NArg() != 2 {
printHelp(helpString.String())
@@ -843,25 +868,30 @@ func main() {
// r.SetDebug(true)
client = apiclient.New(r, nil)
obs, _ = common.NewObsClient("api.opensuse.org")
obs, _ = common.NewObsClient(*obsUrl)
gh := common.GitHandlerGeneratorImpl{}
var gh common.GitHandlerGenerator
var err error
git, err = gh.CreateGitHandler("Autogits - Devel Importer", "not.exist", "devel-importer")
devel_projects, err = common.FetchDevelProjects()
if err != nil {
log.Panicln("Failed to allocate git handler. Err:", err)
log.Panic("Cannot load devel projects:", err)
}
log.Println("# devel projects loaded:", len(devel_projects))
if DebugMode {
if len(*debugGitPath) > 0 {
git.Close()
git, err = gh.ReadExistingPath("Autogits - Devel Importer", "not.exist", *debugGitPath)
gh, err = common.AllocateGitWorkTree(*debugGitPath, "Autogits - Devel Importer", "not.exist")
if err != nil {
log.Panicln(err)
}
}
log.Println(" - working directory:" + git.GetPath())
} else {
defer git.Close()
dir, _ := os.MkdirTemp(os.TempDir(), "devel-importer")
gh, err = common.AllocateGitWorkTree(dir, "Autogits - Devel Importer", "not.exist")
if err != nil {
log.Panicln("Failed to allocate git handler", err)
}
}
prj = flags.Arg(0)
@@ -875,6 +905,13 @@ func main() {
}
}
git, err = gh.CreateGitHandler(org)
if err != nil {
log.Panicln("Cannot create git", err)
}
defer git.Close()
log.Println(" - working directory:" + git.GetPath())
/*
for _, pkg := range packages {
if _, err := client.Organization.CreateOrgRepo(organization.NewCreateOrgRepoParams().WithOrg(org).WithBody(

View File

@@ -0,0 +1,15 @@
Kernel:firmware
Kernel:kdump
devel:languages:clojure
devel:languages:erlang
devel:languages:erlang:Factory
devel:languages:hare
devel:languages:javascript
devel:languages:lua
network:dhcp
network:im:whatsapp
network:messaging:xmpp
systemsmanagement:cockpit
systemsmanagement:wbem
X11:lxde

4
go.mod
View File

@@ -8,8 +8,9 @@ require (
github.com/go-openapi/strfmt v0.23.0
github.com/go-openapi/swag v0.23.0
github.com/go-openapi/validate v0.24.0
github.com/mattn/go-sqlite3 v1.14.22
github.com/opentracing/opentracing-go v1.2.0
github.com/rabbitmq/amqp091-go v1.10.0
github.com/tailscale/hujson v0.0.0-20250226034555-ec1d1c113d33
go.uber.org/mock v0.5.0
)
@@ -27,7 +28,6 @@ require (
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/oklog/ulid v1.3.1 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
go.mongodb.org/mongo-driver v1.14.0 // indirect
go.opentelemetry.io/otel v1.24.0 // indirect
go.opentelemetry.io/otel/metric v1.24.0 // indirect

4
go.sum
View File

@@ -40,8 +40,6 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
@@ -58,6 +56,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tailscale/hujson v0.0.0-20250226034555-ec1d1c113d33 h1:idh63uw+gsG05HwjZsAENCG4KZfyvjK03bpjxa5qRRk=
github.com/tailscale/hujson v0.0.0-20250226034555-ec1d1c113d33/go.mod h1:EbW0wDK/qEUYI0A5bqq0C2kF8JTQwWONmGDBbzsxxHo=
go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80=
go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=

View File

@@ -2,11 +2,14 @@ package main
import (
"flag"
"fmt"
"log"
"net/url"
"regexp"
"runtime/debug"
"slices"
"strconv"
"strings"
"time"
"src.opensuse.org/autogits/common"
@@ -14,105 +17,254 @@ import (
)
var configs common.AutogitConfigs
var reviewRx *regexp.Regexp
var acceptRx *regexp.Regexp
var rejectRx *regexp.Regexp
var groupName string
func InitRegex(groupName string) {
reviewRx = regexp.MustCompile("^" + groupName + "\\s*:\\s*LGTM")
rejectRx = regexp.MustCompile("^" + groupName + "\\s*:")
acceptRx = regexp.MustCompile("\\s*:\\s*LGTM")
rejectRx = regexp.MustCompile("\\s*:\\s*")
}
func ParseReviewLine(reviewText string) (bool, string) {
line := strings.TrimSpace(reviewText)
groupTextName := "@" + groupName
glen := len(groupTextName)
if len(line) < glen || line[0:glen] != groupTextName {
return false, line
}
return true, line[glen:]
}
func ReviewAccepted(reviewText string) bool {
return reviewRx.MatchString(reviewText)
for _, line := range common.SplitStringNoEmpty(reviewText, "\n") {
if matched, reviewLine := ParseReviewLine(line); matched {
return acceptRx.MatchString(reviewLine)
}
}
return false
}
func ReviewRejected(reviewText string) bool {
return rejectRx.MatchString(reviewText)
for _, line := range common.SplitStringNoEmpty(reviewText, "\n") {
if matched, reviewLine := ParseReviewLine(line); matched {
if rejectRx.MatchString(reviewLine) {
return !acceptRx.MatchString(reviewLine)
}
}
}
return false
}
/* comment types - from gitea models/issues/comment.go
var commentStrings = []string{
"comment",
"reopen",
"close",
"issue_ref",
"commit_ref",
"comment_ref",
"pull_ref",
"label",
"milestone",
"assignees",
"change_title",
"delete_branch",
"start_tracking",
"stop_tracking",
"add_time_manual",
"cancel_tracking",
"added_deadline",
"modified_deadline",
"removed_deadline",
"add_dependency",
"remove_dependency",
"code",
"review",
"lock",
"unlock",
"change_target_branch",
"delete_time_manual",
"review_request",
"merge_pull",
"pull_push",
"project",
"project_board", // FIXME: the name should be project_column
"dismiss_review",
"change_issue_ref",
"pull_scheduled_merge",
"pull_cancel_scheduled_merge",
"pin",
"unpin",
"change_time_estimate",
}*/
func FindAcceptableReviewInTimeline(user string, timeline []*models.TimelineComment, reviews []*models.PullReview) *models.TimelineComment {
for _, t := range timeline {
if t.Type == common.TimelineCommentType_Comment && t.User.UserName == user && t.Created == t.Updated {
if ReviewAccepted(t.Body) || ReviewRejected(t.Body) {
return t
}
}
}
return nil
}
func UnrequestReviews(gitea common.Gitea, org, repo string, id int64, users []string) {
if err := gitea.UnrequestReview(org, repo, id, users...); err != nil {
common.LogError("Can't remove reviewrs after a review:", err)
}
}
func ProcessNotifications(notification *models.NotificationThread, gitea common.Gitea) {
defer func() {
if r := recover(); r != nil {
log.Println("--- resovered")
common.LogInfo("panic cought --- recovered")
common.LogError(string(debug.Stack()))
}
}()
rx := regexp.MustCompile(`^https://src\.(?:open)?suse\.(?:org|de)/api/v\d+/repos/(?<org>[a-zA-Z0-9]+)/(?<project>[_a-zA-Z0-9]+)/issues/(?<num>[0-9]+)$`)
rx := regexp.MustCompile(`^/?api/v\d+/repos/(?<org>[_a-zA-Z0-9-]+)/(?<project>[_a-zA-Z0-9-]+)/(?:issues|pulls)/(?<num>[0-9]+)$`)
subject := notification.Subject
match := rx.FindStringSubmatch(subject.URL)
u, err := url.Parse(notification.Subject.URL)
if err != nil {
common.LogError("Invalid format of notification:", subject.URL, err)
return
}
match := rx.FindStringSubmatch(u.Path)
if match == nil {
log.Panicf("** Unexpected format of notification: %s", subject.URL)
common.LogError("** Unexpected format of notification:", subject.URL)
return
}
org := match[1]
repo := match[2]
id, _ := strconv.ParseInt(match[3], 10, 64)
log.Printf("processing: %s/%s#%d\n", org, repo, id)
common.LogInfo("processing:", fmt.Sprintf("%s/%s#%d", org, repo, id))
pr, err := gitea.GetPullRequest(org, repo, id)
if err != nil {
log.Println(" ** Cannot fetch PR associated with review:", subject.URL, "Error:", err)
common.LogError(" ** Cannot fetch PR associated with review:", subject.URL, "Error:", err)
return
}
found := false
for _, reviewer := range pr.RequestedReviewers {
if reviewer != nil && reviewer.UserName == groupName {
found = true
break
}
}
if !found {
common.LogInfo(" review is not requested for", groupName)
if !common.IsDryRun {
gitea.SetNotificationRead(notification.ID)
}
return
}
config := configs.GetPrjGitConfig(org, repo, pr.Base.Name)
if config == nil {
common.LogError("Cannot find config for:", fmt.Sprintf("%s/%s#%s", org, repo, pr.Base.Name))
return
}
if pr.State == "closed" {
// dismiss the review
log.Println(" -- closed request, so nothing to review")
gitea.SetNotificationRead(notification.ID)
common.LogInfo(" -- closed request, so nothing to review")
if !common.IsDryRun {
gitea.SetNotificationRead(notification.ID)
}
return
}
reviews, err := gitea.GetPullRequestReviews(org, repo, id)
if err != nil {
log.Println(" ** No reviews associated with request:", subject.URL, "Error:", err)
common.LogInfo(" ** No reviews associated with request:", subject.URL, "Error:", err)
return
}
timeline, err := common.FetchTimelineSinceReviewRequestOrPush(gitea, groupName, pr.Head.Sha, org, repo, id)
if err != nil {
common.LogError(err)
return
}
requestReviewers, err := config.GetReviewGroupMembers(groupName)
if err != nil {
log.Println(err)
common.LogError(err)
return
}
// submitter cannot be reviewer
requestReviewers = slices.DeleteFunc(requestReviewers, func(u string) bool { return u == pr.User.UserName })
// pr.Head.Sha
for _, review := range reviews {
user := review.User.UserName
if !review.Stale && !review.Dismissed &&
slices.Contains(requestReviewers, user) {
if review.State == common.ReviewStateApproved && ReviewAccepted(review.Body) {
gitea.AddReviewComment(pr, common.ReviewStateApproved, "Signed off by: "+user)
if err := gitea.SetNotificationRead(notification.ID); err != nil {
log.Println(" Cannot set notification as read", err)
for _, reviewer := range requestReviewers {
if review := FindAcceptableReviewInTimeline(reviewer, timeline, reviews); review != nil {
if ReviewAccepted(review.Body) {
if !common.IsDryRun {
gitea.AddReviewComment(pr, common.ReviewStateApproved, "Signed off by: "+reviewer)
UnrequestReviews(gitea, org, repo, id, requestReviewers)
if !common.IsDryRun {
if err := gitea.SetNotificationRead(notification.ID); err != nil {
common.LogDebug(" Cannot set notification as read", err)
}
}
}
log.Println(" -> approved by", user)
common.LogInfo(" -> approved by", reviewer)
common.LogInfo(" review at", review.Created)
return
} else if review.State == common.ReviewStateRequestChanges && ReviewRejected(review.Body) {
gitea.AddReviewComment(pr, common.ReviewStateRequestChanges, "Request changes. See review by: "+user)
if err := gitea.SetNotificationRead(notification.ID); err != nil {
log.Println(" Cannot set notification as read", err)
} else if ReviewRejected(review.Body) {
if !common.IsDryRun {
gitea.AddReviewComment(pr, common.ReviewStateRequestChanges, "Changes requested. See review by: "+reviewer)
UnrequestReviews(gitea, org, repo, id, requestReviewers)
if err := gitea.SetNotificationRead(notification.ID); err != nil {
common.LogDebug(" Cannot set notification as read", err)
}
}
log.Println(" -> declined by", user)
common.LogInfo(" -> declined by", reviewer)
return
}
}
}
// request group member reviews, if missing
log.Println(" Requesting reviews for:", requestReviewers)
if _, err := gitea.RequestReviews(pr, requestReviewers...); err != nil {
log.Println(" -> err:", err)
common.LogDebug(" Review incomplete...")
if len(requestReviewers) > 0 {
common.LogDebug(" Requesting reviews for:", requestReviewers)
if !common.IsDryRun {
if _, err := gitea.RequestReviews(pr, requestReviewers...); err != nil {
common.LogDebug(" -> err:", err)
}
} else {
common.LogDebug(" ^^^ not done")
}
} else {
common.LogDebug(" Not requesting additional reviewers")
}
// add a helpful comment, if not yet added
found_help_comment := false
for _, t := range timeline {
if t.Type == common.TimelineCommentType_Comment && t.User != nil && t.User.UserName == groupName {
found_help_comment = true
break
}
}
if !found_help_comment && !common.IsDryRun {
helpComment := fmt.Sprintln("Review by", groupName, "represents a group of reviewers:", strings.Join(requestReviewers, ", "), ". To review as part of this group, create a comment with contents @"+groupName+": LGTM on a separate line to accept a review. To request changes, write @"+groupName+": followed by reason for rejection. Do not use reviews to review as a group. Editing a comment invalidates that comment.")
gitea.AddComment(pr, helpComment)
}
}
func PeriodReviewCheck(gitea common.Gitea) {
notifications, err := gitea.GetPullNotifications(nil)
notifications, err := gitea.GetNotifications(common.GiteaNotificationType_Pull, nil)
if err != nil {
log.Println(" EEE Error fetching unread notifications: %w", err)
common.LogError(" Error fetching unread notifications: %w", err)
return
}
@@ -124,9 +276,11 @@ func PeriodReviewCheck(gitea common.Gitea) {
func main() {
giteaUrl := flag.String("gitea-url", "https://src.opensuse.org", "Gitea instance used for reviews")
rabbitMqHost := flag.String("rabbit-host", "rabbit.opensuse.org", "RabbitMQ instance where Gitea webhook notifications are sent")
rabbitMqHost := flag.String("rabbit-url", "amqps://rabbit.opensuse.org", "RabbitMQ instance where Gitea webhook notifications are sent")
interval := flag.Int64("interval", 5, "Notification polling interval in minutes (min 1 min)")
configFile := flag.String("config", "", "PrjGit listing config file")
logging := flag.String("logging", "info", "Logging level: [none, error, info, debug]")
flag.BoolVar(&common.IsDryRun, "dry", false, "Dry run, no effect. For debugging")
flag.Parse()
args := flag.Args()
@@ -139,29 +293,43 @@ func main() {
}
groupName = args[0]
if *configFile == "" {
common.LogError("Missing config file")
return
}
configData, err := common.ReadConfigFile(*configFile)
if err != nil {
log.Println("Failed to read config file", err)
common.LogError("Failed to read config file", err)
return
}
if err := common.RequireGiteaSecretToken(); err != nil {
log.Panicln(err)
common.LogError(err)
return
}
if err := common.RequireRabbitSecrets(); err != nil {
log.Panicln(err)
common.LogError(err)
return
}
gitea := common.AllocateGiteaTransport(*giteaUrl)
configs, err = common.ResolveWorkflowConfigs(gitea, configData)
if err != nil {
log.Panicln(err)
common.LogError("Cannot parse workflow configs:", err)
return
}
reviewer, err := gitea.GetCurrentUser()
if err != nil {
log.Panicln("Cannot fetch review user: %w", err)
common.LogError("Cannot fetch review user:", err)
return
}
if err := common.SetLoggingLevelFromString(*logging); err != nil {
common.LogError(err.Error())
return
}
if *interval < 1 {
@@ -170,33 +338,66 @@ func main() {
InitRegex(groupName)
log.Println(" ** processing group reviews for group:", groupName)
log.Println(" ** username in Gitea:", reviewer.UserName)
log.Println(" ** polling internval:", *interval, "min")
log.Println(" ** connecting to RabbitMQ:", *rabbitMqHost)
common.LogInfo(" ** processing group reviews for group:", groupName)
common.LogInfo(" ** username in Gitea:", reviewer.UserName)
common.LogInfo(" ** polling interval:", *interval, "min")
common.LogInfo(" ** connecting to RabbitMQ:", *rabbitMqHost)
if groupName != reviewer.UserName {
log.Println(" ***** Reviewer does not match group name. Aborting. *****")
common.LogError(" ***** Reviewer does not match group name. Aborting. *****")
return
}
_, err = url.Parse("amqps://" + *rabbitMqHost)
u, err := url.Parse(*rabbitMqHost)
if err != nil {
log.Panicln("Cannot parse RabbitMQ host:", err)
common.LogError("Cannot parse RabbitMQ host:", err)
return
}
/*
common.ListenDefinitions{
RabbitURL: u,
GitAuthor: groupName,
Orgs: []string{"#"},
Handlers: map[string]common.RequestProcessor{
common.RequestType_PRReviewRequest: ReviewRequest,
common.RequestType_PRReviewRejected: ProcessReview,
common.RequestType_PRReviewAccepted: ProcessReview,
},
config_update := ConfigUpdatePush{
config_modified: make(chan *common.AutogitConfig),
}
configUpdates := &common.ListenDefinitions{
RabbitURL: u,
Orgs: []string{},
Handlers: map[string]common.RequestProcessor{
common.RequestType_Push: &config_update,
},
}
for _, c := range configs {
if org, _, _ := c.GetPrjGit(); !slices.Contains(configUpdates.Orgs, org) {
configUpdates.Orgs = append(configUpdates.Orgs, org)
}
*/
}
go configUpdates.ProcessRabbitMQEvents()
for {
config_update_loop:
for {
select {
case configTouched, ok := <-config_update.config_modified:
if ok {
for idx, c := range configs {
if c == configTouched {
org, repo, branch := c.GetPrjGit()
prj := fmt.Sprintf("%s/%s#%s", org, repo, branch)
common.LogInfo("Detected config update for", prj)
new_config, err := common.ReadWorkflowConfig(gitea, prj)
if err != nil {
common.LogError("Failed parsing Project config for", prj, err)
} else {
configs[idx] = new_config
}
}
}
}
default:
break config_update_loop
}
}
PeriodReviewCheck(gitea)
time.Sleep(time.Duration(*interval * int64(time.Minute)))
}

View File

@@ -1 +1,56 @@
package main
import (
"fmt"
"slices"
"src.opensuse.org/autogits/common"
)
type ConfigUpdatePush struct {
config_modified chan *common.AutogitConfig
}
func (s *ConfigUpdatePush) ProcessFunc(req *common.Request) error {
if req.Type != common.RequestType_Push {
return fmt.Errorf("Unhandled, ignored request type: %s", req.Type)
}
data := req.Data.(*common.PushWebhookEvent)
org := data.Repository.Owner.Username
repo := data.Repository.Name
const branch_ref = "refs/heads/"
if data.Ref[:len(branch_ref)] != branch_ref {
return fmt.Errorf("No branch updated. Ref: %s", data.Ref)
}
branch := data.Ref[len(branch_ref):]
c := configs.GetPrjGitConfig(org, repo, branch)
if c == nil {
return nil
}
if o, p, b := c.GetPrjGit(); o != org || p != repo || b != branch {
return nil
}
modified_config := false
for _, commit := range data.Commits {
modified_config = modified_config ||
slices.Contains(commit.Modified, common.ProjectConfigFile) ||
slices.Contains(commit.Added, common.ProjectConfigFile) ||
slices.Contains(commit.Removed, common.ProjectConfigFile)
}
if modified_config {
for _, config := range configs {
if o, r, _ := config.GetPrjGit(); o == org && r == repo {
s.config_modified <- config
}
}
}
return nil
}

1
obs-forward-bot/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
forward-bot

293
obs-forward-bot/main.go Normal file
View File

@@ -0,0 +1,293 @@
package main
import (
"flag"
"fmt"
"log"
"net/url"
"os"
"regexp"
"runtime/debug"
"strconv"
"strings"
"time"
"src.opensuse.org/autogits/common"
"src.opensuse.org/autogits/common/gitea-generated/models"
)
var LastDevelProjectUpdate *time.Time
var Git common.GitHandlerGenerator
func DevelProjectForPR(pr *models.PullRequest) (*common.DevelProject, error) {
devels, err := common.FetchDevelProjects()
if err != nil {
common.LogError("Failed to fetch devel projects:", err)
return nil, err
}
org := pr.Head.Repo.Owner.UserName
pkg := pr.Head.Repo.Name
common.LogDebug("Looking for devel package", org, pkg)
for _, devel_project := range devels {
if devel_project.Package == pkg {
common.LogDebug("Fetching prject meta for", devel_project.Project)
meta, err := Obs.GetProjectMeta(devel_project.Project)
if err != nil {
common.LogError("Failed to fetch devel project OBS meta", err)
return nil, err
}
u, err := url.Parse(meta.ScmSync)
if err != nil {
common.LogError("Failed to parse project scm", err)
return nil, err
}
if u.Hostname() != "src.opensuse.org" || strings.TrimSuffix(u.Path[1:], ".git") != org+"/_ObsPrj" {
common.LogError("Invalid ScmSync format for devel project", meta.ScmSync, "Expected:", u.Path, "!=", org+"/_ObsPrj")
return nil, fmt.Errorf("Invalid ScmSync format for devel project %s", meta.ScmSync)
}
g, err := Git.CreateGitHandler(org)
if err != nil {
common.LogError("Failed to alloate git:", err)
return nil, err
}
defer g.Close()
branch := u.Fragment
u.Fragment = ""
_, err = g.GitClone(common.DefaultGitPrj, branch, u.String())
common.PanicOnError(err)
expectedSha, ok := g.GitSubmoduleCommitId(common.DefaultGitPrj, pkg, branch)
if !ok {
common.LogError("Failed to find", pkg, "in projectgit")
return nil, fmt.Errorf("failed to find %s in projectgit", pkg)
}
if expectedSha == pr.Head.Sha {
// found a match back to the devel project
return devel_project, nil
}
return nil, fmt.Errorf("Failed to match submission to devel project")
}
}
return nil, fmt.Errorf("Failed to find PR in a devel project. Ignoring")
}
func ProcessNotification(notification *models.NotificationThread) {
defer func() {
if r := recover(); r != nil {
common.LogInfo("panic cought --- recovered")
common.LogError(string(debug.Stack()))
}
}()
rx := regexp.MustCompile(`^/?api/v\d+/repos/(?<org>[_a-zA-Z0-9-]+)/(?<project>[_a-zA-Z0-9-]+)/(?:issues|pulls)/(?<num>[0-9]+)$`)
subject := notification.Subject
u, err := url.Parse(notification.Subject.URL)
if err != nil {
common.LogError("Invalid format of notification:", subject.URL, err)
return
}
match := rx.FindStringSubmatch(u.Path)
if match == nil {
common.LogError("** Unexpected format of notification:", subject.URL)
return
}
org := match[1]
repo := match[2]
id, _ := strconv.ParseInt(match[3], 10, 64)
common.LogInfo("processing:", fmt.Sprintf("%s/%s#%d", org, repo, id))
pr, err := Gitea.GetPullRequest(org, repo, id)
if err != nil {
common.LogError(" ** Cannot fetch PR associated with review:", subject.URL, "Error:", err)
return
}
repository := notification.Repository
repoorg := repository.Owner.UserName
reponame := repository.Name
if repoorg != org || reponame != repo {
common.LogError(" *** failed to parse org notification. Expected", repoorg, reponame)
return
}
headSha := pr.Head.Sha
timeline, err := common.FetchTimelineSinceLastPush(Gitea, headSha, org, repo, id)
if err != nil {
common.LogError("Failed to fetch comments:", err)
return
}
ObsSrFormat := "OBS SR#%d\n"
ExtractSR := func(body string) int {
rx := regexp.MustCompile("^OBS SR#(\\d+)$")
for _, line := range common.SplitLines(body) {
if m := rx.FindStringSubmatch(line); m != nil && len(m) == 2 {
id, _ := strconv.ParseInt(m[1], 10, 32)
return int(id)
}
}
return 0
}
common.LogDebug("notification", org, repo, id)
superseed := false
for _, timeline := range timeline {
if timeline.Type == common.TimelineCommentType_Comment && timeline.User.UserName == GiteaUser {
// check if SR comment referenced here
if sr := ExtractSR(timeline.Body); sr > 0 {
status, err := Obs.RequestStatus(sr)
if err != nil {
common.LogError("Failed to request OBS request status", err)
return
}
if superseed {
break
}
common.LogInfo("Found status:", status.State.State)
if !common.IsDryRun {
if status.State.State == common.RequestStatus_Accepted {
if _, err := Gitea.AddReviewComment(pr, common.ReviewStateApproved, "SR was accepted in OBS. Approving."); err != nil {
common.LogError("Failed to add review comment to PR:", err)
return
}
} else if status.State.State == common.RequestStatus_Declined || status.State.State == common.RequestStatus_Revoked {
if _, err := Gitea.AddReviewComment(pr, common.ReviewStateRequestChanges, "SR was rejected in OBS. Rejecting."); err != nil {
common.LogError("Failed to add review comment to PR:", err)
return
}
} else {
common.LogDebug("Request is in state:", status.State.State, "Waiting.")
return
}
Gitea.SetNotificationRead(notification.ID)
} else {
}
return
}
} else if timeline.Type == common.TimelineCommentType_PushPull {
superseed = true
}
}
// no current SR running, create one
dp, err := DevelProjectForPR(pr)
if err != nil {
common.LogDebug("Failed to process PR:", err)
return
}
if !common.IsDryRun {
meta, err := Obs.CreateSubmitRequest(dp.Project, dp.Package, ObsTarget)
if err != nil {
common.LogError("Failed to create OBS SR: ", dp.Project, dp.Package, "=>", ObsTarget, err)
return
}
for {
// make sure we leave comment here
err = Gitea.AddComment(pr, "Created OBS submit request to "+ObsTarget+"\n\n"+fmt.Sprintf(ObsSrFormat, meta.Id))
if err == nil {
break
}
common.LogError("Failed to create Gitea comment:", err)
common.LogInfo("Waiting 1 minute and retrying to leave comment...")
time.Sleep(time.Minute)
}
} else {
common.LogInfo("Would create a SR from", dp.Project, "/", dp.Package, "=>", ObsTarget)
}
}
func ProcessNotifications() {
// process PRs and issues
notifications, err := Gitea.GetNotifications(common.GiteaNotificationType_Pull, nil)
if err != nil {
common.LogError("Failed to get notifications.", err)
return
}
for _, notification := range notifications {
ProcessNotification(notification)
}
}
var GiteaUser string
var Gitea common.Gitea
var Obs *common.ObsClient
var ObsTarget, GiteaTargetBranch, GiteaOrg string
func main() {
GiteaHost := flag.String("gitea-host", "https://src.opensuse.org", "Gitea host")
ObsHost := flag.String("obs-host", "https://api.opensuse.org", "OBS instance")
flag.StringVar(&ObsTarget, "obs-target", "openSUSE:Factory", "")
flag.StringVar(&GiteaTargetBranch, "gitea-target", "factory", "")
flag.StringVar(&GiteaOrg, "gitea-org", "pool", "")
debug := flag.Bool("debug", false, "Debug logging")
GitRepoPath := flag.String("git-path", "", "Git repo path")
flag.BoolVar(&common.IsDryRun, "dry", false, "no-op operation")
flag.Parse()
if *debug {
common.SetLoggingLevel(common.LogLevelDebug)
}
var err error
if err = common.RequireGiteaSecretToken(); err != nil {
log.Panic(err)
}
if err = common.RequireObsSecretToken(); err != nil {
log.Panic(err)
}
if Obs, err = common.NewObsClient(*ObsHost); err != nil {
log.Panic(err)
}
Gitea = common.AllocateGiteaTransport(*GiteaHost)
if user, err := Gitea.GetCurrentUser(); err != nil {
log.Panic(err)
} else {
GiteaUser = user.UserName
}
common.LogInfo("Current user:", GiteaUser)
if len(*GitRepoPath) == 0 {
*GitRepoPath, err = os.MkdirTemp(os.TempDir(), "forward-bot")
if err != nil {
common.LogError("Failed to create tempdir:", err)
return
}
}
Git, err = common.AllocateGitWorkTree(*GitRepoPath, "bot", "nothing")
if err != nil {
common.LogError("Failed to allocate git tree", err)
return
}
for {
common.LogDebug("--- Starting processing notifications ---")
ProcessNotifications()
common.LogDebug("--- End processing notifications ---")
time.Sleep(time.Minute * 5)
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -5,6 +5,7 @@ import (
"strings"
"testing"
"src.opensuse.org/autogits/common"
"src.opensuse.org/autogits/common/gitea-generated/models"
)
@@ -16,23 +17,33 @@ func TestObsAPIHostFromWebHost(t *testing.T) {
}{
{
name: "api host",
api: "api.suse.de",
web: "build.suse.de",
api: "https://api.suse.de",
web: "https://build.suse.de",
},
{
name: "api host",
api: "api.opensuse.org",
web: "build.opensuse.org",
api: "https://api.opensuse.org",
web: "https://build.opensuse.org",
},
{
name: "other host",
api: "someapi.suse.de",
web: "someapi.suse.de",
api: "https://someapi.suse.de",
web: "https://someapi.suse.de",
},
{
name: "short host",
api: "s",
web: "s",
api: "https://s",
web: "https://s",
},
{
name: "other schema works",
api: "s://stuffhere",
web: "s://stuffhere",
},
{
name: "other schema works",
api: "s://api.stuffhere/foo",
web: "s://build.stuffhere/foo",
},
}
@@ -47,25 +58,32 @@ func TestObsAPIHostFromWebHost(t *testing.T) {
func TestPRtoObsProjectMapping(t *testing.T) {
tests := []struct {
name string
pr string // org/repo/prNo
config common.StagingConfig
name string
pr string // org/repo/prNo
expectedProject string
}{
{
name: "Regular project",
pr: "foobar/Repo/10",
expectedProject: "home:foo:foobar:Repo:PullRequest:10",
expectedProject: "home:foo:foobar:Repo:PR:10",
},
{
name: "underscore repo name",
pr: "foobar/_FooBar/10",
expectedProject: "home:foo:foobar:XFooBar:PullRequest:10",
expectedProject: "home:foo:foobar:XFooBar:PR:10",
},
{
name: "Underscore repo and project",
pr: "_some_thing/_FooBar/11",
expectedProject: "home:foo:Xsome_thing:XFooBar:PullRequest:11",
expectedProject: "home:foo:Xsome_thing:XFooBar:PR:11",
},
{
config: common.StagingConfig{StagingProject: "staging:project:Pull_Request"},
name: "with staging set",
pr: "_some_thing/_PrjX/14",
expectedProject: "staging:project:Pull_Request:14",
},
}
@@ -86,10 +104,13 @@ func TestPRtoObsProjectMapping(t *testing.T) {
Index: n,
}
p := getObsProjectAssociatedWithPr("home:foo", &pr)
p := GetObsProjectAssociatedWithPr(&test.config, "home:foo", &pr)
if p != test.expectedProject {
t.Error("invalid project:", p, "Expected:", test.expectedProject)
}
})
}
}
func TestStatusCodeResults(t *testing.T) {
}

View File

@@ -1,188 +0,0 @@
package main
/*
* This file is part of Autogits.
*
* Copyright © 2024 SUSE LLC
*
* Autogits is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 2 of the License, or (at your option) any later
* version.
*
* Autogits is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* Foobar. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"crypto/tls"
"encoding/json"
"log"
"strings"
"sync"
"time"
rabbitmq "github.com/rabbitmq/amqp091-go"
"src.opensuse.org/autogits/common"
"src.opensuse.org/autogits/common/gitea-generated/models"
)
type BuildNotification struct {
BuildSuccess bool
Project, Package, Repository, Arch, Release, Rev, Buildtype, Workerid string
Starttime, Endtime, Readytime string
}
var obsNotifications map[string]*BuildNotification // Project/Package/Repositry/Arch as key
var notificationMutex sync.RWMutex
var notificationChannels map[string][]chan *BuildNotification
func getProjectBuildStatus(project string) []*BuildNotification {
notificationMutex.RLock()
defer notificationMutex.RUnlock()
data := make([]*BuildNotification, 0, 4)
for _, val := range obsNotifications {
if val.Package == project {
data = append(data, val)
}
}
return data
}
func addProjectWatcher(meta *common.ProjectMeta, pr *models.PullReview) {
}
func addObsNotificationToCache(notification *BuildNotification) {
key := strings.Join(
[]string{
notification.Project,
notification.Package,
notification.Repository,
notification.Arch,
},
"/",
)
notificationMutex.Lock()
obsNotifications[key] = notification
chns, ok := notificationChannels[notification.Project]
notificationMutex.Unlock()
if ok {
for _, ch := range chns {
ch <- notification
}
}
}
func processObsMessage(msg *rabbitmq.Delivery) {
key := strings.SplitN(msg.RoutingKey, ".", 4)
if len(key) != 4 || len(key[3]) < 7 || key[3][:6] != "build_" {
return
}
buildSuccess := false
switch key[3][6:] {
case "success", "unchanged":
buildSuccess = true
case "fail":
buildSuccess = false
default:
log.Printf("unknown build_ logging message: %s\n", msg.RoutingKey)
return
}
notification := &BuildNotification{
BuildSuccess: buildSuccess,
}
err := json.Unmarshal(msg.Body, notification)
if err != nil {
log.Printf("Cannot unmarshall json object: %s\n", msg.Body)
return
}
log.Printf("%v\n", notification)
addObsNotificationToCache(notification)
}
func ProcessingObsMessages(host, username, password, queueName string) {
if obsNotifications == nil {
obsNotifications = make(map[string]*BuildNotification)
// notificationChannels = make(map[string]chan *BuildNotification)
}
auth := ""
if len(username) > 0 && len(password) > 0 {
auth = username + ":" + password + "@"
}
connection, err := rabbitmq.DialTLS("amqps://"+auth+host, &tls.Config{
ServerName: host,
})
failOnError(err, "Cannot connect to rabbit.opensuse.org")
defer connection.Close()
ch, err := connection.Channel()
failOnError(err, "Cannot create a channel")
defer ch.Close()
err = ch.ExchangeDeclarePassive("pubsub", "topic", true, false, false, false, nil)
failOnError(err, "Cannot find pubsub exchange")
var q rabbitmq.Queue
if len(queueName) == 0 {
q, err = ch.QueueDeclare("", false, true, true, false, nil)
} else {
q, err = ch.QueueDeclarePassive(queueName, true, false, true, false, nil)
if err != nil {
log.Printf("queue not found .. trying to create it: %v\n", err)
if ch.IsClosed() {
ch, err = connection.Channel()
failOnError(err, "Channel cannot be re-opened")
}
q, err = ch.QueueDeclare(queueName, true, false, true, false, nil)
if err != nil {
log.Printf("can't create persistent queue ... falling back to temporaty queue: %v\n", err)
if ch.IsClosed() {
ch, err = connection.Channel()
failOnError(err, "Channel cannot be re-opened")
}
q, err = ch.QueueDeclare("", false, true, true, false, nil)
}
}
}
failOnError(err, "Cannot declare queue")
log.Printf("queue: %s:%d", q.Name, q.Consumers)
err = ch.QueueBind(q.Name, "*.obs.package.*", "pubsub", false, nil)
failOnError(err, "Cannot bind queue to exchange")
msgs, err := ch.Consume(q.Name, "", true, true, false, false, nil)
failOnError(err, "Cannot start consumer")
log.Printf("queue: %s:%d", q.Name, q.Consumers)
for {
msg, ok := <-msgs
if !ok {
log.Printf("channel/connection closed?\n")
if connection.IsClosed() {
// reconnect
log.Printf("reconnecting...")
time.Sleep(5 * time.Second)
go ProcessingObsMessages(host, username, password, queueName)
}
return
}
processObsMessage(&msg)
}
}

View File

@@ -3,6 +3,11 @@ OBS Status Service
Reports build status of OBS service as an easily to produce SVG
Requests for individual build results:
/obs:project/package/repo/arch
Requests for project results
/obs:project
Areas of Responsibility
-----------------------

View File

@@ -19,100 +19,152 @@ package main
*/
import (
"bytes"
"flag"
"fmt"
"log"
"net/http"
"os"
"time"
"src.opensuse.org/autogits/common"
)
const (
ListenAddr = "[::1]:8003"
AppName = "obs-status-service"
AppName = "obs-status-service"
)
type BuildStatusCacheItem struct {
CacheTime time.Time
Result []*common.BuildResult
}
var obs *common.ObsClient
var buildStatusCache map[string]BuildStatusCacheItem
var debug bool
/*
func CacheBuildStatus(prj, pkg string) ([]common.BuildResult, error) {
list, err := obs.BuildStatus(prj, pkg)
if err != nil {
return nil, err
}
return
func LogDebug(v ...any) {
if debug {
log.Println(v...)
}
*/
func PackageBuildStatus(prj, pkg string) (common.ObsBuildStatusDetail, error) {
return common.ObsBuildStatusDetail{
Code: "succeeded",
Description: "stuff",
Success: true,
Finished: true,
}, nil
}
/*
func PackageStatusSvg(buildStatus []common.ObsBuildStatusDetail) []byte {
return
func ProjectStatusSummarySvg(project string) []byte {
res := GetCurrentStatus(project)
if res == nil {
return nil
}
*/
func PackageStatusSummarySvg(buildStatus common.ObsBuildStatusDetail) []byte {
fillColor := "orange"
textColor := "grey"
pkgs := res.GetPackageList()
maxLen := 0
for _, p := range pkgs {
maxLen = max(maxLen, len(p))
}
width := float32(len(res.Result))*1.5 + float32(maxLen)*0.8
height := 1.5*float32(maxLen) + 30
ret := bytes.Buffer{}
ret.WriteString(`<svg version="2.0" width="`)
ret.WriteString(fmt.Sprint(width))
ret.WriteString(`em" height="`)
ret.WriteString(fmt.Sprint(height))
ret.WriteString(`em" xmlns="http://www.w3.org/2000/svg">`)
ret.WriteString(`<defs>
<g id="f"> <!-- failed -->
<rect width="1em" height="1em" fill="#800" />
</g>
<g id="s"> <!--succeeded-->
<rect width="1em" height="1em" fill="#080" />
</g>
<g id="buidling"> <!--building-->
<rect width="1em" height="1em" fill="#880" />
</g>
</defs>`)
ret.WriteString(`<use href="#f" x="1em" y="2em"/>`)
ret.WriteString(`</svg>`)
return ret.Bytes()
}
func PackageStatusSummarySvg(status common.PackageBuildStatus) []byte {
buildStatus, ok := common.ObsBuildStatusDetails[status.Code]
if !ok {
buildStatus = common.ObsBuildStatusDetails["error"]
}
fillColor := "#480" // orange
textColor := "#888"
if buildStatus.Finished {
textColor = "black"
textColor = "#fff"
if buildStatus.Success {
fillColor = "green"
fillColor = "#080"
} else {
fillColor = "red"
fillColor = "#800"
}
}
return []byte(`
<svg version="1.1" width="200" height="20" xmlns="http://www.w3.org/2000/svg">
<rect width="100%" height="100%" fill="` + fillColor + `" />
<text x="20" y="25" font-size="60" text-anchor="middle" fill="` + textColor + `">` + buildStatus.Code + `</text>
log.Println(status, " -> ", buildStatus)
return []byte(`<svg version="2.0" width="8em" height="1.5em" xmlns="http://www.w3.org/2000/svg">
<rect width="100%" height="100%" fill="` + fillColor + `"/>
<text x="4em" y="1.1em" text-anchor="middle" fill="` + textColor + `">` + buildStatus.Code + `</text>
</svg>`)
}
func main() {
common.RequireObsSecretToken()
go ProcessingObsMessages("rabbit.opensuse.org", "opensuse", "opensuse", "pubsub")
cert := flag.String("cert-file", "", "TLS certificates file")
key := flag.String("key-file", "", "Private key for the TLS certificate")
listen := flag.String("listen", "[::1]:8080", "Listening string")
disableTls := flag.Bool("no-tls", false, "Disable TLS")
obsHost := flag.String("obs-host", "api.opensuse.org", "OBS API endpoint for package status information")
flag.BoolVar(&debug, "debug", false, "Enable debug logging")
flag.Parse()
obsHost := os.Getenv("OBS_HOSTNAME")
if len(obsHost) == 0 {
log.Fatal("OBS_HOSTNAME env required.")
common.PanicOnError(common.RequireObsSecretToken())
var err error
if obs, err = common.NewObsClient(*obsHost); err != nil {
log.Fatal(err)
}
/*
if obs, err := common.NewObsClient(obsHost); err != nil {
log.Fatal(err)
}
*/
http.HandleFunc("GET /{ObsProject}", func(res http.ResponseWriter, req *http.Request) {
http.HandleFunc("GET /{Project}", func(res http.ResponseWriter, req *http.Request) {
res.WriteHeader(http.StatusBadRequest)
})
http.HandleFunc("GET /{ObsProject}/{Package}", func(res http.ResponseWriter, req *http.Request) {
obsPrj := req.PathValue("ObsProject")
obsPkg := req.PathValue("ObsPackage")
http.HandleFunc("GET /{Project}/{Package}", func(res http.ResponseWriter, req *http.Request) {
/*
obsPrj := req.PathValue("Project")
obsPkg := req.PathValue("Package")
status, _ := PackageBuildStatus(obsPrj, obsPkg)
svg := PackageStatusSummarySvg(status)
status, _ := PackageBuildStatus(obsPrj, obsPkg)
svg := PackageStatusSummarySvg(status)
*/
res.Header().Add("content-type", "image/svg+xml")
res.Header().Add("size", fmt.Sprint(len(svg)))
res.Write(svg)
//res.Header().Add("size", fmt.Sprint(len(svg)))
//res.Write(svg)
})
http.HandleFunc("GET /{Project}/{Package}/{Repository}/{Arch}", func(res http.ResponseWriter, req *http.Request) {
prj := req.PathValue("Project")
pkg := req.PathValue("Package")
repo := req.PathValue("Repository")
arch := req.PathValue("Arch")
res.Header().Add("content-type", "image/svg+xml")
prjStatus := GetCurrentStatus(prj)
if prjStatus == nil {
return
}
for _, r := range prjStatus.Result {
if r.Arch == arch && r.Repository == repo {
for _, status := range r.Status {
if status.Package == pkg {
res.Write(PackageStatusSummarySvg(status))
return
}
}
}
}
})
log.Fatal(http.ListenAndServe(ListenAddr, nil))
go ProcessUpdates()
if *disableTls {
log.Fatal(http.ListenAndServe(*listen, nil))
} else {
log.Fatal(http.ListenAndServeTLS(*listen, *cert, *key, nil))
}
}

Some files were not shown because too many files have changed in this diff Show More