<commit_before>package net.nemerosa.ontrack.extension.svn.service;

import net.nemerosa.ontrack.extension.issues.IssueServiceRegistry;
import net.nemerosa.ontrack.extension.issues.model.ConfiguredIssueService;
import net.nemerosa.ontrack.extension.issues.model.Issue;
import net.nemerosa.ontrack.extension.svn.client.SVNClient;
import net.nemerosa.ontrack.extension.svn.db.*;
import net.nemerosa.ontrack.extension.svn.model.*;
import net.nemerosa.ontrack.extension.svn.property.SVNBranchConfigurationProperty;
import net.nemerosa.ontrack.extension.svn.property.SVNBranchConfigurationPropertyType;
import net.nemerosa.ontrack.extension.svn.support.SVNUtils;
import net.nemerosa.ontrack.model.structure.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

import static net.nemerosa.ontrack.extension.svn.service.SVNServiceUtils.createChangeLogRevision;

@Service
@Transactional
public class SVNServiceImpl implements SVNService {

    private final StructureService structureService;
    private final PropertyService propertyService;
    private final IssueServiceRegistry issueServiceRegistry;
    private final SVNConfigurationService configurationService;
    private final SVNRevisionDao revisionDao;
    private final SVNIssueRevisionDao issueRevisionDao;
    private final SVNEventDao eventDao;
    private final SVNRepositoryDao repositoryDao;
    private final SVNClient svnClient;

    @Autowired
    public SVNServiceImpl(
            StructureService structureService,
            PropertyService propertyService,
            IssueServiceRegistry issueServiceRegistry,
            SVNConfigurationService configurationService,
            SVNRevisionDao revisionDao,
            SVNIssueRevisionDao issueRevisionDao,
            SVNEventDao eventDao,
            SVNRepositoryDao repositoryDao,
            SVNClient svnClient) {
        this.structureService = structureService;
        this.propertyService = propertyService;
        this.issueServiceRegistry = issueServiceRegistry;
        this.configurationService = configurationService;
        this.revisionDao = revisionDao;
        this.issueRevisionDao = issueRevisionDao;
        this.eventDao = eventDao;
        this.repositoryDao = repositoryDao;
        this.svnClient = svnClient;
    }

    @Override
    public SVNRevisionInfo getRevisionInfo(SVNRepository repository, long revision) {
        TRevision t = revisionDao.get(repository.getId(), revision);
        return new SVNRevisionInfo(
                t.getRevision(),
                t.getAuthor(),
                t.getCreation(),
                t.getBranch(),
                t.getMessage(),
                repository.getRevisionBrowsingURL(t.getRevision())
        );
    }

    @Override
    public SVNRevisionPaths getRevisionPaths(SVNRepository repository, long revision) {
        // Gets the diff for the revision
        List<SVNRevisionPath> revisionPaths = svnClient.getRevisionPaths(repository, revision);
        // OK
        return new SVNRevisionPaths(
                getRevisionInfo(repository, revision),
                revisionPaths);
    }

    @Override
    public List<Long> getRevisionsForIssueKey(SVNRepository repository, String key) {
        return issueRevisionDao.findRevisionsByIssue(repository.getId(), key);
    }

    @Override
    public SVNRepository getRepository(String name) {
        SVNConfiguration configuration = configurationService.getConfiguration(name);
        return SVNRepository.of(
                repositoryDao.getOrCreateByName(configuration.getName()),
                // The configuration contained in the property's configuration is obfuscated
                // and the original one must be loaded
                configuration,
                issueServiceRegistry.getConfiguredIssueService(configuration.getIssueServiceConfigurationIdentifier())
        );
    }

    @Override
    public Optional<SVNRepositoryIssue> searchIssues(SVNRepository repository, String token) {
        ConfiguredIssueService configuredIssueService = repository.getConfiguredIssueService();
        if (configuredIssueService != null) {
            return issueRevisionDao.findIssueByKey(repository.getId(), token)
                    .map(key -> new SVNRepositoryIssue(
                                    repository,
                                    configuredIssueService.getIssue(key)
                            )
                    );
        } else {
            return Optional.empty();
        }
    }

