pytest-dev / pytest

The pytest framework makes it easy to write small tests, yet scales to support complex functional testing
https://pytest.org
MIT License
11.82k stars 2.63k forks source link

Backport workflow: Use access token to run CI on PRs? #9554

Closed The-Compiler closed 2 months ago

The-Compiler commented 2 years ago

Regarding CI not running, right - CI doesn't run when triggered this way - this also happens for the create-pull-request actions and similar. Workaround is to close & reopen, then it triggers. It's also possible to use a user token (pytestbot), but that has its own security considerations.

Originally posted by @bluetech in https://github.com/pytest-dev/pytest/issues/9430#issuecomment-1004842182

webknjaz commented 2 years ago

It's also possible to use a user token (pytestbot), but that has its own security considerations.

Instead of using a PAT, I'd recommend making a GitHub App and provisioning its credentials to the workflow via https://github.com/marketplace/actions/github-app-token + use environments feature in workflows so that the secrets are not global.

Another hack I've been using is adding a deployment key to the repo + adding its private key as a secret. Then, in the workflows, add ssh-key to actions/checkout@v2 with that. Then, any subsequent Git interactions in the job will be configured to use that SSH key, enabling the push event propagation (for triggering CI / notifying other listeners).

The-Compiler commented 2 years ago

FWIW this seems like a good overview of possibilities (some of which @webknjaz has already mentioned): https://github.com/peter-evans/create-pull-request/blob/main/docs/concepts-guidelines.md#workarounds-to-trigger-further-workflow-runs

webknjaz commented 2 years ago

Hey @The-Compiler, have I offered you to use my Patchback GitHub App? I don't remember if I did, but it so happened that a number of projects are using it successfully (some of which I didn't even know existed). So if you're up to trying it out, it's here https://github.com/apps/patchback. Here's an example config https://github.com/ansible-collections/community.general/blob/main/.github/patchback.yml but it'll work just fine even without one. Example PR: https://github.com/aio-libs/aiohttp/pull/6749#issuecomment-1126271590.

bluetech commented 1 year ago

Another hack I've been using is adding a deployment key to the repo + adding its private key as a secret. Then, in the workflows, add ssh-key to actions/checkout@v2 with that. Then, any subsequent Git interactions in the job will be configured to use that SSH key, enabling the push event propagation (for triggering CI / notifying other listeners).

I can easily do this one -- I will generate the key pair, add the private key as a secret and throw it away. Any other core dev wants to ack this (or add a key directly given my ack)?

nicoddemus commented 1 year ago

@bluetech please go ahead! Thanks!

bluetech commented 1 year ago

I realized after the fact what @webknjaz and the peter-evans/create-pr docs say, that a deploy key will only trigger push event but not pull-request event which is what we need. So I created a PR to use @pytestbot key instead (secret already configured).

webknjaz commented 1 year ago

I realized after the fact what @webknjaz and the peter-evans/create-pr docs say, that a deploy key will only trigger push event but not pull-request event which is what we need.

That's not really accurate. If there is a PR for the given branch, the pull_request event will happen too (and will be processed unless GHA workflow is set up to ignore the branch name pattern, for example). This has nothing to do with the deployment key. The problems with non-propagating events are only there if you use ${{ secrets.GITHUB_TOKEN }}. Any other tokens will cause normal events to happen.

webknjaz commented 1 year ago

@bluetech I looked at your PR #10346, and now I see why you've drawn this connection. This is because both PR creation and pushing to Git used the same token. I've done one clever thing in one of my projects — the workflow first pushes an empty commit (push to a new branch happens), then a PR is created using a normal ${{ secrets.GITHUB_TOKEN }} (because there's a branch that exists, it's possible — but this doesn't cause any PR-related events); then, the proper commits are force-pushed to that branch using a deployment key. And this time, both push and pull_request events happen because ${{ secrets.GITHUB_TOKEN }} is not in use. And so this allows the CI to be triggered.

bluetech commented 1 year ago

Reopening, see #10354...

bluetech commented 1 year ago

@webknjaz Heh that's indeed clever. We can try this if nothing else works. Slight downside is that it will create extra notifications for the last push, but that's not too bad.

webknjaz commented 1 year ago

@bluetech have you considered just giving my bot a try instead? You can install Patchback on any test repo under your user account and see if it works for you, no need to experiment on this upstream repo. I have already put a lot of thought into it so you don't have to reinvent the wheel if there's no need.

But if you want to stick with GHA, I'd recommend creating a GitHub App entity under this org and provisioning it's secrets to GHA, scoped to an environment. That would provide you with the most pleasing experience while still allowing you to use GHA is the main runtime (you'd get an API token to use via something like https://github.com/marketplace/actions/app-token).

nicoddemus commented 1 year ago

@bluetech have you considered just giving my bot a try instead?

Out of curiosity I did take a look at the bot. Seems interesting, is there any documentation on how to use it?

I dug around aio-libs (because it is advertised in the bot's page as a project which uses it) and found https://github.com/aio-libs/aiohttp/pull/6993, which has a backport-3.9 label, and indeed the bot posted a comment and created https://github.com/aio-libs/aiohttp/pull/6994.

Is it a matter of just installing the bot and creating labels in the format backport-<BRANCH>?

webknjaz commented 1 year ago

@nicoddemus sorry, I missed your comment.

Out of curiosity I did take a look at the bot. Seems interesting, is there any documentation on how to use it?

Oh, my... Sorry about that! The project kinda grew naturally and took weird turns. First, I had an idea of doing something like this + had some experiments with writing GitHub Apps. I thought I'd use it for aiohttp. Then, I didn't actually start the project. And, at some point, folks maintaining the community Ansible Collections were complaining about the cherry-picking process being annoying. So I remembered my idea and sketched the bot later that evening. I was testing it on those collection repositories, which is why I've just added the config there as it evolved. And later people were just copying it around so I completely forgot about the documentation. Projects I never knew existed somehow learned about the bot and started copying the config or just using it with defaults. Nobody ever asked me to document stuff! But yeah, it's a valid point. I have some issues filed for myself but not about the initial install/setup docs... I guess I didn't foresee it going viral :man_shrugging:

Is it a matter of just installing the bot and creating labels in the format backport-<BRANCH>?

And yes. You just install it (maybe in your fork or a test repo for testing) and create labels (I'd probably prefer to just auto-create them but never got time to work on such a feature). Also, you could copy-paste + edit https://github.com/ansible-collections/community.general/blob/main/.github/patchback.yml#L6-L8 if you want custom names for the labels, target branches or the branches that Patchback creates for PRs. I did mention the configuration once at https://github.com/pytest-dev/pytest/issues/9555#issuecomment-1030709853. That comment also has a link to a failed attempt of an automatic cherry-pick with instructions for the contributors on how to do manual backporting.

P.S. You might want also want to drop in a config for https://github.com/python/cherry-picker — it's originally written for CPython, but then it got integrated into aiohttp and Ansible. I don't use it anymore personally (although, I've contributed a lot at some point) but I know that many people do, and having a config facilitates this. This is an assistive tool specifically for creating backports from the dev machine.

webknjaz commented 1 year ago

@nicoddemus hey, do you want to revisit this?