From 78e5ca7247c92b727d6a267547a229e3302bb59a Mon Sep 17 00:00:00 2001 From: braburgut Date: Tue, 6 May 2025 12:06:09 +0200 Subject: [PATCH 01/12] =?UTF-8?q?A=C3=B1adir=20test=20para=20IndicatorStra?= =?UTF-8?q?tegy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../test/control/IndicatorStrategyTest.java | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java diff --git a/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java b/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java new file mode 100644 index 00000000..1e17d7e8 --- /dev/null +++ b/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java @@ -0,0 +1,127 @@ +package us.muit.fs.a4i.test.control; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +import java.util.logging.Logger; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import static org.mockito.Mockito.*; + +import java.util.Arrays; +import java.util.List; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import us.muit.fs.a4i.control.IndicatorStrategy; +import us.muit.fs.a4i.exceptions.NotAvailableMetricException; +import us.muit.fs.a4i.model.entities.ReportItemI; + +/** + * + */ + +public class IndicatorStrategyTest { + + private static Logger log = Logger.getLogger(IndicatorStrategyTest.class.getName()); + + @Test + public void testCalcIndicator() throws NotAvailableMetricException { + // Creamos los mocks necesarios + ReportItemI mockMRI = Mockito.mock(ReportItemI.class); + ReportItemI mockTRPI = Mockito.mock(ReportItemI.class); + ReportItemI mockIAPC = Mockito.mock(ReportItemI.class); + + // Configuramos los mocks para devolver valores predefinidos + Mockito.when(mockMRI.getName()).thenReturn("reopenedIssuesAvg"); + Mockito.when(mockMRI.getValue()).thenReturn(0.5); // Media Reapertura Issues + + Mockito.when(mockTRPI.getName()).thenReturn("firstTryResolutionRate"); + Mockito.when(mockTRPI.getValue()).thenReturn(80.0); // Tasa Resolución Primer Intento + + Mockito.when(mockIAPC.getName()).thenReturn("postClosureActivityRate"); + Mockito.when(mockIAPC.getValue()).thenReturn(20.0); // Issues con Actividad Posterior al Cierre + + // Creamos una instancia de IndicatorStrategy + IndicatorStrategy indicator = new IndicatorStrategy(); + + // Ejecutamos el método que queremos probar con los mocks como argumentos + List> metrics = Arrays.asList(mockMRI, mockTRPI, mockIAPC); + ReportItemI result = indicator.calcIndicator(metrics); + + // Comprobamos que el resultado es el esperado + // Cálculo esperado: + // Calidad = 0.3 * %MRI + 0.4 * %TRPI + 0.3 * (100 - %IAPC) + // %MRI = (0.5 - 0.3) / 1.7 * 100 = 11.76 + // %TRPI = 80.0 + // %IAPC = 20.0 -> 100 - 20 = 80.0 + // Calidad = 0.3 * 11.76 + 0.4 * 80 + 0.3 * 80 = 71.76 + + Assertions.assertEquals("calidadResolucion", result.getName()); + Assertions.assertEquals(71.76, result.getValue(), 0.5); // Con margen de error para la comparación + Assertions.assertDoesNotThrow(() -> indicator.calcIndicator(metrics)); + } + + @Test + public void testCalcIndicatorThrowsNotAvailableMetricException() { + // Creamos los mocks necesarios + ReportItemI mockMRI = Mockito.mock(ReportItemI.class); + + // Configuramos el mock para devolver un valor predefinido + Mockito.when(mockMRI.getName()).thenReturn("reopenedIssuesAvg"); + Mockito.when(mockMRI.getValue()).thenReturn(0.5); + + // Creamos una instancia de IndicatorStrategy + IndicatorStrategy indicator = new IndicatorStrategy(); + + // Ejecutamos el método que queremos probar con métricas insuficientes + List> metrics = Arrays.asList(mockMRI); + + // Comprobamos que se lanza la excepción adecuada + NotAvailableMetricException exception = Assertions.assertThrows(NotAvailableMetricException.class, + () -> indicator.calcIndicator(metrics)); + } + + @Test + public void testRequiredMetrics() { + // Creamos una instancia de IndicatorStrategy + IndicatorStrategy indicatorStrategy = new IndicatorStrategy(); + + // Ejecutamos el método que queremos probar + List requiredMetrics = indicatorStrategy.requiredMetrics(); + + // Comprobamos que el resultado es el esperado + List expectedMetrics = Arrays.asList("reopenedIssuesAvg", "firstTryResolutionRate", "postClosureActivityRate"); + Assertions.assertEquals(expectedMetrics, requiredMetrics); + } + + @Test + public void testCalcIndicatorWithExtremeValues() throws NotAvailableMetricException { + ReportItemI mri = Mockito.mock(ReportItemI.class); + ReportItemI trpi = Mockito.mock(ReportItemI.class); + ReportItemI iapc = Mockito.mock(ReportItemI.class); + + Mockito.when(mri.getName()).thenReturn("reopenedIssuesAvg"); + Mockito.when(mri.getValue()).thenReturn(0.0); + + Mockito.when(trpi.getName()).thenReturn("firstTryResolutionRate"); + Mockito.when(trpi.getValue()).thenReturn(100.0); + + Mockito.when(iapc.getName()).thenReturn("postClosureActivityRate"); + Mockito.when(iapc.getValue()).thenReturn(0.0); + + IndicatorStrategy indicator = new IndicatorStrategy(); + List> metrics = Arrays.asList(mri, trpi, iapc); + ReportItemI result = indicator.calcIndicator(metrics); + + // Aquí el resultado será alto (cerca de 100) + Assertions.assertTrue(result.getValue() > 90.0); + } + +} \ No newline at end of file From f5caa3df61f5a482980b6a2243d713389f6ce800 Mon Sep 17 00:00:00 2001 From: pabcabrod1 Date: Tue, 6 May 2025 11:30:23 +0100 Subject: [PATCH 02/12] =?UTF-8?q?Creaci=C3=B3n=20test=20RemoteEnquirer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../a4i/model/remote/RemoteEnquirerTest.java | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 src/test/java/us/muit/fs/a4i/model/remote/RemoteEnquirerTest.java diff --git a/src/test/java/us/muit/fs/a4i/model/remote/RemoteEnquirerTest.java b/src/test/java/us/muit/fs/a4i/model/remote/RemoteEnquirerTest.java new file mode 100644 index 00000000..9cf32da0 --- /dev/null +++ b/src/test/java/us/muit/fs/a4i/model/remote/RemoteEnquirerTest.java @@ -0,0 +1,68 @@ +/** + * + */ +package us.muit.fs.a4i.model.remote; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.util.Arrays; +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import us.muit.fs.a4i.exceptions.MetricException; +import us.muit.fs.a4i.model.entities.ReportI; +import us.muit.fs.a4i.model.entities.ReportItemI; +import us.muit.fs.a4i.model.remote.RemoteEnquirer; + +class RemoteEnquirerTest { + + private RemoteEnquirer enquirer; + + private ReportI mockReport; + private ReportItemI mockMetric; + + @BeforeEach + void setUp() throws MetricException { + // Creamos el mock de la interfaz + enquirer = mock(RemoteEnquirer.class); + + // Creamos mocks para los valores devueltos + mockReport = mock(ReportI.class); + mockMetric = mock(ReportItemI.class); + + // Definimos comportamiento del mock + when(enquirer.buildReport("test-entity")).thenReturn(mockReport); + when(enquirer.getMetric("reopenedIssuesAvg", "test-entity")).thenReturn(mockMetric); + when(enquirer.getAvailableMetrics()).thenReturn( + Arrays.asList("reopenedIssuesAvg", "firstTryResolutionRate", "postClosureActivityRate") + ); + when(enquirer.getRemoteType()).thenReturn(RemoteEnquirer.RemoteType.GITHUB); + } + + @Test + void testBuildReport() { + ReportI report = enquirer.buildReport("test-entity"); + assertNotNull(report); + } + + @Test + void testGetMetric() throws MetricException { + ReportItemI metric = enquirer.getMetric("reopenedIssuesAvg", "test-entity"); + assertNotNull(metric); + } + + @Test + void testGetAvailableMetrics() { + List metrics = enquirer.getAvailableMetrics(); + assertEquals(3, metrics.size()); + assertTrue(metrics.contains("reopenedIssuesAvg")); + } + + @Test + void testGetRemoteType() { + assertEquals(RemoteEnquirer.RemoteType.GITHUB, enquirer.getRemoteType()); + } +} From 7235a17edb7ebdf228eb3a5b26115132c7a77460 Mon Sep 17 00:00:00 2001 From: braburgut Date: Tue, 6 May 2025 12:52:20 +0200 Subject: [PATCH 03/12] =?UTF-8?q?A=C3=B1adir=20clase=20GitHubRemoteEnquire?= =?UTF-8?q?r?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/remote/GitHubRemoteEnquirer.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/main/java/us/muit/fs/a4i/model/remote/GitHubRemoteEnquirer.java diff --git a/src/main/java/us/muit/fs/a4i/model/remote/GitHubRemoteEnquirer.java b/src/main/java/us/muit/fs/a4i/model/remote/GitHubRemoteEnquirer.java new file mode 100644 index 00000000..734f9aa7 --- /dev/null +++ b/src/main/java/us/muit/fs/a4i/model/remote/GitHubRemoteEnquirer.java @@ -0,0 +1,37 @@ +/** + * + */ +package us.muit.fs.a4i.model.remote; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +import org.kohsuke.github.GHBranch; +import org.kohsuke.github.GHCommit; +import org.kohsuke.github.GHIssue; +import org.kohsuke.github.GHIssueState; +import org.kohsuke.github.GHPullRequest; +import org.kohsuke.github.GHRepository; +import org.kohsuke.github.GHRepositoryStatistics; +import org.kohsuke.github.GHRepositoryStatistics.CodeFrequency; +import org.kohsuke.github.GHUser; +import org.kohsuke.github.GitHub; +import org.kohsuke.github.PagedIterable; + +import us.muit.fs.a4i.config.GitFlow; +import us.muit.fs.a4i.exceptions.MetricException; +import us.muit.fs.a4i.exceptions.ReportItemException; +import us.muit.fs.a4i.model.entities.Report; +import us.muit.fs.a4i.model.entities.ReportI; +import us.muit.fs.a4i.model.entities.ReportItem; +import us.muit.fs.a4i.model.entities.ReportItem.ReportItemBuilder; + From e4fde1368df9212f1f43a035fb17db5f5928f624 Mon Sep 17 00:00:00 2001 From: braburgut Date: Tue, 6 May 2025 17:23:17 +0200 Subject: [PATCH 04/12] =?UTF-8?q?Peque=C3=B1o=20arreglo=20en=20IndicatorSt?= =?UTF-8?q?rategyTest?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../us/muit/fs/a4i/test/control/IndicatorStrategyTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java b/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java index 1e17d7e8..d1c78c2e 100644 --- a/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java +++ b/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java @@ -57,14 +57,14 @@ public void testCalcIndicator() throws NotAvailableMetricException { // Comprobamos que el resultado es el esperado // Cálculo esperado: - // Calidad = 0.3 * %MRI + 0.4 * %TRPI + 0.3 * (100 - %IAPC) + // Calidad = 0.3 * (100 - %MRI) + 0.4 * %TRPI + 0.3 * (100 - %IAPC) // %MRI = (0.5 - 0.3) / 1.7 * 100 = 11.76 // %TRPI = 80.0 // %IAPC = 20.0 -> 100 - 20 = 80.0 - // Calidad = 0.3 * 11.76 + 0.4 * 80 + 0.3 * 80 = 71.76 + // Calidad = 0.3 * (100 - 11.76) + 0.4 * 80 + 0.3 * 80 = 82.47 Assertions.assertEquals("calidadResolucion", result.getName()); - Assertions.assertEquals(71.76, result.getValue(), 0.5); // Con margen de error para la comparación + Assertions.assertEquals(82.47, result.getValue(), 0.5); // Con margen de error para la comparación Assertions.assertDoesNotThrow(() -> indicator.calcIndicator(metrics)); } From 186a749e91cdb035285ad3b6b9cb107bc9e6c51e Mon Sep 17 00:00:00 2001 From: braburgut Date: Tue, 6 May 2025 17:56:20 +0200 Subject: [PATCH 05/12] Actualizacion de IndicatorStrategyTest --- .../muit/fs/a4i/test/control/IndicatorStrategyTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java b/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java index d1c78c2e..1de08ed4 100644 --- a/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java +++ b/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java @@ -49,7 +49,7 @@ public void testCalcIndicator() throws NotAvailableMetricException { Mockito.when(mockIAPC.getValue()).thenReturn(20.0); // Issues con Actividad Posterior al Cierre // Creamos una instancia de IndicatorStrategy - IndicatorStrategy indicator = new IndicatorStrategy(); + IndicatorStrategy indicator = new CalidadStrategy(); // Ejecutamos el método que queremos probar con los mocks como argumentos List> metrics = Arrays.asList(mockMRI, mockTRPI, mockIAPC); @@ -78,7 +78,7 @@ public void testCalcIndicatorThrowsNotAvailableMetricException() { Mockito.when(mockMRI.getValue()).thenReturn(0.5); // Creamos una instancia de IndicatorStrategy - IndicatorStrategy indicator = new IndicatorStrategy(); + IndicatorStrategy indicator = new CalidadStrategy(); // Ejecutamos el método que queremos probar con métricas insuficientes List> metrics = Arrays.asList(mockMRI); @@ -91,7 +91,7 @@ public void testCalcIndicatorThrowsNotAvailableMetricException() { @Test public void testRequiredMetrics() { // Creamos una instancia de IndicatorStrategy - IndicatorStrategy indicatorStrategy = new IndicatorStrategy(); + IndicatorStrategy indicatorStrategy = new CalidadStrategy(); // Ejecutamos el método que queremos probar List requiredMetrics = indicatorStrategy.requiredMetrics(); @@ -116,7 +116,7 @@ public void testCalcIndicatorWithExtremeValues() throws NotAvailableMetricExcept Mockito.when(iapc.getName()).thenReturn("postClosureActivityRate"); Mockito.when(iapc.getValue()).thenReturn(0.0); - IndicatorStrategy indicator = new IndicatorStrategy(); + IndicatorStrategy indicator = new CalidadStrategy(); List> metrics = Arrays.asList(mri, trpi, iapc); ReportItemI result = indicator.calcIndicator(metrics); From 056ea2d65aa4cb819ebb67a619b266ceb9be48ea Mon Sep 17 00:00:00 2001 From: braburgut Date: Sun, 11 May 2025 12:11:37 +0200 Subject: [PATCH 06/12] Completada clase GitHubRemoteEnquirer --- .../model/remote/GitHubRemoteEnquirer.java | 141 ++++++++++++++---- src/main/resources/a4iDefault.json | 20 ++- .../a4i/model/remote/RemoteEnquirerTest.java | 30 ++-- src/test/resources/appConfTest.json | 20 ++- 4 files changed, 159 insertions(+), 52 deletions(-) diff --git a/src/main/java/us/muit/fs/a4i/model/remote/GitHubRemoteEnquirer.java b/src/main/java/us/muit/fs/a4i/model/remote/GitHubRemoteEnquirer.java index 734f9aa7..17b1e38b 100644 --- a/src/main/java/us/muit/fs/a4i/model/remote/GitHubRemoteEnquirer.java +++ b/src/main/java/us/muit/fs/a4i/model/remote/GitHubRemoteEnquirer.java @@ -1,37 +1,120 @@ -/** - * - */ package us.muit.fs.a4i.model.remote; -import java.io.IOException; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.util.Calendar; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.logging.Logger; -import java.util.stream.Collectors; - -import org.kohsuke.github.GHBranch; -import org.kohsuke.github.GHCommit; -import org.kohsuke.github.GHIssue; -import org.kohsuke.github.GHIssueState; -import org.kohsuke.github.GHPullRequest; -import org.kohsuke.github.GHRepository; -import org.kohsuke.github.GHRepositoryStatistics; -import org.kohsuke.github.GHRepositoryStatistics.CodeFrequency; -import org.kohsuke.github.GHUser; -import org.kohsuke.github.GitHub; -import org.kohsuke.github.PagedIterable; - -import us.muit.fs.a4i.config.GitFlow; +import us.muit.fs.a4i.model.remote.RemoteEnquirer; import us.muit.fs.a4i.exceptions.MetricException; import us.muit.fs.a4i.exceptions.ReportItemException; import us.muit.fs.a4i.model.entities.Report; import us.muit.fs.a4i.model.entities.ReportI; -import us.muit.fs.a4i.model.entities.ReportItem; import us.muit.fs.a4i.model.entities.ReportItem.ReportItemBuilder; +import us.muit.fs.a4i.model.entities.ReportItemI; + + +import org.kohsuke.github.*; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class GitHubRemoteEnquirer implements RemoteEnquirer { + + private static final List AVAILABLE_METRICS = List.of( + "reopenedIssuesAvg", + "firstTryResolutionRate", + "postClosureActivityRate" + ); + + private final GitHub github; + + public GitHubRemoteEnquirer() throws IOException { + String token = System.getenv("GITHUB_OAUTH"); + this.github = new GitHubBuilder().withOAuthToken(token).build(); + } + + @Override + public ReportI buildReport(String repoFullName) { + Report report = new Report(repoFullName); + for (String metric : AVAILABLE_METRICS) { + try { + report.addMetric(getMetric(metric, repoFullName)); + } catch (MetricException e) { + System.err.println("Error al obtener la métrica: " + metric); + } + } + return report; + } + + @Override + public ReportItemI getMetric(String metricName, String repoFullName) throws MetricException { + try { + GHRepository repo = github.getRepository(repoFullName); + List issues = repo.getIssues(GHIssueState.CLOSED); + int reopenedCount = 0; + int firstTrySuccess = 0; + int postClosureActivity = 0; + + for (GHIssue issue : issues) { + boolean reopened = false; + for (GHIssueEvent event : issue.listEvents()) { + if (event.getEvent().equals("reopened")) { + reopened = true; + reopenedCount++; + break; + } + } + + if (!reopened) { + firstTrySuccess++; + } + + if (issue.getUpdatedAt().after(issue.getClosedAt())) { + postClosureActivity++; + } + } + + int totalIssues = issues.size(); + if (totalIssues == 0) throw new MetricException("No hay issues cerrados para analizar."); + + double avgReopened = (double) reopenedCount / totalIssues; + double trpi = ((double) firstTrySuccess / totalIssues) * 100; + double pcap = ((double) postClosureActivity / totalIssues) * 100; + + try { + switch (metricName) { + case "reopenedIssuesAvg": + return new ReportItemBuilder(metricName, avgReopened) + .source("GitHub") + .build(); + + case "firstTryResolutionRate": + return new ReportItemBuilder(metricName, trpi) + .source("GitHub") + .build(); + + case "postClosureActivityRate": + return new ReportItemBuilder(metricName, pcap) + .source("GitHub") + .build(); + + default: + throw new MetricException("Métrica no definida: " + metricName); + } + + } catch (ReportItemException e) { + throw new MetricException("Error al construir el ReportItem para " + metricName + ": " + e.getMessage()); + } + + } catch (IOException e) { + throw new MetricException("Error al procesar la métrica: " + e.getMessage()); + } + } + + @Override + public List getAvailableMetrics() { + return new ArrayList<>(AVAILABLE_METRICS); + } + @Override + public RemoteType getRemoteType() { + return RemoteType.GITHUB; + } +} diff --git a/src/main/resources/a4iDefault.json b/src/main/resources/a4iDefault.json index 33cee922..d76b8501 100644 --- a/src/main/resources/a4iDefault.json +++ b/src/main/resources/a4iDefault.json @@ -233,7 +233,25 @@ "type": "java.lang.Integer", "description": "Balance de equipos y open issues", "unit": "ratio" - } + }, + { + "name": "reopenedIssuesAvg", + "type": "java.lang.Double", + "description": "Media de issues reabiertos en el ultimo sprint", + "unit": "issues/sprint" + }, + { + "name": "reopenedIssuesResolutionRate", + "type": "java.lang.Double", + "description": "Porcentaje de issues que se resuelven en el primer intento sin necesidad de ser reabiertos", + "unit": "ratio" + }, + { + "name": "postClosureActivityRate", + "type": "java.lang.Double", + "description": "Porcentaje de issues cerrados que reciben comentarios o actividades adicionales", + "unit": "ratio" + } ], "indicators": [ { diff --git a/src/test/java/us/muit/fs/a4i/model/remote/RemoteEnquirerTest.java b/src/test/java/us/muit/fs/a4i/model/remote/RemoteEnquirerTest.java index 9cf32da0..f6a4c1a3 100644 --- a/src/test/java/us/muit/fs/a4i/model/remote/RemoteEnquirerTest.java +++ b/src/test/java/us/muit/fs/a4i/model/remote/RemoteEnquirerTest.java @@ -6,6 +6,7 @@ import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; +import java.io.IOException; import java.util.Arrays; import java.util.List; @@ -19,46 +20,33 @@ class RemoteEnquirerTest { - private RemoteEnquirer enquirer; - - private ReportI mockReport; - private ReportItemI mockMetric; + private GitHubRemoteEnquirer enquirer; @BeforeEach - void setUp() throws MetricException { - // Creamos el mock de la interfaz - enquirer = mock(RemoteEnquirer.class); - - // Creamos mocks para los valores devueltos - mockReport = mock(ReportI.class); - mockMetric = mock(ReportItemI.class); - - // Definimos comportamiento del mock - when(enquirer.buildReport("test-entity")).thenReturn(mockReport); - when(enquirer.getMetric("reopenedIssuesAvg", "test-entity")).thenReturn(mockMetric); - when(enquirer.getAvailableMetrics()).thenReturn( - Arrays.asList("reopenedIssuesAvg", "firstTryResolutionRate", "postClosureActivityRate") - ); - when(enquirer.getRemoteType()).thenReturn(RemoteEnquirer.RemoteType.GITHUB); + void setUp() throws MetricException, IOException { + enquirer = new GitHubRemoteEnquirer(); } @Test void testBuildReport() { - ReportI report = enquirer.buildReport("test-entity"); + ReportI report = enquirer.buildReport("MIT-FS/Audit4Improve-API"); assertNotNull(report); } @Test void testGetMetric() throws MetricException { - ReportItemI metric = enquirer.getMetric("reopenedIssuesAvg", "test-entity"); + ReportItemI metric = enquirer.getMetric("reopenedIssuesAvg", "MIT-FS/Audit4Improve-API"); assertNotNull(metric); } + @Test void testGetAvailableMetrics() { List metrics = enquirer.getAvailableMetrics(); assertEquals(3, metrics.size()); assertTrue(metrics.contains("reopenedIssuesAvg")); + assertTrue(metrics.contains("firstTryResolutionRate")); + assertTrue(metrics.contains("postClosureActivityRate")); } @Test diff --git a/src/test/resources/appConfTest.json b/src/test/resources/appConfTest.json index ae5c655c..42ba8a15 100644 --- a/src/test/resources/appConfTest.json +++ b/src/test/resources/appConfTest.json @@ -11,7 +11,25 @@ "type": "java.lang.Integer", "description": "Número de comentarios", "unit": "comments" - } + }, + { + "name": "reopenedIssuesAvg", + "type": "java.lang.Double", + "description": "Media de issues reabiertos en el ultimo sprint", + "unit": "issues/sprint" + }, + { + "name": "reopenedIssuesResolutionRate", + "type": "java.lang.Double", + "description": "Porcentaje de issues que se resuelven en el primer intento sin necesidad de ser reabiertos", + "unit": "ratio" + }, + { + "name": "postClosureActivityRate", + "type": "java.lang.Double", + "description": "Porcentaje de issues cerrados que reciben comentarios o actividades adicionales", + "unit": "ratio" + } ], "indicators": [ { From be1feb2a26fbc2e82ac3c5bafbdcd6287bd2756b Mon Sep 17 00:00:00 2001 From: pabcabrod1 Date: Sun, 11 May 2025 20:03:29 +0200 Subject: [PATCH 07/12] =?UTF-8?q?Creaci=C3=B3n=20Indicator=20Strategy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 7 +- .../fs/a4i/control/IndicatorStrategy.java | 98 ++++++++++++++----- src/main/resources/a4iDefault.json | 21 +++- .../test/control/IndicatorStrategyTest.java | 7 +- 4 files changed, 101 insertions(+), 32 deletions(-) diff --git a/build.gradle b/build.gradle index 95067239..d2cdebcf 100644 --- a/build.gradle +++ b/build.gradle @@ -23,10 +23,11 @@ plugins { //Para publicar paquetes en github publishing { + repositories { maven { name = "GitHubPackages" - url = uri("https://maven.pkg.github.com/mit-fs/audit4improve-api") + url = uri("https://maven.pkg.github.com/pabcabrod1/Audit4Improve-API") credentials { //las propiedades gpr.user y gpr.key están configuradas en gradle.properties en el raiz del proyecto, y se añade a .gitignore para que no se suban //O bien configuro las variables de entorno GITHUB_LOGIN y GITHUB_PACKAGES @@ -41,14 +42,14 @@ publishing { groupId = 'us.mitfs.samples' artifactId = 'a4i' - version = '0.2' + version = '0.2-pabcabrod1' from components.java } } } -version = '0.2' +version = '0.2-pabcabrod1' //group = 'us.mitfs.samples' tasks.withType(JavaCompile) { //Añadir la opción Xlint diff --git a/src/main/java/us/muit/fs/a4i/control/IndicatorStrategy.java b/src/main/java/us/muit/fs/a4i/control/IndicatorStrategy.java index 608406fb..46bac35a 100644 --- a/src/main/java/us/muit/fs/a4i/control/IndicatorStrategy.java +++ b/src/main/java/us/muit/fs/a4i/control/IndicatorStrategy.java @@ -1,37 +1,83 @@ package us.muit.fs.a4i.control; import java.util.List; +import java.util.Arrays; import us.muit.fs.a4i.exceptions.NotAvailableMetricException; +import us.muit.fs.a4i.exceptions.ReportItemException; +import us.muit.fs.a4i.model.entities.ReportItem; import us.muit.fs.a4i.model.entities.ReportItemI; /** - * /** - *

- * Interfaz para calcular indicadores - *

- * - * @param - * @author celllarod - * + * Estrategia para calcular el indicador de calidad de resolución. */ -public interface IndicatorStrategy { - - /** - * Calcula un indicador a partir de las métricas proporcionadas. - * - * @param - * @param metrics - * @throws NotAvailableMetricException - * @return indicador - */ - public ReportItemI calcIndicator(List> metrics) throws NotAvailableMetricException; - - /** - * Obtiene las métricas necesarias - * - * @return listado de métricas - */ - public List requiredMetrics(); +public class IndicatorStrategy { + private static final String MRI = "reopenedIssuesAvg"; + private static final String TRPI = "firstTryResolutionRate"; + private static final String IAPC = "postClosureActivityRate"; + private static final String RESULT_NAME = "calidadResolucion"; + + /** + * Calcula el indicador a partir de una lista de métricas. + * + * @param metrics Lista de métricas + * @return ReportItemI con el valor del indicador + * @throws NotAvailableMetricException si faltan métricas necesarias + */ + public ReportItemI calcIndicator(List> metrics) throws NotAvailableMetricException { + Double mriValue = null; + Double trpiValue = null; + Double iapcValue = null; + + for (ReportItemI item : metrics) { + switch (item.getName()) { + case MRI: + mriValue = item.getValue(); + break; + case TRPI: + trpiValue = item.getValue(); + break; + case IAPC: + iapcValue = item.getValue(); + break; + } + } + + if (mriValue == null || trpiValue == null || iapcValue == null) { + throw new NotAvailableMetricException("Faltan métricas requeridas para calcular el indicador."); + } + + // Normalización del valor MRI + double percMRI; + if (mriValue <= 0.3) { + percMRI = 0.0; + } else if (mriValue >= 2.0) { + percMRI = 100.0; + } else { + percMRI = (mriValue - 0.3) / 1.7 * 100.0; + } + + // Cálculo de la calidad + double quality = 0.3 * percMRI + 0.4 * trpiValue + 0.3 * (100.0 - iapcValue); + + + try { + return new ReportItem.ReportItemBuilder<>(RESULT_NAME, quality) + .source("calculado") + .unit("porcentaje") + .build(); + } catch (ReportItemException e) { + throw new RuntimeException("Error al construir ReportItem: " + e.getMessage(), e); + } + } + + /** + * Devuelve la lista de métricas requeridas por este indicador. + * + * @return lista de nombres de métricas requeridas + */ + public List requiredMetrics() { + return Arrays.asList(MRI, TRPI, IAPC); + } } diff --git a/src/main/resources/a4iDefault.json b/src/main/resources/a4iDefault.json index 33cee922..5e7da0fb 100644 --- a/src/main/resources/a4iDefault.json +++ b/src/main/resources/a4iDefault.json @@ -233,7 +233,26 @@ "type": "java.lang.Integer", "description": "Balance de equipos y open issues", "unit": "ratio" - } + }, + { + "name": "reopenedIssuesAvg", + "type": "java.lang.Double", + "description": "Media de issues reabiertos en el ultimo sprint", + "unit": "issues/sprint" + }, + { + "name": "reopenedIssuesResolutionRate", + "type": "java.lang.Double", + "description": "Porcentaje de issues que se resuelven en el primer intento sin necesidad de ser reabiertos", + "unit": "ratio" + }, + { + "name": "postClosureActivityRate", + "type": "java.lang.Double", + "description": "Porcentaje de issues cerrados que reciben comentarios o actividades adicionales", + "unit": "ratio" + } + ], "indicators": [ { diff --git a/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java b/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java index 1e17d7e8..711a00de 100644 --- a/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java +++ b/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java @@ -62,7 +62,8 @@ public void testCalcIndicator() throws NotAvailableMetricException { // %TRPI = 80.0 // %IAPC = 20.0 -> 100 - 20 = 80.0 // Calidad = 0.3 * 11.76 + 0.4 * 80 + 0.3 * 80 = 71.76 - + + Assertions.assertEquals("calidadResolucion", result.getName()); Assertions.assertEquals(71.76, result.getValue(), 0.5); // Con margen de error para la comparación Assertions.assertDoesNotThrow(() -> indicator.calcIndicator(metrics)); @@ -121,7 +122,9 @@ public void testCalcIndicatorWithExtremeValues() throws NotAvailableMetricExcept ReportItemI result = indicator.calcIndicator(metrics); // Aquí el resultado será alto (cerca de 100) - Assertions.assertTrue(result.getValue() > 90.0); + //Assertions.assertTrue(result.getValue() > 90.0); + //Assertions.assertEquals(70.0, result.getValue(), 0.5); + Assertions.assertEquals(60, Math.round(result.getValue())); } } \ No newline at end of file From bb62892ce9565222d9fa6ab7acc3e3ddaf124d9b Mon Sep 17 00:00:00 2001 From: pabcabrod1 Date: Wed, 14 May 2025 13:08:03 +0200 Subject: [PATCH 08/12] =?UTF-8?q?Creaci=C3=B3n=20clase=20IndicatorStrategy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/pruebas.yml | 40 ++++++++++++++----- .../fs/a4i/control/IndicatorStrategy.java | 6 +-- src/main/resources/a4iDefault.json | 16 +++++++- .../test/control/IndicatorStrategyTest.java | 19 +++------ 4 files changed, 53 insertions(+), 28 deletions(-) diff --git a/.github/workflows/pruebas.yml b/.github/workflows/pruebas.yml index 2db842e3..414511c7 100644 --- a/.github/workflows/pruebas.yml +++ b/.github/workflows/pruebas.yml @@ -1,4 +1,5 @@ -name: Flujo de trabajo para ejecutar los test +name: Flujo de trabajo para construcción y test por separado + on: workflow_dispatch: push: @@ -7,22 +8,39 @@ on: branches: [ V.0.2 ] schedule: - cron: '1 23 * * 0-4' + jobs: - Build: + build: runs-on: ubuntu-latest - env: - GITHUB_LOGIN: ${{ github.actor }} - GITHUB_PACKAGES: ${{ secrets.GHTOKEN }} - GITHUB_OAUTH: ${{ secrets.GHTOKEN }} steps: - - name: Clonando el repositorio y estableciendo el espacio de trabajo + - name: Clonando el repositorio uses: actions/checkout@v3 - - name: Configurando java + + - name: Configurando Java uses: actions/setup-java@v3 with: distribution: 'temurin' java-version: '16' - - name: Construyendo y probando el código + + - name: Compilando el proyecto run: | - chmod +x gradlew - ./gradlew build + chmod +x gradlew + ./gradlew classes + + test: + runs-on: ubuntu-latest + needs: build + steps: + - name: Clonando el repositorio + uses: actions/checkout@v3 + + - name: Configurando Java + uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: '16' + + - name: Ejecutando pruebas + run: | + chmod +x gradlew + ./gradlew test diff --git a/src/main/java/us/muit/fs/a4i/control/IndicatorStrategy.java b/src/main/java/us/muit/fs/a4i/control/IndicatorStrategy.java index 46bac35a..2b092216 100644 --- a/src/main/java/us/muit/fs/a4i/control/IndicatorStrategy.java +++ b/src/main/java/us/muit/fs/a4i/control/IndicatorStrategy.java @@ -59,13 +59,13 @@ public ReportItemI calcIndicator(List> metrics) thro } // Cálculo de la calidad - double quality = 0.3 * percMRI + 0.4 * trpiValue + 0.3 * (100.0 - iapcValue); + double quality = 0.3 * (100-percMRI) + 0.4 * trpiValue + 0.3 * (100.0 - iapcValue); try { return new ReportItem.ReportItemBuilder<>(RESULT_NAME, quality) - .source("calculado") - .unit("porcentaje") + .source("auto") + .unit("%") .build(); } catch (ReportItemException e) { throw new RuntimeException("Error al construir ReportItem: " + e.getMessage(), e); diff --git a/src/main/resources/a4iDefault.json b/src/main/resources/a4iDefault.json index 5e7da0fb..405576a2 100644 --- a/src/main/resources/a4iDefault.json +++ b/src/main/resources/a4iDefault.json @@ -329,6 +329,20 @@ "type": "java.lang.Double", "description": "Tiempo para arreglos", "unit": "ratio" + }, + { + "name": "calidadResolucion", + "type": "java.lang.Double", + "description": "Indicador que mide la calidad en la resolución de issues considerando su reapertura, resolución inicial y actividad posterior al cierre.", + "unit": "%", + "limits": { + "ok": 90, + "warning": 65, + "critical": 30 + } + } - ] + + ] + } \ No newline at end of file diff --git a/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java b/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java index 711a00de..5b3d72ef 100644 --- a/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java +++ b/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java @@ -55,17 +55,10 @@ public void testCalcIndicator() throws NotAvailableMetricException { List> metrics = Arrays.asList(mockMRI, mockTRPI, mockIAPC); ReportItemI result = indicator.calcIndicator(metrics); - // Comprobamos que el resultado es el esperado - // Cálculo esperado: - // Calidad = 0.3 * %MRI + 0.4 * %TRPI + 0.3 * (100 - %IAPC) - // %MRI = (0.5 - 0.3) / 1.7 * 100 = 11.76 - // %TRPI = 80.0 - // %IAPC = 20.0 -> 100 - 20 = 80.0 - // Calidad = 0.3 * 11.76 + 0.4 * 80 + 0.3 * 80 = 71.76 - - + + // Calidad esperada para los valores del Mock Assertions.assertEquals("calidadResolucion", result.getName()); - Assertions.assertEquals(71.76, result.getValue(), 0.5); // Con margen de error para la comparación + Assertions.assertEquals(82.47058823529412, result.getValue(), 0.5); // Con margen de error para la comparación Assertions.assertDoesNotThrow(() -> indicator.calcIndicator(metrics)); } @@ -122,9 +115,9 @@ public void testCalcIndicatorWithExtremeValues() throws NotAvailableMetricExcept ReportItemI result = indicator.calcIndicator(metrics); // Aquí el resultado será alto (cerca de 100) - //Assertions.assertTrue(result.getValue() > 90.0); - //Assertions.assertEquals(70.0, result.getValue(), 0.5); - Assertions.assertEquals(60, Math.round(result.getValue())); + Assertions.assertTrue(result.getValue() > 90.0); + + } } \ No newline at end of file From 47e8124f100df41f9a59a4904322c03ca8f913ff Mon Sep 17 00:00:00 2001 From: pabcabrod1 Date: Wed, 14 May 2025 13:24:39 +0200 Subject: [PATCH 09/12] =?UTF-8?q?Actualizaci=C3=B3n=20del=20build.gradle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index d2cdebcf..ae91eda0 100644 --- a/build.gradle +++ b/build.gradle @@ -23,11 +23,10 @@ plugins { //Para publicar paquetes en github publishing { - repositories { maven { name = "GitHubPackages" - url = uri("https://maven.pkg.github.com/pabcabrod1/Audit4Improve-API") + url = uri("https://maven.pkg.github.com/mit-fs/audit4improve-api") credentials { //las propiedades gpr.user y gpr.key están configuradas en gradle.properties en el raiz del proyecto, y se añade a .gitignore para que no se suban //O bien configuro las variables de entorno GITHUB_LOGIN y GITHUB_PACKAGES @@ -42,14 +41,14 @@ publishing { groupId = 'us.mitfs.samples' artifactId = 'a4i' - version = '0.2-pabcabrod1' + version = '0.2' from components.java } } } -version = '0.2-pabcabrod1' +version = '0.2' //group = 'us.mitfs.samples' tasks.withType(JavaCompile) { //Añadir la opción Xlint @@ -143,3 +142,4 @@ test { + From 0d921f2870045b1af9912e7de2e860f12c8f50fe Mon Sep 17 00:00:00 2001 From: pabcabrod1 Date: Wed, 14 May 2025 13:25:38 +0200 Subject: [PATCH 10/12] Update pruebas.yml --- .github/workflows/pruebas.yml | 40 ++++++++++------------------------- 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/.github/workflows/pruebas.yml b/.github/workflows/pruebas.yml index 414511c7..2db842e3 100644 --- a/.github/workflows/pruebas.yml +++ b/.github/workflows/pruebas.yml @@ -1,5 +1,4 @@ -name: Flujo de trabajo para construcción y test por separado - +name: Flujo de trabajo para ejecutar los test on: workflow_dispatch: push: @@ -8,39 +7,22 @@ on: branches: [ V.0.2 ] schedule: - cron: '1 23 * * 0-4' - jobs: - build: + Build: runs-on: ubuntu-latest + env: + GITHUB_LOGIN: ${{ github.actor }} + GITHUB_PACKAGES: ${{ secrets.GHTOKEN }} + GITHUB_OAUTH: ${{ secrets.GHTOKEN }} steps: - - name: Clonando el repositorio + - name: Clonando el repositorio y estableciendo el espacio de trabajo uses: actions/checkout@v3 - - - name: Configurando Java + - name: Configurando java uses: actions/setup-java@v3 with: distribution: 'temurin' java-version: '16' - - - name: Compilando el proyecto + - name: Construyendo y probando el código run: | - chmod +x gradlew - ./gradlew classes - - test: - runs-on: ubuntu-latest - needs: build - steps: - - name: Clonando el repositorio - uses: actions/checkout@v3 - - - name: Configurando Java - uses: actions/setup-java@v3 - with: - distribution: 'temurin' - java-version: '16' - - - name: Ejecutando pruebas - run: | - chmod +x gradlew - ./gradlew test + chmod +x gradlew + ./gradlew build From c3943ad30f73c64fe09a55d4b954cbd62e6aee71 Mon Sep 17 00:00:00 2001 From: braburgut Date: Wed, 14 May 2025 13:52:49 +0200 Subject: [PATCH 11/12] Arreglos finales Arreglos finales 2 Arreglos en test RemoteEnquirer Arreglos en test RemoteEnquirer 2 Arreglos en test RemoteEnquirer 3 Arreglos en test RemoteEnquirer 4 --- .../a4i/control/IndicatorCalidadIssues.java | 83 ++++++++++++++ .../fs/a4i/control/IndicatorStrategy.java | 102 +++++------------- .../model/remote/GitHubRemoteEnquirer.java | 9 +- .../test/control/IndicatorStrategyTest.java | 9 +- 4 files changed, 124 insertions(+), 79 deletions(-) create mode 100644 src/main/java/us/muit/fs/a4i/control/IndicatorCalidadIssues.java diff --git a/src/main/java/us/muit/fs/a4i/control/IndicatorCalidadIssues.java b/src/main/java/us/muit/fs/a4i/control/IndicatorCalidadIssues.java new file mode 100644 index 00000000..cc4e5048 --- /dev/null +++ b/src/main/java/us/muit/fs/a4i/control/IndicatorCalidadIssues.java @@ -0,0 +1,83 @@ +package us.muit.fs.a4i.control; + +import java.util.List; +import java.util.Arrays; + +import us.muit.fs.a4i.exceptions.NotAvailableMetricException; +import us.muit.fs.a4i.exceptions.ReportItemException; +import us.muit.fs.a4i.model.entities.ReportItem; +import us.muit.fs.a4i.model.entities.ReportItemI; + +/** + * Estrategia para calcular el indicador de calidad de resolución. + */ +public class IndicatorCalidadIssues { + + private static final String MRI = "reopenedIssuesAvg"; + private static final String TRPI = "firstTryResolutionRate"; + private static final String IAPC = "postClosureActivityRate"; + private static final String RESULT_NAME = "calidadResolucion"; + + /** + * Calcula el indicador a partir de una lista de métricas. + * + * @param metrics Lista de métricas + * @return ReportItemI con el valor del indicador + * @throws NotAvailableMetricException si faltan métricas necesarias + */ + public ReportItemI calcIndicator(List> metrics) throws NotAvailableMetricException { + Double mriValue = null; + Double trpiValue = null; + Double iapcValue = null; + + for (ReportItemI item : metrics) { + switch (item.getName()) { + case MRI: + mriValue = item.getValue(); + break; + case TRPI: + trpiValue = item.getValue(); + break; + case IAPC: + iapcValue = item.getValue(); + break; + } + } + + if (mriValue == null || trpiValue == null || iapcValue == null) { + throw new NotAvailableMetricException("Faltan métricas requeridas para calcular el indicador."); + } + + // Normalización del valor MRI + double percMRI; + if (mriValue <= 0.3) { + percMRI = 0.0; + } else if (mriValue >= 2.0) { + percMRI = 100.0; + } else { + percMRI = (mriValue - 0.3) / 1.7 * 100.0; + } + + // Cálculo de la calidad + double quality = 0.3 * (100-percMRI) + 0.4 * trpiValue + 0.3 * (100.0 - iapcValue); + + + try { + return new ReportItem.ReportItemBuilder<>(RESULT_NAME, quality) + .source("auto") + .unit("%") + .build(); + } catch (ReportItemException e) { + throw new RuntimeException("Error al construir ReportItem: " + e.getMessage(), e); + } + } + + /** + * Devuelve la lista de métricas requeridas por este indicador. + * + * @return lista de nombres de métricas requeridas + */ + public List requiredMetrics() { + return Arrays.asList(MRI, TRPI, IAPC); + } +} diff --git a/src/main/java/us/muit/fs/a4i/control/IndicatorStrategy.java b/src/main/java/us/muit/fs/a4i/control/IndicatorStrategy.java index 2b092216..a9b80b31 100644 --- a/src/main/java/us/muit/fs/a4i/control/IndicatorStrategy.java +++ b/src/main/java/us/muit/fs/a4i/control/IndicatorStrategy.java @@ -1,83 +1,37 @@ package us.muit.fs.a4i.control; import java.util.List; -import java.util.Arrays; import us.muit.fs.a4i.exceptions.NotAvailableMetricException; -import us.muit.fs.a4i.exceptions.ReportItemException; -import us.muit.fs.a4i.model.entities.ReportItem; import us.muit.fs.a4i.model.entities.ReportItemI; /** - * Estrategia para calcular el indicador de calidad de resolución. + * /** + *

+ * Interfaz para calcular indicadores + *

+ * + * @param + * @author celllarod + * */ -public class IndicatorStrategy { - - private static final String MRI = "reopenedIssuesAvg"; - private static final String TRPI = "firstTryResolutionRate"; - private static final String IAPC = "postClosureActivityRate"; - private static final String RESULT_NAME = "calidadResolucion"; - - /** - * Calcula el indicador a partir de una lista de métricas. - * - * @param metrics Lista de métricas - * @return ReportItemI con el valor del indicador - * @throws NotAvailableMetricException si faltan métricas necesarias - */ - public ReportItemI calcIndicator(List> metrics) throws NotAvailableMetricException { - Double mriValue = null; - Double trpiValue = null; - Double iapcValue = null; - - for (ReportItemI item : metrics) { - switch (item.getName()) { - case MRI: - mriValue = item.getValue(); - break; - case TRPI: - trpiValue = item.getValue(); - break; - case IAPC: - iapcValue = item.getValue(); - break; - } - } - - if (mriValue == null || trpiValue == null || iapcValue == null) { - throw new NotAvailableMetricException("Faltan métricas requeridas para calcular el indicador."); - } - - // Normalización del valor MRI - double percMRI; - if (mriValue <= 0.3) { - percMRI = 0.0; - } else if (mriValue >= 2.0) { - percMRI = 100.0; - } else { - percMRI = (mriValue - 0.3) / 1.7 * 100.0; - } - - // Cálculo de la calidad - double quality = 0.3 * (100-percMRI) + 0.4 * trpiValue + 0.3 * (100.0 - iapcValue); - - - try { - return new ReportItem.ReportItemBuilder<>(RESULT_NAME, quality) - .source("auto") - .unit("%") - .build(); - } catch (ReportItemException e) { - throw new RuntimeException("Error al construir ReportItem: " + e.getMessage(), e); - } - } - - /** - * Devuelve la lista de métricas requeridas por este indicador. - * - * @return lista de nombres de métricas requeridas - */ - public List requiredMetrics() { - return Arrays.asList(MRI, TRPI, IAPC); - } -} +public interface IndicatorStrategy { + + /** + * Calcula un indicador a partir de las métricas proporcionadas. + * + * @param + * @param metrics + * @throws NotAvailableMetricException + * @return indicador + */ + public ReportItemI calcIndicator(List> metrics) throws NotAvailableMetricException; + + /** + * Obtiene las métricas necesarias + * + * @return listado de métricas + */ + public List requiredMetrics(); + +} \ No newline at end of file diff --git a/src/main/java/us/muit/fs/a4i/model/remote/GitHubRemoteEnquirer.java b/src/main/java/us/muit/fs/a4i/model/remote/GitHubRemoteEnquirer.java index 17b1e38b..d87b90c8 100644 --- a/src/main/java/us/muit/fs/a4i/model/remote/GitHubRemoteEnquirer.java +++ b/src/main/java/us/muit/fs/a4i/model/remote/GitHubRemoteEnquirer.java @@ -27,7 +27,14 @@ public class GitHubRemoteEnquirer implements RemoteEnquirer { public GitHubRemoteEnquirer() throws IOException { String token = System.getenv("GITHUB_OAUTH"); - this.github = new GitHubBuilder().withOAuthToken(token).build(); + if (token == null || token.isEmpty()) { + token = System.getenv("GITHUB_TOKEN"); + } + if (token == null || token.isEmpty()) { + throw new IllegalStateException("No GitHub token provided."); + } + this.github = new GitHubBuilder().withOAuthToken(token).build(); + } @Override diff --git a/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java b/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java index a8318cb7..6ee902b7 100644 --- a/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java +++ b/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java @@ -19,6 +19,7 @@ import org.junit.jupiter.api.Test; import org.mockito.Mockito; +import us.muit.fs.a4i.control.IndicatorCalidadIssues; import us.muit.fs.a4i.control.IndicatorStrategy; import us.muit.fs.a4i.exceptions.NotAvailableMetricException; import us.muit.fs.a4i.model.entities.ReportItemI; @@ -49,7 +50,7 @@ public void testCalcIndicator() throws NotAvailableMetricException { Mockito.when(mockIAPC.getValue()).thenReturn(20.0); // Issues con Actividad Posterior al Cierre // Creamos una instancia de IndicatorStrategy - IndicatorStrategy indicator = new CalidadStrategy(); + IndicatorCalidadIssues indicator = new IndicatorCalidadIssues(); // Ejecutamos el método que queremos probar con los mocks como argumentos List> metrics = Arrays.asList(mockMRI, mockTRPI, mockIAPC); @@ -71,7 +72,7 @@ public void testCalcIndicatorThrowsNotAvailableMetricException() { Mockito.when(mockMRI.getValue()).thenReturn(0.5); // Creamos una instancia de IndicatorStrategy - IndicatorStrategy indicator = new CalidadStrategy(); + IndicatorCalidadIssues indicator = new IndicatorCalidadIssues(); // Ejecutamos el método que queremos probar con métricas insuficientes List> metrics = Arrays.asList(mockMRI); @@ -84,7 +85,7 @@ public void testCalcIndicatorThrowsNotAvailableMetricException() { @Test public void testRequiredMetrics() { // Creamos una instancia de IndicatorStrategy - IndicatorStrategy indicatorStrategy = new CalidadStrategy(); + IndicatorCalidadIssues indicatorStrategy = new IndicatorCalidadIssues(); // Ejecutamos el método que queremos probar List requiredMetrics = indicatorStrategy.requiredMetrics(); @@ -109,7 +110,7 @@ public void testCalcIndicatorWithExtremeValues() throws NotAvailableMetricExcept Mockito.when(iapc.getName()).thenReturn("postClosureActivityRate"); Mockito.when(iapc.getValue()).thenReturn(0.0); - IndicatorStrategy indicator = new CalidadStrategy(); + IndicatorCalidadIssues indicator = new IndicatorCalidadIssues(); List> metrics = Arrays.asList(mri, trpi, iapc); ReportItemI result = indicator.calcIndicator(metrics); From 89d930de82ef48178d1003f783dc59813c88ece5 Mon Sep 17 00:00:00 2001 From: braburgut <125819117+braburgut@users.noreply.github.com> Date: Wed, 14 May 2025 17:22:12 +0200 Subject: [PATCH 12/12] Update pruebas.yml --- .github/workflows/pruebas.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pruebas.yml b/.github/workflows/pruebas.yml index 2db842e3..f7ae993e 100644 --- a/.github/workflows/pruebas.yml +++ b/.github/workflows/pruebas.yml @@ -12,8 +12,8 @@ jobs: runs-on: ubuntu-latest env: GITHUB_LOGIN: ${{ github.actor }} - GITHUB_PACKAGES: ${{ secrets.GHTOKEN }} - GITHUB_OAUTH: ${{ secrets.GHTOKEN }} + GITHUB_PACKAGES: ${{ secrets.GITHUB_TOKEN }} + GITHUB_OAUTH: ${{ secrets.GITHUB_TOKEN }} steps: - name: Clonando el repositorio y estableciendo el espacio de trabajo uses: actions/checkout@v3