    @Override
    public OntrackSVNIssueInfo getIssueInfo(String configurationName, String issueKey) {
        // Repository
        SVNRepository repository = getRepository(configurationName);
        // Issue service
        ConfiguredIssueService configuredIssueService = repository.getConfiguredIssueService();
        if (configuredIssueService == null) {
            // No issue service configured
            return OntrackSVNIssueInfo.empty(repository.getConfiguration());
        }
        // Gets the details about the issue
        Issue issue = configuredIssueService.getIssue(issueKey);
        // Gets the list of revisions & their basic info (order from latest to oldest)
        List<SVNChangeLogRevision> revisions = getRevisionsForIssueKey(repository, issueKey).stream()
                .map(revision -> {
                    SVNRevisionInfo basicInfo = getRevisionInfo(repository, revision);
                    return createChangeLogRevision(
                            repository,
                            basicInfo.getPath(),
                            0,
                            revision,
                            basicInfo.getMessage(),
                            basicInfo.getAuthor(),
                            basicInfo.getDateTime()
                    );
                })
                .collect(Collectors.toList());

        // Gets the last revision (which is the first in the list)
        SVNChangeLogRevision firstRevision = revisions.get(0);
        OntrackSVNRevisionInfo revisionInfo = getOntrackRevisionInfo(repository, firstRevision.getRevision());

        // Merged revisions
        List<Long> merges = revisionDao.getMergesForRevision(repository.getId(), revisionInfo.getRevisionInfo().getRevision());
        List<OntrackSVNRevisionInfo> mergedRevisionInfos = new ArrayList<>();
        Set<String> paths = new HashSet<>();
        for (long merge : merges) {
            // Gets the revision info
            OntrackSVNRevisionInfo mergeRevisionInfo = getOntrackRevisionInfo(repository, merge);
            // If the information contains as least one build, adds it
            if (!mergeRevisionInfo.getBuildViews().isEmpty()) {
                // Keeps only the first one for a given target path
                String path = mergeRevisionInfo.getRevisionInfo().getPath();
                if (!paths.contains(path)) {
                    mergedRevisionInfos.add(mergeRevisionInfo);
                    paths.add(path);
                }
            }
        }

        // OK
        return new OntrackSVNIssueInfo(
                repository.getConfiguration(),
                repository.getConfiguredIssueService().getIssueServiceConfigurationRepresentation(),
                issue,
                revisionInfo,
                mergedRevisionInfos
        );

    }

    @Override
    public OntrackSVNRevisionInfo getOntrackRevisionInfo(SVNRepository repository, long revision) {

        // Gets information about the revision
        SVNRevisionInfo basicInfo = getRevisionInfo(repository, revision);
        SVNChangeLogRevision changeLogRevision = createChangeLogRevision(
                repository,
                basicInfo.getPath(),
                0,
                revision,
                basicInfo.getMessage(),
                basicInfo.getAuthor(),
                basicInfo.getDateTime()
        );

        // Gets the first copy event on this path after this revision
        SVNLocation firstCopy = getFirstCopyAfter(repository, basicInfo.toLocation());

        // Data to collect
        Collection<BuildView> buildViews = new ArrayList<>();
        // Loops over all authorised branches
        for (Project project : structureService.getProjectList()) {
            for (Branch branch : structureService.getBranchesForProject(project.getId())) {
                // Identifies a possible build given the path/revision and the first copy
                Optional<Build> build = lookupBuild(basicInfo.toLocation(), firstCopy, branch);
                // Build found
                if (build.isPresent()) {
                    // Gets the build view
                    BuildView buildView = structureService.getBuildView(build.get());
                    // Adds it to the list
                    buildViews.add(buildView);
                }
            }
        }

        // OK
        return new OntrackSVNRevisionInfo(
                repository.getConfiguration(),
                changeLogRevision,
                buildViews
        );

    }
<commit_msg>Revision info: filter projects & branches on the SVN configuration present or not<commit_after>package net.nemerosa.ontrack.extension.svn.service;

import net.nemerosa.ontrack.extension.issues.IssueServiceRegistry;
import net.nemerosa.ontrack.extension.issues.model.ConfiguredIssueService;
import net.nemerosa.ontrack.extension.issues.model.Issue;
import net.nemerosa.ontrack.extension.svn.client.SVNClient;
import net.nemerosa.ontrack.extension.svn.db.*;
import net.nemerosa.ontrack.extension.svn.model.*;
import net.nemerosa.ontrack.extension.svn.property.SVNBranchConfigurationProperty;
import net.nemerosa.ontrack.extension.svn.property.SVNBranchConfigurationPropertyType;
import net.nemerosa.ontrack.extension.svn.property.SVNProjectConfigurationPropertyType;
import net.nemerosa.ontrack.extension.svn.support.SVNUtils;
import net.nemerosa.ontrack.model.structure.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

import static net.nemerosa.ontrack.extension.svn.service.SVNServiceUtils.createChangeLogRevision;

@Service
@Transactional
public class SVNServiceImpl implements SVNService {

