Closed cclauss closed 3 years ago
I would really like to have this feature, unfortunately I don't really have time to implement this any time soon. PRs would be very welcome. I'd be happy to help, if you have any questions.
I will try to get to it. In general, I do this with a pre-commit hook but encapsulating all that complexity into a GitHub Action would be a superpower.
@cclauss Thanks for taking a look. An other workflow would be to listen to /black format
comments in the PR and push a fix directly to the branch. That way the action doesn't introduce merge conflicts by accident.
I'm also looking into this, see this fork. It's currently broken, but should hopefully be finished soon. I can't give a timeline though, so feel free to take any code from there and use it in a PR here.
@lgeiger @cclauss I have finished a minimal working product and submitted a pull request. Please let me know what you think!
I have written an action that will raise a pull request for local changes to the Actions workspace. You can check it out here. https://github.com/peter-evans/create-pull-request
There is also an example here where I'm formatting code with autopep8 and using create-pull-request
action to raise a PR.
https://github.com/peter-evans/autopep8
@cclauss Just to clarify further for your use-case. The create-pull-request
action will raise a PR to merge into the branch that triggered the workflow. So if you were to push code with bad formatting to a feature branch, Black-action could run to make fixes locally and then a PR would be created to merge back to that same branch. It's maybe not quite as automatic as you wanted because you need to click "Merge" on the PR that create-pull-request
action creates for the changes to be committed to your feature branch.
I now have an on: pull_request
workflow example for direct push to the pull request branch working. If black-action could expose an exit-code to know whether or not changes were made, a similar workflow could probably be used.
https://github.com/peter-evans/autopep8#direct-push-with-on-pull_request-workflows
Could you get a status code from black —check . and then run black . if that status code is nonzero?
@cclauss I think that could work, yes. However, I figured out a generic solution that should work for any git-tracked modified files during an on: pull_request
workflow. Use a repo
scoped token instead of GITHUB_TOKEN
if you have other pull request checks.
This is the example for Black-action.
name: auto-format
on: pull_request
jobs:
format:
# Check if the PR is not from a fork
if: github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: black
uses: lgeiger/black-action@v1.0.1
with:
args: .
- name: Check for modified files
id: git-check
run: echo ::set-output name=modified::$(if git diff-index --quiet HEAD --; then echo "false"; else echo "true"; fi)
- name: Push changes
if: steps.git-check.outputs.modified == 'true'
run: |
git config --global user.name 'Peter Evans'
git config --global user.email 'peter-evans@users.noreply.github.com'
git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/$GITHUB_REPOSITORY
git checkout $GITHUB_HEAD_REF
git commit -am "Automated changes"
git push
Also wrote a blog post about this solution with a bunch of other examples. https://peterevans.dev/posts/github-actions-how-to-automate-code-formatting-in-pull-requests/
@peter-evans, as a personal anecdote, I had to modify your code slightly to get it to work with an on: push
hook. Not sure if it directly related to the change in hook, but the as-is example you provided complained about not being on a branch during the final push. Here's the modified version that works for my repository:
name: auto-format
on: push
jobs:
format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: black
uses: lgeiger/black-action@master
with:
args: .
- name: Check for modified files
id: git-check
run: echo ::set-output name=modified::$(if git diff-index --quiet HEAD --; then echo "false"; else echo "true"; fi)
- name: Push changes
if: steps.git-check.outputs.modified == 'true'
run: |
git config --global user.name 'NIU Rover'
git config --global user.email 'niurover@gmail.com'
git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/$GITHUB_REPOSITORY
git checkout `basename $GITHUB_REF`
git commit -am "Automated changes"
git push origin HEAD:`basename $GITHUB_REF`
@LuckierDodge it easier on a repo that you own but it is quite difficult on a repo that someone else owns... cclauss/autoblack#8
With the new yml approach, you don’t need to have your own Docker image and you don’t need entrypoint.sh
@LuckierDodge Yes, what I posted only works for on: pull_request
because it's checking out GITHUB_HEAD_REF
which is the merging branch. This variable only makes sense (and is only available) for on: pull_request
workflows. For on: push
workflows you can just checkout GITHUB_REF
as you discovered.
It turns out that the workflow I posted here doesn't work on PRs raised from forks. I've updated it to stop it running on those PRs with the following job condition. It limits the usefulness of this workflow considerably, but it looks unavoidable at the moment due to limitations on forks.
jobs:
format:
# Check if the PR is not from a fork
if: github.event.pull_request.head.repo.full_name == github.repository
Look at the commits in this PR... TheAlgorithms/Python#1779
The change to the first file was made by me in the first commit. The changes to the other three files was made in the second commit by the autoblack GitHub Action.
We use autoblack to add a second, automatic commit to a PR that black formats the code. This only succeeds if the author of the PR has write access to this repo.
I do this by using the git-auto-commit-action of stefanzweifel.
name: auto-format
on: push
jobs:
format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: black
uses: lgeiger/black-action@master
with:
args: .
- name: Apply black formatting if reviewdog found formatting errors
if: "${{ failure() }}"
run: |
black .
- name: Commit black formatting results
if: "${{ failure() }}"
uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: ":art: Format Python code with psf/black push"
Yes. With actions/checkout@v1
it is possible to write back but that is disabled in actions/checkout@v2
.
@cclauss Thanks for pointing that out I was not aware of that!
@cclauss Judging from the fact that you use v1
in your (very helpful) examples, I assume there currently is no (easy) way to autoformat the code using actions/checkout@v2
?
@cclauss I did some testing, and for me, the action appears to be working with checkout@v2 when you make sure you resolve the detached head. Stefanzweifel also states something about this in the repository readme.
A_W_E_S_O_M_E!!! Thanks for the detective work! Closing.
Use case: I make a modification of a repo's (that I do not own) code and send in a PR. Black-action runs on that PR and instead of failing the run, it replaces the code in my PR with Black formatted code. This would make Black formatting automatic instead of forcing committers to do it manually each time that tests fail.
https://developer.github.com/actions/managing-workflows/storing-secrets/#github-token-secret
git diff master -U0 | black --diff # would provide a diff for each file For each Python file that had a diff, we could commit the black changes back into the PR.