{"id":20385020,"url":"https://github.com/d-e-s-o/github-pull-request-mirror","last_synced_at":"2025-09-04T19:13:15.273Z","repository":{"id":83738518,"uuid":"162862449","full_name":"d-e-s-o/github-pull-request-mirror","owner":"d-e-s-o","description":"A Github web hook handler used for mirroring branches of pull requests locally.","archived":false,"fork":false,"pushed_at":"2019-12-25T18:31:42.000Z","size":25,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-07-17T11:06:18.311Z","etag":null,"topics":["github-api","github-webhooks","gitlab-ci","python","python3"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/d-e-s-o.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-12-23T04:34:38.000Z","updated_at":"2019-12-25T18:31:44.000Z","dependencies_parsed_at":null,"dependency_job_id":"4437b36d-866e-4c24-a4a7-7b9713ba8728","html_url":"https://github.com/d-e-s-o/github-pull-request-mirror","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/d-e-s-o/github-pull-request-mirror","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/d-e-s-o%2Fgithub-pull-request-mirror","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/d-e-s-o%2Fgithub-pull-request-mirror/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/d-e-s-o%2Fgithub-pull-request-mirror/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/d-e-s-o%2Fgithub-pull-request-mirror/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/d-e-s-o","download_url":"https://codeload.github.com/d-e-s-o/github-pull-request-mirror/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/d-e-s-o%2Fgithub-pull-request-mirror/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273658050,"owners_count":25145206,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-04T02:00:08.968Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["github-api","github-webhooks","gitlab-ci","python","python3"],"created_at":"2024-11-15T02:31:34.650Z","updated_at":"2025-09-04T19:13:10.224Z","avatar_url":"https://github.com/d-e-s-o.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"github-pull-request-mirror\n==========================\n\n`github-pull-request-mirror` is a program that can act as the end point\nto a [Github][github] web hook. Upon receiving notification that a pull\nrequest to one of the user's repositories was made, it creates a mirror\nof the branch to be merged in in the repository the pull request was\nmade in.\n\n\nMotivation\n----------\n\nGithub does not come with its own Continuous Integration (CI)\npipeline. There are various applications out there that provide such a\nservice, each with different trade-offs. The [Gitlab][gitlab] CI\npipeline was found to be very flexible and more configurable than most\nservices.\n\nThe way the Gitlab pipeline works is by mirroring (i.e., cloning) an\nexisting external repository (e.g., one hosted on Github). That is, it\nregisters a web hook with Github to be notified of new commits in the\nrepository and will update the cloned repository state in Gitlab\naccordingly.\n\nUnfortunately, this mechanism does not work for pull requests. A pull\nrequest on Github does **not** create a local branch in the repository\nthe merge is supposed to happen in. Without such a branch Gitlab's\nmirroring repository will never get the to-be-merged code and, hence,\nthe pipeline cannot run on it.\n\n`github-pull-request-mirror` bridges this gap by acting as a Github web\nhook endpoint in itself. Once it gets notified that a pull request on\nthe Github repository occurred, it will create a mirror of the branch\nthat is to be merged in in the local repository. This way, Gitlab will\nbe able to see a new branch/commit and can ensure to test it via its CI\npipeline.\n\n\nSetup\n-----\n\n### Github Configuration\n\nThere are two configurations that need to happen in order to register\nthis program on the Github side.\n1. An access token needs to be generated through which the program can\n   push a new branch to a user's repository. This can be created through\n   the [Github UI][github-tokens]. The token needs to have at least\n   access to the `public_repo` scope.\n2. A new web hook needs to be added that sends a `POST` request to a\n   server running `github-pull-request-mirror`. Such a web hook needs to\n   be added on a per repository basis. That can be done at\n   `https://github.com/\u003cuser\u003e/\u003crepo\u003e/settings/hooks`.\n   The fields should be set as follows:\n   - `Payload URL` is typically `https://\u003cdns-of-server\u003e:\u003cport\u003e`.\n   - `Content-Type` should be set to `application/json`.\n   - `Secret` can be any secret of your choosing. The same secret will\n     need to be supplied to the program (see [Usage](#usage))\n   - If you are not in possession of a certificate signed by a publicly\n     trusted certificate authority, you will have to create a\n     self-signed certificate (see [Server Setup](#server-setup)) and\n     disable `SSL verification`.\n   - The hook should be triggered only on `Pull requests` events. While\n     other events should not cause problems, they result in unnecessary\n     traffic.\n\n### Server Setup\n`github-pull-request-mirror` needs to run on some publicly reachable\nserver. The program unconditionally uses an SSL enabled HTTP server. As\nsuch, it requires a valid certificate to work with. If a certificate\nsigned by a trusted CA is not available, a self-signed certificate can\nbe used. This way all traffic is still encrypted, but Github will not be\nable to verify the authenticity of the host the request is sent to.\n\nA self-signed certificate can be created using OpenSSL, like so:\n```sh\nopenssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -nodes\n```\n\nNote that `-nodes` disables password protection of the associated key,\nwhich allows for easily using this certificate in a non-interactive\ncontext.\nUsing the above command, the certificate does not expire. Use the\noptional `-days` argument in order to limit its lifetime. Please refer\nto your favorite OpenSSL tutorial for a more comprehensive reference.\n\n### Usage\n\nA typical invocation looks as follows:\n```sh\npython3 main.py \u003cuser\u003e \u003ctoken\u003e \u003csecret\u003e cert.pem key.pem\n```\n\nHere `\u003cuser\u003e` is the user's Github user name. `\u003ctoken\u003e` is a token\ngenerated through the aforementioned [Github UI][github-tokens].\n`\u003csecret\u003e` is the secret configured for the web hook handling pull\nrequests.\n\nNote that by virtue of being a daemon style process, the program should\nlikely run under some sort of watchdog in case an error brings it down.\n\n\nSupport\n-------\n\nThe module is tested with Python 3. There is no work going on to ensure compatibility with Python 2.\n\n\n[github]: https://github.com/\n[github-tokens]: https://github.com/settings/tokens\n[gitlab]: https://gitlab.com/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fd-e-s-o%2Fgithub-pull-request-mirror","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fd-e-s-o%2Fgithub-pull-request-mirror","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fd-e-s-o%2Fgithub-pull-request-mirror/lists"}