It's not the same without you

Join the community to find out what other Atlassian users are discussing, debating and creating.

Atlassian Community Hero Image Collage

StreamFile not recognized as method in custom script hook?

Andy Miller Sep 01, 2016

I'm trying to implement a pre-receive hook in Bitbucket Server using the Custom Script Hook feature. I'm not the most savvy with Groovy, but I was fairly sure I'd got the syntax right. However, on trying to add the hook it gives the error:

 

[Static type checking] - Cannot find matching method com.atlassian.bitbucket.content.ContentServce#streamFile

 

import com.atlassian.sal.api.component.ComponentLocator
import com.atlassian.bitbucket.hook.HookResponse
import com.atlassian.bitbucket.repository.RefChange
import com.atlassian.bitbucket.repository.Repository
import com.atlassian.bitbucket.content.ContentService
import com.atlassian.bitbucket.content.FileContentCallback

if(repository.getProject().getName() == "Constellation" && repository.getName() == "apollo" && refChanges.pathsMatch('glob:apollo/ui/**')) {
    def contentService = ComponentLocator.getComponent(ContentService)
    def filePath = "apollo/ui/dist/js/app.js"
    def searchFragment = "WSURL=window.location.hostname"
    def fragmentFound = false
    contentService.streamFile(repository, refChanges.first().getToHash(), filePath, new FileContentCallback() {
        @Override
        boolean onLine(int lineNumber, String line, boolean truncated) throws IOException {
            if(line.toLowerCase().contains(searchFragment.toLowerCase()))
                fragmentFound = true
            return true;
        }
    });
    if(!fragmentFound) {
        //reject push with note
        hookResponse.out().print("Push rejected!\nAre you sure you ran `npm run build`?\n\n")
        return true
    } else {
        //allow push
        return false
    }
}

 

I've imported ContentService and it does seem to recognize ContentService when obtained with ComponentLocator. So why doesn't it recognize the streamFile method?

 

Any other comments on my code are welcome as well. The purpose of the pre-receive hook is to only accept pushes that have edits to files in a certain folder if a specific file has a certain substring. The API seems to say that ContentService.streamFile is the correct method to read a whole source file, as opposed to just reading changes from a given commit.

 

Thanks in advance!

2 answers

1 accepted

2 votes
Answer accepted
Adam Markham [Adaptavist] Community Leader Sep 01, 2016

Theres a siimilar question here regarding reading files in a repository using ScriptRunner: https://answers.atlassian.com/questions/39450211

Your code should look like this:

import com.atlassian.bitbucket.content.ContentService
import com.atlassian.bitbucket.io.TypeAwareOutputSupplier
import com.atlassian.sal.api.component.ComponentLocator

import javax.annotation.Nonnull
import java.nio.charset.StandardCharsets

if(repository.getProject().getName() == "Constellation" && repository.getName() == "apollo" && refChanges.pathsMatch('glob:apollo/ui/**')) {
    def contentService = ComponentLocator.getComponent(ContentService)
    def filePath = "apollo/ui/dist/js/app.js"
    def searchFragment = "WSURL=window.location.hostname"

    def supplier = new ByteArrayStreamOutputSupplier()

    contentService.streamFile(repository, refChanges.first().getToHash(), filePath, supplier)

    supplier.stream.close()

    // convert byte array to UTF-8 encoded string which has the file contents
    def content = new String(supplier.baos.toByteArray(), StandardCharsets.UTF_8)

    // process each line in the content
    def fragmentFound = content.readLines().any { line ->
        line.toLowerCase().contains(searchFragment.toLowerCase())
    }

    if(!fragmentFound) {
        //reject push with note
        hookResponse.out().print("Push rejected!\nAre you sure you ran `npm run build`?\n\n")
        return false
    }
}

return true

class ByteArrayStreamOutputSupplier implements TypeAwareOutputSupplier {

    ByteArrayOutputStream baos
    BufferedOutputStream stream

    ByteArrayStreamOutputSupplier() {
        this.baos = new ByteArrayOutputStream()
        this.stream = new BufferedOutputStream(baos)
    }

    @Override
    OutputStream getStream(@Nonnull String contentType) throws IOException {
        stream
    }
}

Issues I can see are:

  • You need to return false if you want to block the push and true if you want to allow the push.
  • ContentService looks like its spelt wrong in that error message, could that be the issue?
  • Your best off using the TypeAwareOutputSupplier version of stream file, its just easier to use in my view.
  • May be best off using repository.getSlug() and project.getKey() rather than the names.

You'll see a static type checking error in the inline code editor but its safe to ignore, it just can't work out where the pathsMatch method comes from, which is one ScriptRunner provides.

For future reference if you tag your question with: com.onresolve.jira.stash.groovyrunner its easier for us to respond and means your question will be found by the right person.

0 votes
Andy Miller Sep 02, 2016

Thanks for the response! I'll try out your changes and see if they work. The misspelled error message was my bad, not related to the code.

Suggest an answer

Log in or Sign up to answer
This widget could not be displayed.
This widget could not be displayed.
Community showcase
Posted in Off-topic

Disney Live Action Reboots: Are you for or against?

Happy Friday Everyone! Today marks the international release of Disney's live action version of the animated classic Aladdin. I know that this movie was met with some controversy of over cast...

192 views 21 10
Join discussion

Community Events

Connect with like-minded Atlassian users at free events near you!

Find an event

Connect with like-minded Atlassian users at free events near you!

Unfortunately there are no Community Events near you at the moment.

Host an event

You're one step closer to meeting fellow Atlassian users at your local event. Learn more about Community Events

Events near you