Uploaded image for project: 'Bitbucket Data Center'
  1. Bitbucket Data Center
  2. BSERV-7475

Allow only certain users to make changes without a pull request

    • Icon: Suggestion Suggestion
    • Resolution: Done
    • 4.5.1
    • Enterprise
    • We collect Bitbucket feedback from various sources, and we evaluate what we've collected when planning our product roadmap. To understand how this piece of feedback will be reviewed, see our Implementation of New Features Policy.

      STASH-2910 added the option for an additional (per-branch) restriction to block "Changes without a pull request"

      However, this is an option that applies for all users, rather than "allowing only a restricted set of users to push but allowing all to merge a pull request" (which was the original summary to STASH-2910)

      It would be very useful to have these additional options be able to be bypassed by certain users/groups. Use case:

      • Commits to the release branches have to be done through pull requests, but the ci server (which isn't an access key user, so this isn't the same as STASH-5009) can do release builds and update versions in pom.xml files.

      Note that the users with this permission must be managed separately to the list of users with write access to the branch, otherwise the use case of 'developers do their own merges to the branch after an approved pull request' won't work.

      It may be useful to also apply this to the other two options added in stash 3.10 ("rewriting history" and "branch deletion"), but the pull request restriction is more useful, at least to me.

          Form Name

            [BSERV-7475] Allow only certain users to make changes without a pull request

            With the release of Bitbucket Server 4.5, there have been some improvements to branch permissions.
            It is now possible to add exemptions for any type of branch permission, including "Prevent changes without a pull request".

            For more information see the branch permissions documentation.

            Felix (Inactive) added a comment - With the release of Bitbucket Server 4.5 , there have been some improvements to branch permissions. It is now possible to add exemptions for any type of branch permission, including "Prevent changes without a pull request". For more information see the branch permissions documentation .

            wisen.tanasa, when I know for sure I will update. There's some UI tweaks in progress that could affect when it will ship.

            Roger Barnes (Inactive) added a comment - wisen.tanasa , when I know for sure I will update. There's some UI tweaks in progress that could affect when it will ship.

            @rbarnes Can you advise what's the fixVersion going to be for this particular issue?

            Wisen Tanasa added a comment - @rbarnes Can you advise what's the fixVersion going to be for this particular issue?

            Hi all, thanks for your feedback, and patience, on this. We appreciate that it's a hot topic for effective developer workflows.

            We are working on making it possible to specify user/group exceptions in for pull requests in branch permissions (via API and UI) and hope to share some news on that soon. We've not forgotten about those that want access keys to join the party too (per BSERV-5009), but to set expectations that's not in the current round of changes. We'll keep iterating on this over time, so keep the feedback coming!

            Roger Barnes (Inactive) added a comment - Hi all, thanks for your feedback, and patience, on this. We appreciate that it's a hot topic for effective developer workflows. We are working on making it possible to specify user/group exceptions in for pull requests in branch permissions (via API and UI) and hope to share some news on that soon. We've not forgotten about those that want access keys to join the party too (per BSERV-5009 ), but to set expectations that's not in the current round of changes. We'll keep iterating on this over time, so keep the feedback coming!

            We used to use the REST API to exclude a user as well in Stash 3.x. This hidden functionality now is removed in Stash 4. So I'm assuming that Bradley Baetz was using Stash 3.x when he did the POST.

            We are trialing this plugin now and it has the functionality that we need e.g. to ignore a user from git push: Pull Request Please for Bitbucket Server

            Wisen Tanasa added a comment - We used to use the REST API to exclude a user as well in Stash 3.x. This hidden functionality now is removed in Stash 4. So I'm assuming that Bradley Baetz was using Stash 3.x when he did the POST. We are trialing this plugin now and it has the functionality that we need e.g. to ignore a user from git push: Pull Request Please for Bitbucket Server

            I added the exclusion using REST API, as sugested by Bradley Baetz. The username now appears on the Branch Permissions screen, but the user still get an error when trying to push. It is not clear for me whether the REST call would be enough or a plugin change is also necessary. I am using version 4.1.3. Thank you!

            Cristiano Mariano added a comment - I added the exclusion using REST API, as sugested by Bradley Baetz. The username now appears on the Branch Permissions screen, but the user still get an error when trying to push. It is not clear for me whether the REST call would be enough or a plugin change is also necessary. I am using version 4.1.3. Thank you!

            I certainly hope this will be included in Bitbucket Server as well.

            Andrew Pitt added a comment - I certainly hope this will be included in Bitbucket Server as well.

            BobS added a comment - - edited

            We recently got around this by writing a Pre-Receive Hook. We have two branch patterns for which pull requests should always be required - 'master' and 'patch/'. For other branches, people can commit directly. We have a Jenkins user set up in Bitbucket Server called, originally enough, 'jenkins'. The hook disallows direct pushes to the two branch patterns unless the user is 'jenkins'. Here's the code - someone may find it useful as a pattern:

            package com.sirsidynix.bitbucket.plugin.hook;
            
            import com.atlassian.bitbucket.auth.AuthenticationContext;
            import com.atlassian.bitbucket.hook.HookResponse;
            import com.atlassian.bitbucket.hook.repository.PreReceiveRepositoryHook;
            import com.atlassian.bitbucket.hook.repository.RepositoryHookContext;
            import com.atlassian.bitbucket.repository.RefChange;
            import com.atlassian.bitbucket.user.ApplicationUser;
            import com.atlassian.sal.api.component.ComponentLocator;
            
            import javax.annotation.Nonnull;
            import java.util.Collection;
            
            /**
             * SirsiDynix Pre-Receive Repository Hook
             * <br>
             * Ensures that only the Jenkins Build User can push direct to the master branch
             * or to a patch/XXX branch.  All other branches are unchecked here (i.e. subject
             * only to Bitbucket Server setup as to who can push).
             * <br>
             * NOTE: this affects ONLY the push - not the merge process.  So, again,
             * who can merge is controlled only by the Bitbucket Server setup.
             */
            public class SirsiDynixPreReceiveHook implements PreReceiveRepositoryHook {
            
                private static final String JENKINS_USER = "jenkins";
            
                /**
                 * Disables push to master or patch/XXX branch except for the "jenkins" user.
                 */
                @Override
                public boolean onReceive(@Nonnull RepositoryHookContext context, @Nonnull Collection<RefChange> refChanges, @Nonnull HookResponse hookResponse) {
            
                    boolean isMasterOrPatch = false;
            
                    for (RefChange refChange : refChanges) {
                        String branch = refChange.getRef().getDisplayId();
                        if ("master".equals(branch) || branch.startsWith("patch/")) {
                            isMasterOrPatch = true;
                            break;
                        }
                    }
            
                    if (isMasterOrPatch) {
                        AuthenticationContext authContext = ComponentLocator.getComponent(AuthenticationContext.class);
                        ApplicationUser user = authContext.getCurrentUser();
                        if (user == null || !JENKINS_USER.equals(user.getName())) {
                            hookResponse.err().println("*** You may not push directly to master or patch/xxx branches! Work through a Feature or Bugfix branch. ****");
                            return false;
                        }
                    }
            
                    return true;
                }
            }
            

            And then the atlassian-plugin.xml that goes with it:

            <?xml version="1.0" encoding="UTF-8"?>
            
            <atlassian-plugin key="${atlassian.plugin.key}" name="${project.name}" plugins-version="2">
              <plugin-info>
                <description>${project.description}</description>
                <version>${project.version}</version>
                <vendor name="${project.organization.name}" url="${project.organization.url}"/>
                <param name="plugin-icon">images/pluginIcon.png</param>
                <param name="plugin-logo">images/pluginLogo.png</param>
              </plugin-info>
              <repository-hook key="sirsi-dynix-pre-receive-hook" name="SirsiDynix Pre Receive Hook" i18n-name-key="sirsi-dynix-pre-receive-hook.name" class="com.sirsidynix.bitbucket.plugin.hook.SirsiDynixPreReceiveHook">
                <description key="sirsi-dynix-pre-receive-hook.description">The SirsiDynix Pre Receive Hook Plugin</description>
              </repository-hook>
            </atlassian-plugin>
            

            Note that some contexts (e.g. IntelliJ IDEA) will not echo the err message - they assume that a failure on the push means that your branch is out of synch and needs updating before the merge can be done. i.e. the push fails, which is what you want, but the IDE doesn't give the right reason. You just have to know that's what it means

            Works fine, though, from the git command line...

            BobS added a comment - - edited We recently got around this by writing a Pre-Receive Hook. We have two branch patterns for which pull requests should always be required - 'master' and 'patch/'. For other branches, people can commit directly. We have a Jenkins user set up in Bitbucket Server called, originally enough, 'jenkins'. The hook disallows direct pushes to the two branch patterns unless the user is 'jenkins'. Here's the code - someone may find it useful as a pattern: package com.sirsidynix.bitbucket.plugin.hook; import com.atlassian.bitbucket.auth.AuthenticationContext; import com.atlassian.bitbucket.hook.HookResponse; import com.atlassian.bitbucket.hook.repository.PreReceiveRepositoryHook; import com.atlassian.bitbucket.hook.repository.RepositoryHookContext; import com.atlassian.bitbucket.repository.RefChange; import com.atlassian.bitbucket.user.ApplicationUser; import com.atlassian.sal.api.component.ComponentLocator; import javax.annotation.Nonnull; import java.util.Collection; /**  * SirsiDynix Pre-Receive Repository Hook  * <br>  * Ensures that only the Jenkins Build User can push direct to the master branch  * or to a patch/XXX branch.  All other branches are unchecked here (i.e. subject  * only to Bitbucket Server setup as to who can push).  * <br>  * NOTE: this affects ONLY the push - not the merge process.  So, again,  * who can merge is controlled only by the Bitbucket Server setup.  */ public class SirsiDynixPreReceiveHook implements PreReceiveRepositoryHook {     private static final String JENKINS_USER = "jenkins" ;     /**      * Disables push to master or patch/XXX branch except for the "jenkins" user.      */     @Override     public boolean onReceive(@Nonnull RepositoryHookContext context, @Nonnull Collection<RefChange> refChanges, @Nonnull HookResponse hookResponse) {         boolean isMasterOrPatch = false ;         for (RefChange refChange : refChanges) {             String branch = refChange.getRef().getDisplayId();             if ( "master" .equals(branch) || branch.startsWith( "patch/" )) {                 isMasterOrPatch = true ;                 break ;             }         }         if (isMasterOrPatch) {             AuthenticationContext authContext = ComponentLocator.getComponent(AuthenticationContext.class);             ApplicationUser user = authContext.getCurrentUser();             if (user == null || !JENKINS_USER.equals(user.getName())) {                 hookResponse.err().println( "*** You may not push directly to master or patch/xxx branches! Work through a Feature or Bugfix branch. ****" );                 return false ;             }         }         return true ;     } } And then the atlassian-plugin.xml that goes with it: <?xml version= "1.0" encoding= "UTF-8" ?> <atlassian-plugin key= "${atlassian.plugin.key}" name= "${project.name}" plugins-version= "2" > <plugin-info> <description>${project.description}</description> <version>${project.version}</version> <vendor name= "${project.organization.name}" url= "${project.organization.url}" /> <param name= "plugin-icon" >images/pluginIcon.png</param> <param name= "plugin-logo" >images/pluginLogo.png</param> </plugin-info> <repository-hook key= "sirsi-dynix-pre-receive-hook" name= "SirsiDynix Pre Receive Hook" i18n-name-key= "sirsi-dynix-pre-receive-hook.name" class= "com.sirsidynix.bitbucket.plugin.hook.SirsiDynixPreReceiveHook" > <description key= "sirsi-dynix-pre-receive-hook.description" >The SirsiDynix Pre Receive Hook Plugin</description> </repository-hook> </atlassian-plugin> Note that some contexts (e.g. IntelliJ IDEA) will not echo the err message - they assume that a failure on the push means that your branch is out of synch and needs updating before the merge can be done. i.e. the push fails, which is what you want, but the IDE doesn't give the right reason. You just have to know that's what it means Works fine, though, from the git command line...

            ahhhh man, I just hit this myself.
            The way the screens/documentation read suggested to me that you could enforce pull requests but still grant write access to those users in the limit field (i.e. they were exempt)

            in fact, the way it works is that everyone must use pull requests, but only those users in the limit field can merge those pull requests. It might be an idea to to and capture this more clearly in the docs.

            Deleted Account (Inactive) added a comment - ahhhh man, I just hit this myself. The way the screens/documentation read suggested to me that you could enforce pull requests but still grant write access to those users in the limit field (i.e. they were exempt) in fact, the way it works is that everyone must use pull requests, but only those users in the limit field can merge those pull requests. It might be an idea to to and capture this more clearly in the docs.

            We are having the same issue as Bradley. We want all developers to use pull requests (even if they have the ability to merge them themselves), but our Release plans in Bamboo (that use the Maven Release plug-in) now fail, since it assumes Bamboo can push POM version updates directly to master.

            I've had to turn off this branch permission for new (which is unfortunate), but I'd love to be able to turn it back on once there is a mechanism to add exceptional users (e.g. CI user).

            Andrew Pitt added a comment - We are having the same issue as Bradley. We want all developers to use pull requests (even if they have the ability to merge them themselves), but our Release plans in Bamboo (that use the Maven Release plug-in) now fail, since it assumes Bamboo can push POM version updates directly to master. I've had to turn off this branch permission for new (which is unfortunate), but I'd love to be able to turn it back on once there is a mechanism to add exceptional users (e.g. CI user).

              fhaehnel Felix (Inactive)
              06fbb7509c24 Bradley Baetz
              Votes:
              47 Vote for this issue
              Watchers:
              50 Start watching this issue

                Created:
                Updated:
                Resolved: