RedmineService.java

package fr.paris.lutece.plugins.lutecetools.service;

import com.taskadapter.redmineapi.*;
import com.taskadapter.redmineapi.bean.*;
import fr.paris.lutece.plugins.lutecetools.business.Component;
import fr.paris.lutece.portal.service.util.AppLogService;
import fr.paris.lutece.portal.service.util.AppPropertiesService;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class RedmineService implements ComponentInfoFiller
{

    public static final String REDMINE_STATUS = "redmineStatus";
    private static final String SERVICE_NAME = "Redmine Info filler service registered";
    private static final String REDMINE_URL = AppPropertiesService.getProperty( "lutecetools.redmine.url" );
    private static final String REDMINE_API_KEY = AppPropertiesService.getProperty( "lutecetools.redmine.apiKey" );
    private static final int LIMIT = 100; // Maximum limit as per Redmine API

    private final IssueManager issueManager;
    private final ProjectManager projectManager;

    public RedmineService( )
    {
        // Initialize RedmineManager and managers once in the constructor
        RedmineManager redmineManager = RedmineManagerFactory.createWithApiKey( REDMINE_URL, REDMINE_API_KEY );
        this.issueManager = redmineManager.getIssueManager( );
        this.projectManager = redmineManager.getProjectManager( );
    }

    @Override
    public void fill( Component component, StringBuilder sbLogs )
    {
        String strJiraKey = component.get( Component.JIRA_KEY );
        String snapshotVersion = component.get( Component.SNAPSHOT_VERSION );
        component.set( REDMINE_STATUS, 1 );

        if ( strJiraKey == null )
        {
            sbLogs.append( "\n*** ERROR *** No Redmine key defined for component " ).append( component.getArtifactId( ) );
            return;
        }

        try
        {
            Project project = projectManager.getProjectByKey( strJiraKey.toLowerCase( ) );

            // Fetch open issues
            List<Issue> openIssues = fetchIssuesByStatus( project.getId( ), "open" );
            component.set( "redmineOpenIssuesCount", openIssues.size( ) );

            // Fetch closed issues and filter based on snapshotVersion
            List<Issue> closedIssues = fetchIssuesByStatus( project.getId( ), "closed" );
            List<Issue> filteredClosedIssues = closedIssues.stream( ).filter( issue -> {
                String targetVersion = issue.getTargetVersion( ) != null ? issue.getTargetVersion( ).getName( ) : null;
                return targetVersion != null && targetVersion.equals( snapshotVersion.replace( "-SNAPSHOT", "" ) );
            } ).collect( Collectors.toList( ) );

            component.set( "redmineClosedIssuesCount", filteredClosedIssues.size( ) );

            if ( AppLogService.isDebugEnabled( ) )
            {
                StringBuilder sbDebug = new StringBuilder( );
                sbDebug.append( "RedmineService - Project " ).append( strJiraKey ).append( " OpenIssues : " ).append( openIssues.size( ) )
                        .append( " ClosedIssues : " ).append( filteredClosedIssues.size( ) );
                AppLogService.debug( sbDebug.toString( ) );
            }
        }
        catch( RedmineException e )
        {
            sbLogs.append( "\n*** ERROR *** Error accessing Redmine: " ).append( e.getMessage( ) );
        }
    }

    private List<Issue> fetchIssuesByStatus( int projectId, String statusId ) throws RedmineException
    {
        List<Issue> allIssues = new ArrayList<>( );
        int offset = 0;

        while ( true )
        {
            Params params = new Params( ).add( "project_id", String.valueOf( projectId ) ).add( "limit", String.valueOf( LIMIT ) )
                    .add( "offset", String.valueOf( offset ) ).add( "status_id", statusId );

            List<Issue> issues = issueManager.getIssues( params ).getResults( );

            if ( issues.isEmpty( ) )
            {
                break; // Exit the loop if there are no more issues
            }

            allIssues.addAll( issues );
            offset += LIMIT; // Increment offset for the next page
        }

        return allIssues;
    }

    @Override
    public String getName( )
    {
        return SERVICE_NAME;
    }
}