    private final StructureService structureService;
    private final PropertyService propertyService;
    private final IssueServiceRegistry issueServiceRegistry;
    private final SVNConfigurationService configurationService;
    private final SVNRevisionDao revisionDao;
    private final SVNIssueRevisionDao issueRevisionDao;
    private final SVNEventDao eventDao;
    private final SVNRepositoryDao repositoryDao;
    private final SVNClient svnClient;

    @Autowired
    public SVNServiceImpl(
            StructureService structureService,
            PropertyService propertyService,
            IssueServiceRegistry issueServiceRegistry,
            SVNConfigurationService configurationService,
            SVNRevisionDao revisionDao,
            SVNIssueRevisionDao issueRevisionDao,
            SVNEventDao eventDao,
            SVNRepositoryDao repositoryDao,
            SVNClient svnClient) {
        this.structureService = structureService;
        this.propertyService = propertyService;
        this.issueServiceRegistry = issueServiceRegistry;
        this.configurationService = configurationService;
        this.revisionDao = revisionDao;
        this.issueRevisionDao = issueRevisionDao;
        this.eventDao = eventDao;
        this.repositoryDao = repositoryDao;
        this.svnClient = svnClient;
    }

    @Override
    public SVNRevisionInfo getRevisionInfo(SVNRepository repository, long revision) {
        TRevision t = revisionDao.get(repository.getId(), revision);
        return new SVNRevisionInfo(
                t.getRevision(),
                t.getAuthor(),
                t.getCreation(),
                t.getBranch(),
                t.getMessage(),
                repository.getRevisionBrowsingURL(t.getRevision())
        );
    }

    @Override
    public SVNRevisionPaths getRevisionPaths(SVNRepository repository, long revision) {
        // Gets the diff for the revision
        List<SVNRevisionPath> revisionPaths = svnClient.getRevisionPaths(repository, revision);
        // OK
        return new SVNRevisionPaths(
                getRevisionInfo(repository, revision),
                revisionPaths);
    }

    @Override
    public List<Long> getRevisionsForIssueKey(SVNRepository repository, String key) {
        return issueRevisionDao.findRevisionsByIssue(repository.getId(), key);
    }

    @Override
    public SVNRepository getRepository(String name) {
        SVNConfiguration configuration = configurationService.getConfiguration(name);
        return SVNRepository.of(
                repositoryDao.getOrCreateByName(configuration.getName()),
                // The configuration contained in the property's configuration is obfuscated
                // and the original one must be loaded
                configuration,
                issueServiceRegistry.getConfiguredIssueService(configuration.getIssueServiceConfigurationIdentifier())
        );
    }

    @Override
    public Optional<SVNRepositoryIssue> searchIssues(SVNRepository repository, String token) {
        ConfiguredIssueService configuredIssueService = repository.getConfiguredIssueService();
        if (configuredIssueService != null) {
            return issueRevisionDao.findIssueByKey(repository.getId(), token)
                    .map(key -> new SVNRepositoryIssue(
                                    repository,
                                    configuredIssueService.getIssue(key)
                            )
                    );
        } else {
            return Optional.empty();
        }
    }

