What should be used to write BitBucket plugin to fill newly created repositories with a content?

I need to write BitBucket plugin, which will create default branch and will place .gitignore and adjusted (specifically for the new repository) README.md.

Following the tutorials it was easy to start and the to add Event Listener component by creating class below. The @EventListener method fires as soon as new repository is created.

    @Named("repositoryCreatedListener")
    public class RepositoryCreatedListener {
    
    
    @EventListener
    public void repositoryCreated(RepositoryCreatedEvent evt) {

        Repository repository = evt.getRepository();
        String projectKey = repository.getProject().getKey();
        String repoSlug = repository.getSlug();

        System.out.println(String.format("REPOSITORY IS BEING CREATED!!!! ACT !!!!!  %s/%s", projectKey, repoSlug));
    }
    }

However, how can I

  • create a branch in the brand new repository and
  • add a couple of files to it?

Seems RefService can help with creation of the branch, but Spring fails to autowire RefService as it does not find any implementations of this interface.

  • How can I get a reference to RefService implementation or
  • should I use something else to initialize the content of new repository?
    @Named("repositoryCreatedListener")
    public class RepositoryCreatedListener {
    
    private static final String DEFAULT_BRANCH_NAME = "master";

    private final RefService refService;

    @Autowired
    public RepositoryCreatedListener(@ComponentImport RefService refService) {
        this.refService = refService;
    }

    @EventListener
    public void repositoryCreated(RepositoryCreatedEvent evt) {

        try {
            Repository repository = evt.getRepository();
            String projectKey = repository.getProject().getKey();
            String repoSlug = repository.getSlug();

            System.out.println(String.format("REPOSITORY IS BEING CREATED!!!! ACT !!!!!  %s/%s", projectKey, repoSlug));

            CreateBranchRequest createBranchRequest = new CreateBranchRequest.Builder(repository, DEFAULT_BRANCH_NAME, "").build();
            refService.createBranch(createBranchRequest);
        } catch (Exception e) {
            // TODO: do better
            e.printStackTrace();
        }
    }
    }

Dependencies of the plugin project are <bitbucket.version>4.9.1</bitbucket.version> and the same version is used for testing - Atlassian SDK is used for this.

I think other questions have shown the use of bs apis but I use ParallelGit

           org.eclipse.jgit.lib.Repository repo = RepositoryUtils.openRepository(repoDir);

            if (!BranchUtils.branchExists(Constants.MASTER, repo))
            {
                // Create master with the README file.
                DirCache cache = DirCache.newInCore();
                byte[] content = Constants.encode(
                    "The master branch is not used on this project.  Please consult your lead for the latest active branch.");
                AnyObjectId blobId = ObjectUtils.insertBlob(content, repo);
                CacheUtils.addFile("README", FileMode.REGULAR_FILE, blobId, cache);
                AnyObjectId commit = CommitUtils.createCommit("Initial Setup", cache,
                    new PersonIdent(user.getUsername(), user.getEmail()), null, repo);
                BranchUtils.initBranch(Constants.MASTER, commit, repo);
                publishEvent(repository,
                    getRefChanges(Constants.MASTER, ObjectId.zeroId(), repo.resolve(Constants.MASTER), RefChangeType.ADD));
                refService.setDefaultBranch(repository, Constants.MASTER);
                eventPublisher.publish(new BranchCreatedEvent(this, repository, refService.getDefaultBranch(repository)));
            }
1 Like

Thank you very much! This might work!
However how would I know repoDir?

        String repoPath = propertiesService.getRepositoryDir(repository).getAbsolutePath();
        File repoDir = new File(repoPath);

For the latter part, change:

private final RefService refService;

    @Autowired
    public RepositoryCreatedListener(@ComponentImport RefService refService) {
        this.refService = refService;
    }

to:

@ComponentImport
private final RefService refService;

    @Autowired
    public RepositoryCreatedListener( RefService refService) {
        this.refService = refService;
    }

Thanks! Will give it a try tomorrow

Thank you very much! This has helped!
Now into discovering available services and into details of using them

Pardon me, and where is propertiesService coming from?
Suggested by @daniel change helps to resolve ContentService (most probably useless in my case) and RefService, however it does not help to find ApplicationPropertiesService - NoSuchBeanDefinitionException: No qualifying bean of type [com.atlassian.bitbucket.server.ApplicationPropertiesService]

getting to be every question in this community is an issue with annotations. i still use atlassian-plugin.xml. try annotating your class with @scanned

I do not understand why annotations work with some service implementations and do not work with others. However I managed to find propertiesService without annotations.

ApplicationPropertiesService propertiesService = ComponentLocator.getComponent(ApplicationPropertiesService.class);

Thanks for helping out

Don’t use componentlocator. You’ll regret it later especially if you’re doing unit tests and if you’re depending on non-host services.

What’s does your import-package look like in Pom.xml?

Here it is, generated by Atlassian SDK.

This with suggested by you combination of @ComponentImport and @Autowired constructor is enough to resolve RefService and ScmService. However this does not work for ApplicationPropertiesService - Srping fails to find an implementation.

<properties>
    <bitbucket.version>4.9.1</bitbucket.version>
    <bitbucket.data.version>4.9.1</bitbucket.data.version>
    <amps.version>6.2.11</amps.version>
    <plugin.testrunner.version>1.2.3</plugin.testrunner.version>
    <atlassian.spring.scanner.version>1.2.13</atlassian.spring.scanner.version>
    <!-- This key is used to keep the consistency between the key in atlassian-plugin.xml and the key to generate bundle. -->
    <atlassian.plugin.key>${project.groupId}.${project.artifactId}</atlassian.plugin.key>
</properties>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.atlassian.bitbucket.server</groupId>
            <artifactId>bitbucket-parent</artifactId>
            <version>${bitbucket.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>
    <dependency>
        <groupId>com.atlassian.sal</groupId>
        <artifactId>sal-api</artifactId>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>com.atlassian.bitbucket.server</groupId>
        <artifactId>bitbucket-api</artifactId>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>com.atlassian.bitbucket.server</groupId>
        <artifactId>bitbucket-spi</artifactId>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>com.atlassian.bitbucket.server</groupId>
        <artifactId>bitbucket-page-objects</artifactId>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <scope>provided</scope>
    </dependency>

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.10</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>commons-lang</groupId>
        <artifactId>commons-lang</artifactId>
        <version>2.6</version>
        <scope>provided</scope>
    </dependency>

    <dependency>
        <groupId>com.atlassian.plugin</groupId>
        <artifactId>atlassian-spring-scanner-annotation</artifactId>
        <version>${atlassian.spring.scanner.version}</version>
        <scope>compile</scope>
    </dependency>

    <dependency>
        <groupId>com.atlassian.plugin</groupId>
        <artifactId>atlassian-spring-scanner-runtime</artifactId>
        <version>${atlassian.spring.scanner.version}</version>
        <scope>runtime</scope>
    </dependency>

    <dependency>
        <groupId>javax.inject</groupId>
        <artifactId>javax.inject</artifactId>
        <version>1</version>
        <scope>provided</scope>
    </dependency>

    <!-- WIRED TEST RUNNER DEPENDENCIES -->
    <dependency>
        <groupId>javax.ws.rs</groupId>
        <artifactId>jsr311-api</artifactId>
        <version>1.1.1</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.2.2-atlassian-1</version>
    </dependency>
</dependencies>