|
| 1 | +import re |
| 2 | +import sys |
| 3 | +import osc.commandline_git |
| 4 | + |
| 5 | + |
| 6 | +class TestPrjCommand(osc.commandline_git.GitObsCommand): |
| 7 | + """ |
| 8 | + Create test project in OBS linking git packages |
| 9 | + """ |
| 10 | + |
| 11 | + name = "testprj" |
| 12 | + |
| 13 | + def init_arguments(self): |
| 14 | + self.add_argument( |
| 15 | + "-a", |
| 16 | + "--api-url", |
| 17 | + help="OBS api url, defaults to api.opensuse.org", |
| 18 | + default="api.opensuse.org", |
| 19 | + ) |
| 20 | + self.add_argument( |
| 21 | + "-p", |
| 22 | + "--prj", |
| 23 | + help="OBS base project to copy config from, defaults to openSUSE:Factory", |
| 24 | + ) |
| 25 | + self.add_argument( |
| 26 | + "-b", |
| 27 | + "--branch", |
| 28 | + help="Git branch to use", |
| 29 | + ) |
| 30 | + self.add_argument( |
| 31 | + "-f", |
| 32 | + "--fork", |
| 33 | + action="store_true", |
| 34 | + help="Fork gitea pkg repos in your user home, defaults to False", |
| 35 | + default=False, |
| 36 | + ) |
| 37 | + self.add_argument( |
| 38 | + "prj_name", |
| 39 | + help="test project name to create in home:USER:$prj_name", |
| 40 | + ) |
| 41 | + self.add_argument( |
| 42 | + "pkg_repo", |
| 43 | + nargs="*", |
| 44 | + help="pkg gitea ref, it should be [org/]repo[#branch]", |
| 45 | + ) |
| 46 | + |
| 47 | + def run(self, args): |
| 48 | + from osc import conf |
| 49 | + |
| 50 | + self.output = [] |
| 51 | + self.apiurl = conf.sanitize_apiurl(args.api_url) |
| 52 | + self.args = args |
| 53 | + self.weburl = self.apiurl.replace("api", "build", count=1) |
| 54 | + |
| 55 | + c = conf.get_config() |
| 56 | + self.user = conf.get_apiurl_usr(self.apiurl) |
| 57 | + |
| 58 | + project = f"home:{self.user}:{self.args.prj_name}" |
| 59 | + self.create_project(project) |
| 60 | + self.output.append(f"OBS test project created: {project}") |
| 61 | + self.output.append(f"{self.weburl}/project/show/{project}") |
| 62 | + self.output.append("") |
| 63 | + |
| 64 | + self.num_entries = 0 |
| 65 | + self.failed_entries = [] |
| 66 | + for repo in args.pkg_repo: |
| 67 | + repo, branch = self.parse_repo(repo) |
| 68 | + package, scm = self.create_package(project, repo, branch) |
| 69 | + self.output.append(f" * Linked pkg: {package} <- {scm}") |
| 70 | + |
| 71 | + print() |
| 72 | + for line in self.output: |
| 73 | + print(line, file=sys.stderr) |
| 74 | + |
| 75 | + def create_project(self, project): |
| 76 | + from osc.util.xml import ET |
| 77 | + from osc.core import edit_meta, xml_fromstring, show_project_meta |
| 78 | + |
| 79 | + # Get base project meta |
| 80 | + if self.args.prj: |
| 81 | + meta_data = b''.join(show_project_meta(self.apiurl, self.args.prj)) |
| 82 | + root = xml_fromstring(meta_data) |
| 83 | + repos = "\n".join(ET.tostring(i).decode() for i in root.findall("repository")) |
| 84 | + else: |
| 85 | + repos = """ |
| 86 | + <repository name="openSUSE_Tumbleweed"> |
| 87 | + <path project="openSUSE:Tumbleweed" repository="standard"/> |
| 88 | + <arch>x86_64</arch> |
| 89 | + </repository> |
| 90 | + """ |
| 91 | + |
| 92 | + data = f""" |
| 93 | +<project name="{project}"> |
| 94 | + <title>Test project gitea</title> |
| 95 | + <description/> |
| 96 | + <person userid="{self.user}" role="maintainer"/> |
| 97 | + {repos} |
| 98 | +</project> |
| 99 | +""" |
| 100 | + |
| 101 | + # Create the project in OBS |
| 102 | + edit_meta(metatype="prj", |
| 103 | + data=data, |
| 104 | + apiurl=self.apiurl, |
| 105 | + path_args=(project, )) |
| 106 | + |
| 107 | + def create_package(self, project, repo, branch): |
| 108 | + from osc.core import edit_meta |
| 109 | + |
| 110 | + package = repo.repo |
| 111 | + if self.args.fork: |
| 112 | + scm = self.fork(repo, branch, self.args.branch) |
| 113 | + else: |
| 114 | + scm = f"{repo.clone_url}#{branch}" |
| 115 | + |
| 116 | + # Create the package in OBS |
| 117 | + data = f""" |
| 118 | +<package name="{package}" project="{project}"> |
| 119 | + <title/> |
| 120 | + <description/> |
| 121 | + <person userid="{self.user}" role="maintainer"/> |
| 122 | + <scmsync>{scm}</scmsync> |
| 123 | +</package> |
| 124 | + """ |
| 125 | + |
| 126 | + edit_meta(metatype="pkg", |
| 127 | + data=data, |
| 128 | + apiurl=self.apiurl, |
| 129 | + path_args=(project, package)) |
| 130 | + |
| 131 | + return package, scm |
| 132 | + |
| 133 | + def fork(self, repo, base_branch, new_branch=None): |
| 134 | + from osc import gitea_api |
| 135 | + owner, repo = repo.owner, repo.repo |
| 136 | + print(f"Forking git repo {owner}/{repo} ...", file=sys.stderr) |
| 137 | + try: |
| 138 | + repo_obj = gitea_api.Fork.create(self.gitea_conn, owner, repo) |
| 139 | + fork_owner = repo_obj.owner |
| 140 | + fork_repo = repo_obj.repo |
| 141 | + print(f" * Fork created: {fork_owner}/{fork_repo}", file=sys.stderr) |
| 142 | + self.num_entries += 1 |
| 143 | + except gitea_api.ForkExists as e: |
| 144 | + fork_owner = e.fork_owner |
| 145 | + fork_repo = e.fork_repo |
| 146 | + print(f" * Fork already exists: {fork_owner}/{fork_repo}", file=sys.stderr) |
| 147 | + self.num_entries += 1 |
| 148 | + except gitea_api.GiteaException as e: |
| 149 | + if e.status == 404: |
| 150 | + print(f" * ERROR: Repo doesn't exist: {owner}/{repo}", file=sys.stderr) |
| 151 | + self.failed_entries.append(f"{owner}/{repo}") |
| 152 | + return None |
| 153 | + raise |
| 154 | + |
| 155 | + r = gitea_api.Repo.get(self.gitea_conn, fork_owner, fork_repo) |
| 156 | + if new_branch: |
| 157 | + try: |
| 158 | + _branch = gitea_api.Branch.create(self.gitea_conn, fork_owner, |
| 159 | + fork_repo, new_branch_name=new_branch, |
| 160 | + old_ref_name=base_branch) |
| 161 | + except gitea_api.BranchExists: |
| 162 | + print(f" * Warning: Branch already exists, not creating it: {fork_owner}/{fork_repo}#{new_branch}", file=sys.stderr) |
| 163 | + |
| 164 | + branch = new_branch or base_branch |
| 165 | + return f"{r.clone_url}#{branch}" |
| 166 | + |
| 167 | + def parse_repo(self, repo): |
| 168 | + """ |
| 169 | + Convert org/repo#branch into gitea repo |
| 170 | + org and branch are optional, default org is "pool" and default |
| 171 | + branch is the default branch configured in gitea. |
| 172 | +
|
| 173 | + returns [Repo, branch] |
| 174 | + """ |
| 175 | + from osc import gitea_api |
| 176 | + |
| 177 | + org = "pool" |
| 178 | + if "/" in repo: |
| 179 | + org, repo = repo.split("/", maxsplit=1) |
| 180 | + if "#" in repo: |
| 181 | + repo, branch = repo.split("#", maxsplit=1) |
| 182 | + else: |
| 183 | + branch = None |
| 184 | + |
| 185 | + r = gitea_api.Repo.get(self.gitea_conn, org, repo) |
| 186 | + return r, branch or r.default_branch |
0 commit comments