    @Override
    public OntrackSVNIssueInfo getIssueInfo(String configurationName, String issueKey) {
        // Repository
        SVNRepository repository = getRepository(configurationName);
        // Issue service
        ConfiguredIssueService configuredIssueService = repository.getConfiguredIssueService();
        if (configuredIssueService == null) {
            // No issue service configured
            return OntrackSVNIssueInfo.empty(repository.getConfiguration());
        }
        // Gets the details about the issue
        Issue issue = configuredIssueService.getIssue(issueKey);
        // Gets the list of revisions & their basic info (order from latest to oldest)
        List<SVNChangeLogRevision> revisions = getRevisionsForIssueKey(repository, issueKey).stream()
                .map(revision -> {
                    SVNRevisionInfo basicInfo = getRevisionInfo(repository, revision);
                    return createChangeLogRevision(
                            repository,
                            basicInfo.getPath(),
                            0,
                            revision,
                            basicInfo.getMessage(),
                            basicInfo.getAuthor(),
                            basicInfo.getDateTime()
                    );
                })
                .collect(Collectors.toList());

        // Gets the last revision (which is the first in the list)
        SVNChangeLogRevision firstRevision = revisions.get(0);
        OntrackSVNRevisionInfo revisionInfo = getOntrackRevisionInfo(repository, firstRevision.getRevision());

        // Merged revisions
        List<Long> merges = revisionDao.getMergesForRevision(repository.getId(), revisionInfo.getRevisionInfo().getRevision());
        List<OntrackSVNRevisionInfo> mergedRevisionInfos = new ArrayList<>();
        Set<String> paths = new HashSet<>();
        for (long merge : merges) {
            // Gets the revision info
            OntrackSVNRevisionInfo mergeRevisionInfo = getOntrackRevisionInfo(repository, merge);
            // If the information contains as least one build, adds it
            if (!mergeRevisionInfo.getBuildViews().isEmpty()) {
                // Keeps only the first one for a given target path
                String path = mergeRevisionInfo.getRevisionInfo().getPath();
                if (!paths.contains(path)) {
                    mergedRevisionInfos.add(mergeRevisionInfo);
                    paths.add(path);
                }
            }
        }

        // OK
        return new OntrackSVNIssueInfo(
                repository.getConfiguration(),
                repository.getConfiguredIssueService().getIssueServiceConfigurationRepresentation(),
                issue,
                revisionInfo,
                mergedRevisionInfos
        );

    }

    @Override
    public OntrackSVNRevisionInfo getOntrackRevisionInfo(SVNRepository repository, long revision) {

        // Gets information about the revision
        SVNRevisionInfo basicInfo = getRevisionInfo(repository, revision);
        SVNChangeLogRevision changeLogRevision = createChangeLogRevision(
                repository,
                basicInfo.getPath(),
                0,
                revision,
                basicInfo.getMessage(),
                basicInfo.getAuthor(),
                basicInfo.getDateTime()
        );

        // Gets the first copy event on this path after this revision
        SVNLocation firstCopy = getFirstCopyAfter(repository, basicInfo.toLocation());

        // Data to collect
        Collection<BuildView> buildViews = new ArrayList<>();
        // Loops over all authorised branches
        for (Project project : structureService.getProjectList()) {
            // Filter on SVN configuration
            if (propertyService.hasProperty(project, SVNProjectConfigurationPropertyType.class)) {
                for (Branch branch : structureService.getBranchesForProject(project.getId())) {
                    // Filter on SVN configuration
                    if (propertyService.hasProperty(branch, SVNBranchConfigurationPropertyType.class)) {
                        // Identifies a possible build given the path/revision and the first copy
                        Optional<Build> build = lookupBuild(basicInfo.toLocation(), firstCopy, branch);
                        // Build found
                        if (build.isPresent()) {
                            // Gets the build view
                            BuildView buildView = structureService.getBuildView(build.get());
                            // Adds it to the list
                            buildViews.add(buildView);
                        }
                    }
                }
            }
        }

        // OK
        return new OntrackSVNRevisionInfo(
                repository.getConfiguration(),
                changeLogRevision,
                buildViews
        );

    }

{'fraction_non_alphanumeric': 0.07168364667576935, 'fraction_numerical': 0.0003150929524209642, 'mean_word_length': 2.2424655201770816, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6207972', 'n_tokens_mistral': 4598, 'n_tokens_neox': 4378, 'n_words': 973}