Detect direct pushes to master w/GitHub Actions - github

We currently have a GitHub repository where our master branch is protected for everyone except admins, who are able to commit and push directly to the branch without first opening a pull request. We're looking to find a way to send a Slack notification anytime an admin commits directly to master in order to call attention to the fact that there was an override of the branch protections. This may happen intentionally due to extreme circumstances or, worst case, by mistake (which will need to be addressed).
This seems like it'd be possible with a combination of the GitHub Slack action, the if key on the job/step definition, and ideally some piece of information from the push event JSON.
The last part is where I'm stuck: I don't see an obvious way to use the data contained in the push event to differentiate between one-off commits that would violate our branch protection policy and a normal/compliant pull request.
Does anyone have any ideas as to whether or not this is possible? Perhaps there's another event that I should be attaching this workflow to that would give me the information I'd need to tell the difference and launch the Slack notification?

In general, using GitHub Actions to do this kind of notification is problematic because the user can simply remove or neutralize the code that reports this and then push to the main branch. The Actions workflow that's used will be the one pushed into the repo as part of that commit, so this won't be an effective control.
You'd want to probably instead use a webhook to notify a service of this fact and then look at the HEAD commit, parse the commit message to extract the PR number, and verify that the second parent of the commit is the same as the head of the PR. Note that this won't work if you're using squash merges, because there's no easy way to verify that the commit created by a squash merge is the same as the one created by the branch from which it was created.

Related

How to get the merge_method for a merged GitHub pull request

I am trying determine the merge method applied to a GitHub pull request.
There is a merge_method attribute on the API for merging a PR.
https://docs.github.com/en/rest/reference/pulls#merge-a-pull-request
But I do not see this available on the response for the GET
https://docs.github.com/en/rest/reference/pulls#get-a-pull-request
I'm not finding much about this anywhere, has anyone come up with a clever solution to compute this value? Or will it be added the API in the near future?
GitHub doesn't store this information because the pull request can have been merged by means other than the merge button on a pull request.
For example, if I perform a manual merge of a PR and the main branch myself and then push the result to the main branch, that will close the pull request as merged, since the main branch now includes the head of the pull request. This is also true if I do a fast forward merge, which might be the behavior done by a rebase through the web interface.
You can even close a pull request for branch A by merging it into branch B and then merging branch B into the main branch, using the web interface, the API, or otherwise. GitHub uses this technique for its deployment trains, where B is a train and A is a normal feature branch.
Essentially, any time the main branch is updated to include the head of the feature branch in a pull request, that pull request is considered merged. The exception is squash merges, where this doesn't happen, which are treated specially. So there's no guaranteed way to find out this information.
Seems like you can get it like this from their GraphQL API:
{
repository(owner: "TeamCodeStream", name: "codestream") {
viewerDefaultMergeMethod
}
}
Method reposted from this SO answer: https://stackoverflow.com/a/64146400/12206312

Counting commits per developer using webhooks

Using Github webhooks, what is the best way to count the number of commits by a developer for a particular piece of work.
I was thinking that I could do like this:
Listen for webhooks pertaining to merges of any PR into the main branch
discard the webhook event unless it pertains to the main branch
if the PR merge is into the main branch, then find out all the commits (and developer-related to each commit) related to that merge and calculate a count
are all these commits(and developer usernames) even listed in the webhook event?
Will the commits related to the merge definitely only be comprised of commits after the branch was created up until its merge.. or will they actually go all the way back to the beginning of repository creation?
Had also considered listening on webhooks related to "Tag" type pushes, but would a new tag event be able to tell me about all the commits between that tag and a previous tag.. probably not right? I'm guessing that whatever the tag is that it would always represent all commits from the start of repo creation
You can use roughly the approach you've outlined. You can extract the base and head revisions from the desired webhook events and then run git rev-list --no-commit-header --format=%aE $base...$head to find the email address associated with each commit. (You can use git log instead of git rev-list --no-commit-header if you're using an older Git).
That will count only the commits that were created in the branch and are not otherwise merged into main. Note that if you're using squash merges, this doesn't work because the merge base doesn't update; I recommend not using squash merges anyway. In the case of a squash merge, the number of commits created is always 1. You can tell whether a squash merge has taken place because git merge-base --is-ancestor $head main will exit 1; that is, the head of the PR branch is not an ancestor of the most recent main.
While this will work to count the commits per developer, I should point out that counting a developer's commits is not a good measure of productivity and shouldn't be used as a performance metric. A developer may be highly skilled and write only a single commit after investigating a difficult problem, but counting commits would rank that person lower than someone who fixes many easy problems. There are also other skills, like communication and collaboration, which cannot be measured in commits.

