diff --git a/docs/source/how-to-contribute/ROS-SIG-EUR-package-process.md b/docs/source/how-to-contribute/ROS-SIG-EUR-package-process.md index 6c81e4280264cb00b02bfa13dafb9c20c23ec0bb..fa4d4d48615741b575ec01624190214b8fcb3066 100644 --- a/docs/source/how-to-contribute/ROS-SIG-EUR-package-process.md +++ b/docs/source/how-to-contribute/ROS-SIG-EUR-package-process.md @@ -158,6 +158,174 @@ except CoprRequestException as ex: 这个代码是导入一个包的实现,可以自行修改代码里对应的内容,实现批量导入软件包 +### 6.2 从gitee仓库批量创建软件包 + +此脚本为从gitee仓库中导入某个分支的所有包,只需修改下面四个字段,导入成功会提示成功创建x个软件包,x个失败,失败的会返回失败原因; + +导入结束后可选择是否触发构建,输入y可以为所导入的包开始构建; + +```python +REPO_OWNER = "xxx" # 仓库拥有者或组织 +REPO_NAME = "xxx" # 仓库名称 +BRANCH_NAME = "xxx" # 分支名 +PROJECT_NAME = "xxx" # eur 工程名 +``` + +```python +from copr.v3 import Client, CoprRequestException +from copr.v3.proxies import BaseProxy +import requests +import os +import sys + +# monkey patch +def fixed_api_base_url(self): + return os.path.join(self.config["copr_url"], "api_3", "").replace("\\", "/") +BaseProxy.api_base_url = property(fixed_api_base_url) + +REPO_OWNER = "xxx" # 仓库拥有者或组织 +REPO_NAME = "xxx" # 仓库名称 +BRANCH_NAME = "xxx" # 分支名 +PROJECT_NAME = "xxx" # eur 工程名 + +def get_spec_files(repo_owner, repo_name, branch_name): + API_URL = f"https://gitee.com/api/v5/repos/{repo_owner}/{repo_name}/contents/" + spec_files = [] + + def get_directory_contents(path=""): + url = API_URL + path if path else API_URL + try: + response = requests.get(url, params={"ref": branch_name}) + if response.status_code == 200: + for item in response.json(): + if item.get('type') == 'file' and item.get('name', '').endswith('.spec'): + full_path = os.path.join(path, item['name']) if path else item['name'] + spec_files.append({ + 'name': item['name'], + 'path': full_path, + 'spec_name': item['name'].replace('.spec', '') + }) + elif item.get('type') == 'dir': + sub_path = os.path.join(path, item['name']) if path else item['name'] + get_directory_contents(sub_path) + except requests.exceptions.RequestException: + pass + + get_directory_contents() + return spec_files +def create_package_for_spec(client, project_name, repo_owner, repo_name, branch_name, spec_file): + package_name = f"ros-humble-{spec_file['spec_name']}" + + try: + client.project_proxy.get(ownername=client.config["username"], projectname=project_name) + client.package_proxy.add( + ownername=client.config["username"], + projectname=project_name, + packagename=package_name, + source_type="scm", + source_dict={ + "clone_url": f"https://gitee.com/{repo_owner}/{repo_name}.git", + "committish": branch_name, + "subdirectory": os.path.dirname(spec_file['path']) or "", + "spec": spec_file['name'], + "scm_type": "git" + } + ) + return True, None + except CoprRequestException as ex: + return False, str(ex) + + +def rebuild_all(client, project_name, spec_files_to_build): + """ + 触发列表中所有软件包的构建。 + """ + print(f"\n→ 正在为项目 {project_name} 触发 {len(spec_files_to_build)} 个软件包的构建...") + success_builds = 0 + failed_builds = [] + + for spec_file in spec_files_to_build: + package_name = f"ros-humble-{spec_file['spec_name']}" + try: + client.package_proxy.build( + ownername=client.config["username"], + projectname=project_name, + packagename=package_name + ) + print(f" ✓ 已提交 {package_name} 的构建请求") + success_builds += 1 + except CoprRequestException as ex: + print(f" ✗ 提交 {package_name} 构建失败: {ex}") + failed_builds.append((package_name, str(ex))) + except Exception as ex: + print(f" ✗ 提交 {package_name} 时发生未知错误: {ex}") + failed_builds.append((package_name, str(ex))) + + print(f"\n✓ 成功提交 {success_builds} 个构建请求。") + if failed_builds: + print(f"✗ 失败 {len(failed_builds)} 个:") + for pkg, err in failed_builds: + print(f" - {pkg}: {err}") + + print(" 请稍后在网页上查看构建状态。") + return True +def main(): + try: + client = Client.create_from_config_file("./copr.conf") + print("✓ 成功连接到 EUR 构建平台") + except Exception as e: + print(f"✗ 连接 EUR 构建平台失败: {e}") + return + + spec_files = get_spec_files(REPO_OWNER, REPO_NAME, BRANCH_NAME) + + if not spec_files: + print("✗ 未找到任何 spec 文件") + return + + print(f"✓ 从 {REPO_OWNER}/{REPO_NAME} 仓库,{BRANCH_NAME} 分支检索到 {len(spec_files)} 个 spec 文件") + print("→ 开始创建软件包...") + + success_count = 0 + failed_packages = [] + + for spec_file in spec_files: + success, error = create_package_for_spec(client, PROJECT_NAME, REPO_OWNER, REPO_NAME, BRANCH_NAME, spec_file) + if success: + success_count += 1 + else: + failed_packages.append((f"ros-humble-{spec_file['spec_name']}", error)) + + print(f"\n✓ 成功创建 {success_count} 个软件包", end="") + if failed_packages: + print(f",{len(failed_packages)} 个失败") + for pkg_name, error in failed_packages: + print(f" - {pkg_name}: {error}") + else: + print() + + while True: + response = input("\n是否触发构建? (y/n): ").strip().lower() + if response == 'y': + if not spec_files: + print("✗ 没有找到 spec 文件,无法触发构建。") + else: + rebuild_all(client, PROJECT_NAME, spec_files) + break + elif response == 'n': + print("任务结束") + break + else: + print("请输入 y 或 n") + +if __name__ == "__main__": + main() +``` + +运行结果如下,以moveit-resources为例: + +![alt text](image/eur/run_script.png) + 更多功能可以参考API文档 - diff --git a/docs/source/how-to-contribute/image/eur/run_script.png b/docs/source/how-to-contribute/image/eur/run_script.png new file mode 100644 index 0000000000000000000000000000000000000000..6645906a376a6dcedb233b50d1e420e8f8848434 Binary files /dev/null and b/docs/source/how-to-contribute/image/eur/run_script.png differ