-
Notifications
You must be signed in to change notification settings - Fork 59
Implement dist-git onboarding #3013
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -342,6 +342,69 @@ def from_number(number: int): | |||||||||
| # Default URL of the logdetective-packit interface server for sending the Log Detective requests. | ||||||||||
| LOGDETECTIVE_PACKIT_SERVER_URL = "https://logdetective01.fedorainfracloud.org" | ||||||||||
|
|
||||||||||
| DG_ONBOARDING_TITLE = "Add initial Packit configuration" | ||||||||||
| DG_ONBOARDING_DESCRIPTION = """ | ||||||||||
| Hello, | ||||||||||
|
|
||||||||||
| thank you for introducing a new package to Fedora! | ||||||||||
|
|
||||||||||
| Let us present you [Packit](https://packit.dev/), an automation for Fedora releases. | ||||||||||
| We are sending a configuration file with a basic setup. | ||||||||||
| The automation will be enabled by merging this pull-request into the `rawhide` branch. | ||||||||||
|
|
||||||||||
| If you have any question or concern, ask here or on `#packit:fedora.im` Matrix channel | ||||||||||
| and Packit team will help. | ||||||||||
|
|
||||||||||
| If you look at the configuration file, you can see that Packit is configured to do 3 jobs for you: | ||||||||||
| * [`pull_from_upstream`](https://packit.dev/docs/configuration/downstream/pull_from_upstream): | ||||||||||
| Create a new set of pull-requests when there is a new upstream release. | ||||||||||
| (The specfile-changes and sources are taken care of. Packit is notified about new release from | ||||||||||
| [Release Monitoring](https://release-monitoring.org/) service. Check if your project is there.) | ||||||||||
| * [`koji_build`](https://packit.dev/docs/configuration/downstream/koji_build): | ||||||||||
| Submit a Koji build as reaction to a merged pull request. | ||||||||||
| * [`bodhi_update`](https://packit.dev/docs/configuration/downstream/bodhi_update): | ||||||||||
| Create a Bodhi update as a reaction to a succesful Koji build. | ||||||||||
|
|
||||||||||
| These jobs are independent so you can pick just those that are relevant to you. | ||||||||||
| For each, you can also configure Fedora/EPEL versions other than Rawhide that the jobs | ||||||||||
| should be run for. | ||||||||||
|
|
||||||||||
| You can also further tweak the process. A few handy options are prepared for you | ||||||||||
| in the confguration file to uncomment. Rest can be found in | ||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
| [the documentation](https://packit.dev/docs/fedora-releases-guide/dist-git-onboarding). | ||||||||||
| In case you have a group of dependent packages, you might want to take a look at | ||||||||||
| [how to configure multi-package updates] | ||||||||||
| (https://packit.dev/docs/fedora-releases-guide/releasing-multiple-packages). | ||||||||||
|
Comment on lines
+376
to
+377
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
|
|
||||||||||
|
|
||||||||||
| Things you still need to be aware of: | ||||||||||
|
|
||||||||||
| * The package maintenance is still your responsibility -- Packit is just a handy tool that can | ||||||||||
| save you some time. | ||||||||||
| * When Packit introduces new releases in form of the pull-request, it's your responsibility | ||||||||||
| to check the pull-request including the newly-introduced source. This is the place where human | ||||||||||
| intervention is required. | ||||||||||
| * Be aware that there are other packages and packagers and that you might break someone else's work | ||||||||||
| by using Packit in a wrong way. (E.g. be careful about dependent packages since there is | ||||||||||
|
Comment on lines
+387
to
+388
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
I would just use a bit milder tone here. |
||||||||||
| no automatic check for these in place.) | ||||||||||
| * Check [Fedora updates policy](https://docs.fedoraproject.org/en-US/fesco/Updates_Policy/). | ||||||||||
| * Check [Fedora Packaging guidelines](https://docs.fedoraproject.org/en-US/packaging-guidelines/) | ||||||||||
| including the specifics for your package type. | ||||||||||
| * Consult the approach with other maintainers of this package and care about the Packit results | ||||||||||
| so you don't introduce spam and extra work for others. | ||||||||||
| * Speaking of notifications -- you might want to setup a rule on | ||||||||||
| [Fedora Notifications](https://notifications.fedoraproject.org/) so you won't miss | ||||||||||
| anything important, since `packit` FAS account will be the actor of the jobs. | ||||||||||
|
|
||||||||||
|
|
||||||||||
| In case you don't want to receive these pull-requests in the future, you can use | ||||||||||
| the `--onboard-packit no` option when running `fedpkg request-repo`. | ||||||||||
|
Comment on lines
+400
to
+401
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe we could also mention that they can easily disable packit by either removing particular jobs or the file itself (emphasis on rawhide branch) |
||||||||||
|
|
||||||||||
|
|
||||||||||
| I hope you will be happy with the automation! | ||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
| *[Packit team](https://packit.dev/#contact)* | ||||||||||
| """ | ||||||||||
|
|
||||||||||
| # CI Transition comment for Fedora dist-git PRs | ||||||||||
| # TODO: Remove this after March 2026 | ||||||||||
| # https://github.com/packit/packit-service/issues/3008 | ||||||||||
|
|
||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| # Copyright Contributors to the Packit project. | ||
| # SPDX-License-Identifier: MIT | ||
|
|
||
| from typing import Optional | ||
|
|
||
| from packit.config import PackageConfig | ||
|
|
||
| from .abstract.base import ForgeIndependent | ||
|
|
||
|
|
||
| class Request(ForgeIndependent): | ||
| @classmethod | ||
| def event_type(cls) -> str: | ||
| return "onboarding.Request" | ||
|
|
||
| def __init__( | ||
| self, | ||
| package: str, | ||
| open_pr: bool = True, | ||
| ): | ||
| super().__init__(project_url=f"https://src.fedoraproject.org/rpms/{package}") | ||
| self.open_pr = open_pr | ||
|
|
||
| def get_packages_config(self) -> Optional[PackageConfig]: | ||
| return None |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| # Copyright Contributors to the Packit project. | ||
| # SPDX-License-Identifier: MIT | ||
|
|
||
| import logging | ||
| from http import HTTPStatus | ||
| from os import getenv | ||
|
|
||
| from flask import request | ||
| from flask_restx import Namespace, Resource, fields | ||
|
|
||
| from packit_service.celerizer import celery_app | ||
| from packit_service.config import ServiceConfig | ||
| from packit_service.constants import CELERY_DEFAULT_MAIN_TASK_NAME | ||
| from packit_service.service.api.errors import ValidationFailed | ||
|
|
||
| logger = logging.getLogger("packit_service") | ||
nforro marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| config = ServiceConfig.get_service_config() | ||
|
|
||
| ns = Namespace("onboarding", description="Packit dist-git onboarding") | ||
|
|
||
| payload = ns.model( | ||
| "Packit dist-git onboarding request", | ||
| { | ||
| "package": fields.String(required=True, example="packit"), | ||
| "open_pr": fields.Boolean(required=True, default=True), | ||
| "token": fields.String(required=True, example="HERE-IS-A-VALID-TOKEN"), | ||
| }, | ||
| ) | ||
|
|
||
|
|
||
| @ns.route("/request") | ||
| class OnboardingRequest(Resource): | ||
| @ns.response(HTTPStatus.OK.value, "Request has been accepted") | ||
| @ns.response(HTTPStatus.BAD_REQUEST.value, "Bad request data") | ||
| @ns.response(HTTPStatus.UNAUTHORIZED.value, "Secret validation failed") | ||
| @ns.expect(payload) | ||
| def post(self): | ||
| msg = request.json | ||
|
|
||
| if not msg: | ||
| logger.debug("/onboarding/request: we haven't received any JSON data.") | ||
| return "We haven't received any JSON data.", HTTPStatus.BAD_REQUEST | ||
|
|
||
| try: | ||
| self.validate_onboarding_request() | ||
| except ValidationFailed as exc: | ||
| logger.info(f"/onboarding/request {exc}") | ||
| return str(exc), HTTPStatus.UNAUTHORIZED | ||
|
|
||
| msg["source"] = "onboarding" | ||
|
|
||
| celery_app.send_task( | ||
| name=getenv("CELERY_MAIN_TASK_NAME") or CELERY_DEFAULT_MAIN_TASK_NAME, | ||
| kwargs={ | ||
| "event": msg, | ||
| "source": "onboarding", | ||
| "event_type": "request", | ||
| }, | ||
| ) | ||
|
|
||
| return "Onboarding request accepted", HTTPStatus.OK | ||
|
|
||
| @staticmethod | ||
| def validate_onboarding_request(): | ||
| if not config.onboarding_secret: | ||
| msg = "Onboarding secret not specified in config" | ||
| logger.error(msg) | ||
| raise ValidationFailed(msg) | ||
|
|
||
| if not (token := request.json.get("token")): | ||
| msg = "The request doesn't contain any token" | ||
| logger.info(msg) | ||
| raise ValidationFailed(msg) | ||
nforro marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| if token == config.onboarding_secret: | ||
| return | ||
nforro marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| msg = "Invalid onboarding secret provided" | ||
| logger.warning(msg) | ||
| raise ValidationFailed(msg) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| # Copyright Contributors to the Packit project. | ||
| # SPDX-License-Identifier: MIT | ||
|
|
||
| import logging | ||
|
|
||
| from packit.constants import CONFIG_FILE_NAMES | ||
|
|
||
| from packit_service.worker.checker.abstract import Checker | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| class ProjectIsNotOnboarded(Checker): | ||
| def pre_check(self) -> bool: | ||
| if any(f for f in self.project.get_files(ref="rawhide") if f in CONFIG_FILE_NAMES): | ||
| logger.info(f"Package {self.project.repo} is already onboarded") | ||
| return False | ||
| return True |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| # Copyright Contributors to the Packit project. | ||
| # SPDX-License-Identifier: MIT | ||
|
|
||
| """ | ||
| This file defines classes for job handlers specific to onboarding tasks | ||
| """ | ||
|
|
||
| import logging | ||
|
|
||
| from packit.cli.dist_git_init import ( | ||
| COMMIT_MESSAGE, | ||
| CONFIG_FILE_NAME, | ||
| ONBOARD_BRANCH_NAME, | ||
| DistGitInitializer, | ||
| ) | ||
| from packit.config.config import Config | ||
| from packit.config.package_config import PackageConfig | ||
|
|
||
| from packit_service.constants import DG_ONBOARDING_DESCRIPTION, DG_ONBOARDING_TITLE | ||
| from packit_service.events import ( | ||
| onboarding, | ||
| ) | ||
| from packit_service.worker.checker.abstract import Checker | ||
| from packit_service.worker.checker.onboarding import ProjectIsNotOnboarded | ||
| from packit_service.worker.handlers.abstract import ( | ||
| JobHandler, | ||
| TaskName, | ||
| reacts_to, | ||
| ) | ||
| from packit_service.worker.mixin import ConfigFromEventMixin, PackitAPIWithDownstreamMixin | ||
| from packit_service.worker.result import TaskResults | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| @reacts_to(event=onboarding.Request) | ||
| class OnboardingRequestHandler( | ||
| JobHandler, | ||
| ConfigFromEventMixin, | ||
| PackitAPIWithDownstreamMixin, | ||
| ): | ||
| task_name = TaskName.onboarding_request | ||
|
|
||
| @staticmethod | ||
| def get_checkers() -> tuple[type[Checker], ...]: | ||
| return (ProjectIsNotOnboarded,) | ||
|
|
||
| def _run(self) -> TaskResults: | ||
| package = self.project.repo | ||
| logger.debug(f"Running onboarding for {package}") | ||
|
|
||
| # generate and load config | ||
| initializer = DistGitInitializer( | ||
| config=Config(), | ||
| path_or_url="", | ||
| upstream_git_url=None, | ||
| ) | ||
| self.package_config = self.job_config = PackageConfig.get_from_dict( | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we actually need these?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| initializer.package_config_dict | {"downstream_package_name": package}, | ||
| ) | ||
|
|
||
| self.perform_onboarding( | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we need some exception handling here?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure... it should be retried automatically on common exceptions, but perhaps it would be better to be explicit about it. |
||
| config=initializer.package_config_content, | ||
| open_pr=self.data.event_dict.get("open_pr", True), | ||
| ) | ||
|
|
||
| return TaskResults(success=True, details={}) | ||
|
|
||
| def perform_onboarding(self, config: str, open_pr: bool) -> None: | ||
| # clone the repo and fetch rawhide | ||
| self.packit_api.dg.create_branch( | ||
| "rawhide", | ||
| base="remotes/origin/rawhide", | ||
| setup_tracking=True, | ||
| ) | ||
| self.packit_api.dg.update_branch("rawhide") | ||
| self.packit_api.dg.switch_branch("rawhide", force=True) | ||
|
|
||
| if open_pr: | ||
| self.packit_api.dg.create_branch(ONBOARD_BRANCH_NAME) | ||
| self.packit_api.dg.switch_branch(ONBOARD_BRANCH_NAME, force=True) | ||
| self.packit_api.dg.reset_workdir() | ||
|
|
||
| working_dir = self.packit_api.dg.local_project.working_dir | ||
|
|
||
| # create config file | ||
| (working_dir / CONFIG_FILE_NAME).write_text(config) | ||
|
|
||
| self.packit_api.dg.commit( | ||
| title=COMMIT_MESSAGE, | ||
| msg="", | ||
| prefix="", | ||
| ) | ||
|
|
||
| if open_pr: | ||
| self.packit_api.push_and_create_pr( | ||
| pr_title=DG_ONBOARDING_TITLE, | ||
| pr_description=DG_ONBOARDING_DESCRIPTION, | ||
| git_branch="rawhide", | ||
| repo=self.packit_api.dg, | ||
| ) | ||
| else: | ||
| self.packit_api.dg.push(refspec="HEAD:rawhide") | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.