Single User GitHub Repository - How to protect master, but allow my own PR's?

Research I've done before raising this question:
[github] single user pr - no relevant results
[github] single user pull request - no relevant results
[github] approve own pull request
github protected branch require pull request (Unanswered)
A potentially relevant question, but around a multiple user environment, so there were workarounds. I don't have a workaround.
'[github] approve own pr` - no relevant results.
Quite a few Google searches
So my problem is simple: I have a personal GitHub repository that I am using to manage my website code. I would like to prevent accidental check-ins to the master branch because I do not want the CI/CD pipeline that I'm building to trigger unless a feature is complete; I'm planning to use issue-linked feature branches to handle updates.
My problem is that I cannot seem to set this up without having someone else to approve the pull requests, which I don't have. So the question is: How, other than creating a secondary git account to handle PR's, can I protect a branch to prevent accidental check-ins from happening, without having someone else on my team to approve those pull requests?
I know that I can do this in Azure Repositories, however, I quite like the GitHub environment so I'd rather do this in GitHub.
I managed to work around this. At the time I made this request, I didn't have automated tests set up (Something I believe all projects should have for completeness). When I set up validation requirements to merge into Master, I could not directly check-in to Master because those checks had not been run.
I could still approve the PR myself, so that was allowable, however, I also had to ensure that all pipeline checks had completed before that PR could complete.
It's not a complete answer because if you are not running a CI/CD pipeline with test running you will not be able to take advantage - but it's easy enough to set something dummy up that will always pass to enable this solution. Until GitHub.com provides a self-approval allowance, it seems to be the best answer.
I'm always happy to hear alternatives though!

can I make a pull request without fork?

On Coursera course Version Control with Git, I encountered a problem below:
Which one of these statements is true?
A pull request must be made from a forked repository.
A pull request can be made only when a branch is being merged.
A pull request can act as a form of review and approval.
From my perspective, both 1 and 3 are correct.
Can someone point out which choice is correct, which are incorrect, and provide reasons?
A pull request can also be made on your own repository by members of that project, so the first choice is not correct.
A pull request can also be made between commits, tags, and earlier points in time, so the second choice is not correct.
The third point is true. So that's the answer.
Your question is technically about Github, not Git. Git doesn't have pull requests.
Third one statement is true. because we can create pull request without being merged and can be created without fork a repository. And we create a pull request for review the changes first then we're going to merge them into repository for which we created pull request.

Mercurial hook to list outdated branches which are behind their parents

We use mercurial workflow with one stable branch (default), one unstable (develop) and feature branches. We want feature branches to always contain all changesets from parent branch(es) to simplify merging them back. Is there any example hooks to prevent adding commits to feature branches which are behind their parent branch? Github has a similar message when your branch is behind master.
Generally there are two scenarios:
Enforce feature-branch owners to sync with upstream branch before pushing new changes (pushed changegroup should be not behind its parent)
Periodically check for list of child branches which became outdated due to recent commits in their parent branches and nudge branch owners to sync or close it
It's basically two separate things you ask:
There is no pre-made hook for denying push when not merged with default which I know of, but maybe some google-foo might reveal some. However it should be quite straight forward to create one:
By my understanding of your requirements: you want to check an incoming transaction to contain only commits to the non-default branch, if their latest commit is a merge of default into it. This is a task for a server-side hook of the pretxnchangegroup kind; there you can analyse the incoming transaction and the changesets it contains and reject the transaction if it does not meet your requirements. Therein check the latest commit to a feature branch (or better non-default and non-develop(?)) to be a merge commit with default or develop.
As to periodic checking with the central repository:
The periodic checking for outdated child branches is a client-side action. You could for instance create here a commit hook. Thus querying hg incoming each time a commit is made. Or simply make a crontab entry client-side and trim the output to your desire.