BitBucket ContentService is unable to stream file content or directory info

bitbucket-server

#1

I have a plugin which implements a pre-receive hook by reading a file in a separate repository. This is configured in the plugin settings.
This works in BitBucket Server 4.9.1
As a part of testing an upgrade to BB Server 5.1.0, the plugin is unable to read the same file with an exception:

com.atlassian.bitbucket.content.NoSuchPathException: The path “settings.conf” does not exist at revision “master”

I have also tried to use contentService.streamDirectory to see what files are available, but that also fails.
It might be worth noting that the file exists in the root of the separate repository.
Here is the code that I am using:

String project = settings.getString("permsProject");
String repo = settings.getString("permsRepo");
String branch = settings.getString("permsBranch");
String file = settings.getString("permsFile");

Repository permissionsRepo = repositories.getBySlug(project, repo);

ByteArrayOutputStream out = new ByteArrayOutputStream();
contentService.streamFile(permissionsRepo, branch, file, (s) -> out);

How to read file contents in a global prereceive hook?
#2

Hi @michael.rappazzo,
Thanks for reaching out.
In the example you are passing repo into the streamFile call. Since repo is a String that should not be compiling, I’m guessing this is not the actual code in your plugin?. Do you think you could share the actual code you are running? Or maybe a link to a public repository where we can take a look at it?

Also, do you think you can share a stacktrace so that we can get a better idea of where it’s failing?

Thank you
Juan Palacios
Atlassian - Bitbucket Server


#3

I have edited the original snippet. It was merely an omission from when I scrubbed the code. I thought that it was plain anyway, since right above the call to streamFile, it fetches the repo by slug.

Perhaps it is also worth mentioning that the repo fetched by slug is not the same as the repo which is triggering the pre-receive hook (which is what this plugin is for).

Here is a stack trace:

com.atlassian.bitbucket.content.NoSuchPathException: The path "policy.conf" does not exist at revision "master"
        at com.atlassian.bitbucket.scm.git.command.GitCommandExitHandler.newNoSuchPathException(GitCommandExitHandler.java:190)
        at com.atlassian.bitbucket.scm.git.command.GitCommandExitHandler.evaluateStdErr(GitCommandExitHandler.java:91)
        at com.atlassian.bitbucket.scm.git.command.GitCommandExitHandler.onError(GitCommandExitHandler.java:197)
        at com.atlassian.bitbucket.scm.DefaultCommandExitHandler.onExit(DefaultCommandExitHandler.java:31)
        at com.atlassian.bitbucket.scm.BaseCommand.callExitHandler(BaseCommand.java:146)
        at com.atlassian.bitbucket.scm.BaseCommand$CommandFuture.internalGet(BaseCommand.java:280)
        at com.atlassian.bitbucket.scm.BaseCommand$CommandFuture.get(BaseCommand.java:244)
        at com.atlassian.bitbucket.scm.BaseCommand.call(BaseCommand.java:83)
        at com.atlassian.stash.internal.content.DefaultContentService.streamFile(DefaultContentService.java:201)
        at com.atlassian.plugin.util.ContextClassLoaderSettingInvocationHandler.invoke(ContextClassLoaderSettingInvocationHandler.java:26)
        at org.eclipse.gemini.blueprint.service.importer.support.internal.aop.ServiceInvoker.doInvoke(ServiceInvoker.java:56)
        at org.eclipse.gemini.blueprint.service.importer.support.internal.aop.ServiceInvoker.invoke(ServiceInvoker.java:60)
        at org.eclipse.gemini.blueprint.service.util.internal.aop.ServiceTCCLInterceptor.invokeUnprivileged(ServiceTCCLInterceptor.java:70)
        at org.eclipse.gemini.blueprint.service.util.internal.aop.ServiceTCCLInterceptor.invoke(ServiceTCCLInterceptor.java:53)
        at org.eclipse.gemini.blueprint.service.importer.support.LocalBundleContextAdvice.invoke(LocalBundleContextAdvice.java:57)
        at com.mycompany.git.Policy.load(Policy.java:103)
        at com.mycompany.git.PolicyHooks$1.perform(PolicyHooks.java:119)
        at com.mycompany.git.PolicyHooks$1.perform(PolicyHooks.java:1)
        at com.atlassian.stash.internal.user.DefaultEscalatedSecurityContext.call(DefaultEscalatedSecurityContext.java:54)
        at com.mycompany.git.PolicyHooks.preUpdateGeneral(PolicyHooks.java:116)
        at com.mycompany.git.PolicyHooks.preUpdate(PolicyHooks.java:92)
        at com.atlassian.stash.internal.hook.repository.DefaultRepositoryHookService.preUpdate(DefaultRepositoryHookService.java:583)
        at com.atlassian.stash.internal.hook.repository.DefaultRepositoryHookService.preUpdate(DefaultRepositoryHookService.java:284)
        at com.atlassian.stash.internal.hook.DefaultBuiltInHookHandlerFactory.lambda$preReceive$0(DefaultBuiltInHookHandlerFactory.java:33)
        at com.atlassian.stash.internal.scm.git.GitQuarantineHelper.lambda$null$0(GitQuarantineHelper.java:87)
        at com.atlassian.stash.internal.hook.DefaultHookService.doHandleRequest(DefaultHookService.java:303)
        at com.atlassian.stash.internal.hook.DefaultHookService.handleRequest(DefaultHookService.java:289)
        at com.atlassian.stash.internal.hook.DefaultHookService.handleRawRequest(DefaultHookService.java:230)
        at com.atlassian.stash.internal.hook.DefaultHookService$1.lambda$run$0(DefaultHookService.java:197)
        at com.atlassian.stash.internal.concurrent.DefaultTransferableStateManager$StateTransferringRunnable.run(DefaultTransferableStateManager.java:166)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.lang.Thread.run(Thread.java:745)
        ... 85 frames trimmed

I also made an attempt to invoke the command directly with a similar result:

com.atlassian.bitbucket.scm.CommandFailedException: '/usr/local/bin/git show master:policy.conf' exited with code 128 saying: fatal: Path 'policy.conf' does not exist in 'master'

#4

This problem is caused by our handling of quarantine pushes introduced by Git 2.11.0.

I’ve created this ticket with a description of the issue and so that everyone can track it’s progress: https://jira.atlassian.com/browse/BSERV-10437


#5

I’m experiencing a very similar issue, if not the same when trying to develop a simple preReceiveHook plugin.

The bug should be fixed in 5.6.2 & 5.7, the SDK boots a bitbucket that is marked as 5.8…

So I want to veryfy certain “contracts” that developers have agreed on that apply to our git repositories. One thing that I want to check requeires me to read a file and check its content.

So I need to verify that the commit beeing pushed has a certain file with certain content or that the file already exists in the repository.

So basicly I got:

    public RepositoryHookResult preUpdate(@Nonnull PreRepositoryHookContext preRepositoryHookContext, @Nonnull RepositoryPushHookRequest request) {
request.getRefChanges().stream().forEach(refChange -> contentService.streamDirectory(request.getRepository(), refChange.getToHash(), false , new myContentTreeCallback(refChange.getToHash()), PageRequestImpl(0, 1000));
}

// And My ContentTreeCallback that takes the hashString in constructor (refChange.getToHash())

        public boolean onTreeNode(@Nonnull ContentTreeNode node) throws IOException {
                boolean readme = node.getPath().getName().equalsIgnoreCase("readme.md");
                if(readme){
                     try (ByteArrayOutputStream array = new ByteArrayOutputStream()) {
                    contentService.streamFile(repository,hashString, node.getPath().getName(), s -> array);
}

I am getting a:

[WARNING] com.atlassian.bitbucket.content.NoSuchPathException: The path "readme.md" does not exist at revision "f8a198dc6157077d27cbac91b704b6fd6d404d79"
[WARNING]       at com.atlassian.bitbucket.scm.git.command.GitCommandExitHandler.newNoSuchPathException(GitCommandExitHandler.java:190)
[WARNING]       at com.atlassian.bitbucket.scm.git.command.GitCommandExitHandler.evaluateStdErr(GitCommandExitHandler.java:91)
[WARNING]       at com.atlassian.bitbucket.scm.git.command.GitCommandExitHandler.onError(GitCommandExitHandler.java:197)
[WARNING]       at com.atlassian.bitbucket.scm.DefaultCommandExitHandler.onExit(DefaultCommandExitHandler.java:31)
[WARNING]       at com.atlassian.bitbucket.scm.BaseCommand.callExitHandler(BaseCommand.java:146)
[WARNING]       at com.atlassian.bitbucket.scm.BaseCommand$CommandFuture.internalGet(BaseCommand.java:280)