From 14c2327962fc57ffc7709889223932a63c05c362 Mon Sep 17 00:00:00 2001 From: Prudhvi Godithi Date: Tue, 20 Aug 2024 12:11:18 -0700 Subject: [PATCH] Update release metrics fields Signed-off-by: Prudhvi Godithi --- .../dagger/MetricsModule.java | 5 +- .../metrics/MetricsCalculation.java | 3 + .../metrics/release/ReleaseIssueChecker.java | 61 ++++++++++++++ .../metrics/release/ReleaseMetrics.java | 22 +++--- .../model/release/ReleaseMetricsData.java | 13 +++ .../release/ReleaseIssueCheckerTest.java | 79 +++++++++++++++++++ .../metrics/release/ReleaseMetricsTest.java | 23 ++++++ .../model/release/ReleaseMetricsDataTest.java | 32 ++++++++ 8 files changed, 225 insertions(+), 13 deletions(-) create mode 100644 src/main/java/org/opensearchmetrics/metrics/release/ReleaseIssueChecker.java create mode 100644 src/test/java/org/opensearchmetrics/metrics/release/ReleaseIssueCheckerTest.java diff --git a/src/main/java/org/opensearchmetrics/dagger/MetricsModule.java b/src/main/java/org/opensearchmetrics/dagger/MetricsModule.java index 80a87d7..4078cc6 100644 --- a/src/main/java/org/opensearchmetrics/dagger/MetricsModule.java +++ b/src/main/java/org/opensearchmetrics/dagger/MetricsModule.java @@ -6,6 +6,7 @@ import org.opensearchmetrics.metrics.general.*; import org.opensearchmetrics.metrics.label.LabelMetrics; import org.opensearchmetrics.metrics.release.ReleaseBranchChecker; +import org.opensearchmetrics.metrics.release.ReleaseIssueChecker; import org.opensearchmetrics.metrics.release.ReleaseLabelIssuesFetcher; import org.opensearchmetrics.metrics.release.ReleaseLabelPullsFetcher; import org.opensearchmetrics.metrics.release.ReleaseMetrics; @@ -143,7 +144,7 @@ public LabelMetrics getLabelMetrics() { public ReleaseMetrics getReleaseMetrics(OpenSearchUtil openSearchUtil, ObjectMapper objectMapper, ReleaseRepoFetcher releaseRepoFetcher, ReleaseLabelIssuesFetcher releaseLabelIssuesFetcher, ReleaseLabelPullsFetcher releaseLabelPullsFetcher, ReleaseVersionIncrementChecker releaseVersionIncrementChecker, - ReleaseBranchChecker releaseBranchChecker, ReleaseNotesChecker releaseNotesChecker) { - return new ReleaseMetrics(openSearchUtil, objectMapper, releaseRepoFetcher, releaseLabelIssuesFetcher, releaseLabelPullsFetcher, releaseVersionIncrementChecker, releaseBranchChecker, releaseNotesChecker); + ReleaseBranchChecker releaseBranchChecker, ReleaseNotesChecker releaseNotesChecker, ReleaseIssueChecker releaseIssueChecker) { + return new ReleaseMetrics(openSearchUtil, objectMapper, releaseRepoFetcher, releaseLabelIssuesFetcher, releaseLabelPullsFetcher, releaseVersionIncrementChecker, releaseBranchChecker, releaseNotesChecker, releaseIssueChecker); } } diff --git a/src/main/java/org/opensearchmetrics/metrics/MetricsCalculation.java b/src/main/java/org/opensearchmetrics/metrics/MetricsCalculation.java index 65faa07..5e8dc04 100644 --- a/src/main/java/org/opensearchmetrics/metrics/MetricsCalculation.java +++ b/src/main/java/org/opensearchmetrics/metrics/MetricsCalculation.java @@ -166,6 +166,7 @@ public void generateReleaseMetrics() { throw new RuntimeException(e); } releaseMetricsData.setReleaseVersion(releaseInput.getVersion()); + releaseMetricsData.setVersion(releaseInput.getVersion()); releaseMetricsData.setReleaseState(releaseInput.getState()); releaseMetricsData.setIssuesOpen(releaseMetrics.getReleaseLabelIssues(releaseInput.getVersion(), repo, "open", false)); releaseMetricsData.setAutocutIssuesOpen(releaseMetrics.getReleaseLabelIssues(releaseInput.getVersion(), repo, "open", true)); @@ -175,6 +176,8 @@ public void generateReleaseMetrics() { releaseMetricsData.setVersionIncrement(releaseMetrics.getReleaseVersionIncrement(releaseInput.getVersion(), repo, releaseInput.getBranch())); releaseMetricsData.setReleaseNotes(releaseMetrics.getReleaseNotes(releaseInput.getVersion(), repo, releaseInput.getBranch())); releaseMetricsData.setReleaseBranch(releaseMetrics.getReleaseBranch(releaseInput.getVersion(), repo)); + releaseMetricsData.setReleaseOwners(releaseMetrics.getReleaseOwners(releaseInput.getVersion(), repo)); + releaseMetricsData.setReleaseIssue(releaseMetrics.getReleaseIssue(releaseInput.getVersion(), repo)); return Stream.of(releaseMetricsData); })) .collect(Collectors.toMap(ReleaseMetricsData::getId, diff --git a/src/main/java/org/opensearchmetrics/metrics/release/ReleaseIssueChecker.java b/src/main/java/org/opensearchmetrics/metrics/release/ReleaseIssueChecker.java new file mode 100644 index 0000000..6025969 --- /dev/null +++ b/src/main/java/org/opensearchmetrics/metrics/release/ReleaseIssueChecker.java @@ -0,0 +1,61 @@ +package org.opensearchmetrics.metrics.release; + +import org.opensearch.action.search.SearchRequest; +import org.opensearch.action.search.SearchResponse; +import org.opensearch.index.query.BoolQueryBuilder; +import org.opensearch.index.query.QueryBuilders; +import org.opensearch.search.SearchHit; +import org.opensearch.search.aggregations.AggregationBuilders; +import org.opensearch.search.aggregations.bucket.terms.Terms; +import org.opensearch.search.builder.SearchSourceBuilder; +import org.opensearchmetrics.util.OpenSearchUtil; + +import javax.inject.Inject; +import java.util.Arrays; + +public class ReleaseIssueChecker { + + @Inject + public ReleaseIssueChecker() {} + + public String[] releaseOwners(String releaseVersion, String repo, OpenSearchUtil openSearchUtil) { + BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); + boolQueryBuilder.must(QueryBuilders.matchQuery("repository.keyword", repo)); + boolQueryBuilder.must(QueryBuilders.matchQuery("title.keyword", "[RELEASE] Release version " + releaseVersion)); + boolQueryBuilder.must(QueryBuilders.matchQuery("issue_pull_request", false)); + SearchRequest searchRequest = new SearchRequest("github_issues"); + SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); + searchSourceBuilder.query(boolQueryBuilder); + searchSourceBuilder.size(9000); + searchSourceBuilder.aggregation( + AggregationBuilders.terms("issue_assignees") + .field("issue_assignees.keyword") + .size(50) + ); + searchRequest.source(searchSourceBuilder); + SearchResponse searchResponse = openSearchUtil.search(searchRequest); + Terms termsAgg = searchResponse.getAggregations().get("issue_assignees"); + return termsAgg.getBuckets().stream() + .map(Terms.Bucket::getKeyAsString) + .toArray(String[]::new); + } + + public String releaseIssue(String releaseVersion, String repo, OpenSearchUtil openSearchUtil) { + BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); + boolQueryBuilder.must(QueryBuilders.matchQuery("repository.keyword", repo)); + boolQueryBuilder.must(QueryBuilders.matchQuery("title.keyword", "[RELEASE] Release version " + releaseVersion)); + boolQueryBuilder.must(QueryBuilders.matchQuery("issue_pull_request", false)); + SearchRequest searchRequest = new SearchRequest("github_issues"); + SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); + searchSourceBuilder.query(boolQueryBuilder); + searchSourceBuilder.size(9000); + searchRequest.source(searchSourceBuilder); + SearchResponse searchResponse = openSearchUtil.search(searchRequest); + SearchHit[] hits = searchResponse.getHits().getHits(); + return Arrays.stream(hits) + .findFirst() + .map(hit -> (String) hit.getSourceAsMap().get("html_url")) + .orElse(null); + } + +} diff --git a/src/main/java/org/opensearchmetrics/metrics/release/ReleaseMetrics.java b/src/main/java/org/opensearchmetrics/metrics/release/ReleaseMetrics.java index 9208824..52ea0f2 100644 --- a/src/main/java/org/opensearchmetrics/metrics/release/ReleaseMetrics.java +++ b/src/main/java/org/opensearchmetrics/metrics/release/ReleaseMetrics.java @@ -21,12 +21,13 @@ public class ReleaseMetrics { private final ReleaseNotesChecker releaseNotesChecker; + private final ReleaseIssueChecker releaseIssueChecker; @Inject public ReleaseMetrics(OpenSearchUtil openSearchUtil, ObjectMapper objectMapper, ReleaseRepoFetcher releaseRepoFetcher, ReleaseLabelIssuesFetcher releaseLabelIssuesFetcher, ReleaseLabelPullsFetcher releaseLabelPullsFetcher, ReleaseVersionIncrementChecker releaseVersionIncrementChecker, ReleaseBranchChecker releaseBranchChecker, - ReleaseNotesChecker releaseNotesChecker) { + ReleaseNotesChecker releaseNotesChecker, ReleaseIssueChecker releaseIssueChecker) { this.openSearchUtil = openSearchUtil; this.objectMapper = objectMapper; this.releaseRepoFetcher = releaseRepoFetcher; @@ -35,41 +36,40 @@ public ReleaseMetrics(OpenSearchUtil openSearchUtil, ObjectMapper objectMapper, this.releaseVersionIncrementChecker = releaseVersionIncrementChecker; this.releaseBranchChecker = releaseBranchChecker; this.releaseNotesChecker = releaseNotesChecker; + this.releaseIssueChecker = releaseIssueChecker; } - public List getReleaseRepos(String releaseVersion) { return releaseRepoFetcher.getReleaseRepos(releaseVersion); } - public Long getReleaseLabelIssues(String releaseVersion, String repo, String issueState, boolean autoCut) { return releaseLabelIssuesFetcher.releaseLabelIssues(releaseVersion, repo, issueState, autoCut, openSearchUtil); } - - public Long getReleaseLabelPulls(String releaseVersion, String repo, String pullState) { return releaseLabelPullsFetcher.releaseLabelPulls(releaseVersion, repo, pullState, openSearchUtil); } - - - public boolean getReleaseVersionIncrement (String releaseVersion, String repo, String branch) { return releaseVersionIncrementChecker.releaseVersionIncrement(releaseVersion, repo, branch, objectMapper, openSearchUtil); } - public Boolean getReleaseNotes (String releaseVersion, String repo, String releaseBranch) { return releaseNotesChecker.releaseNotes(releaseVersion, repo, releaseBranch); } - - public Boolean getReleaseBranch (String releaseVersion, String repo) { return releaseBranchChecker.releaseBranch(releaseVersion, repo); } + public String[] getReleaseOwners (String releaseVersion, String repo) { + return releaseIssueChecker.releaseOwners(releaseVersion, repo, openSearchUtil); + } + + public String getReleaseIssue (String releaseVersion, String repo) { + return releaseIssueChecker.releaseIssue(releaseVersion, repo, openSearchUtil); + } + } diff --git a/src/main/java/org/opensearchmetrics/model/release/ReleaseMetricsData.java b/src/main/java/org/opensearchmetrics/model/release/ReleaseMetricsData.java index 0ad1791..d57b8af 100644 --- a/src/main/java/org/opensearchmetrics/model/release/ReleaseMetricsData.java +++ b/src/main/java/org/opensearchmetrics/model/release/ReleaseMetricsData.java @@ -6,6 +6,7 @@ import lombok.Data; import java.util.HashMap; +import java.util.List; import java.util.Map; @Data @@ -23,6 +24,9 @@ public class ReleaseMetricsData { @JsonProperty("release_version") private String releaseVersion; + @JsonProperty("version") + private String version; + @JsonProperty("release_state") private String releaseState; @@ -49,12 +53,19 @@ public class ReleaseMetricsData { @JsonProperty("release_branch") private boolean releaseBranch; + @JsonProperty("release_owners") + private String[] releaseOwners; + + @JsonProperty("release_issue") + private String releaseIssue; + public String toJson(ObjectMapper mapper) throws JsonProcessingException { Map data = new HashMap<>(); data.put("id", id); data.put("current_date", currentDate); data.put("repository", repository); data.put("release_version", releaseVersion); + data.put("version", version); data.put("release_state", releaseState); data.put("issues_open", issuesOpen); data.put("autocut_issues_open", autocutIssuesOpen); @@ -64,6 +75,8 @@ public String toJson(ObjectMapper mapper) throws JsonProcessingException { data.put("version_increment", versionIncrement); data.put("release_notes", releaseNotes); data.put("release_branch", releaseBranch); + data.put("release_owners", releaseOwners); + data.put("release_issue", releaseIssue); return mapper.writeValueAsString(data); } diff --git a/src/test/java/org/opensearchmetrics/metrics/release/ReleaseIssueCheckerTest.java b/src/test/java/org/opensearchmetrics/metrics/release/ReleaseIssueCheckerTest.java new file mode 100644 index 0000000..c3547dd --- /dev/null +++ b/src/test/java/org/opensearchmetrics/metrics/release/ReleaseIssueCheckerTest.java @@ -0,0 +1,79 @@ +package org.opensearchmetrics.metrics.release; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opensearch.action.search.SearchRequest; +import org.opensearch.action.search.SearchResponse; +import org.opensearch.core.rest.RestStatus; +import org.opensearch.search.SearchHit; +import org.opensearch.search.SearchHits; +import org.opensearch.search.aggregations.Aggregations; +import org.opensearch.search.aggregations.bucket.terms.Terms; +import org.opensearchmetrics.util.OpenSearchUtil; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class ReleaseIssueCheckerTest { + + @Mock + private OpenSearchUtil openSearchUtil; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + } + + @Test + void testReleaseOwners() { + Terms.Bucket bucket1 = mock(Terms.Bucket.class); + when(bucket1.getKeyAsString()).thenReturn("sample_user_1"); + Terms.Bucket bucket2 = mock(Terms.Bucket.class); + when(bucket2.getKeyAsString()).thenReturn("sample_user_2"); + Terms.Bucket bucket3 = mock(Terms.Bucket.class); + when(bucket3.getKeyAsString()).thenReturn("sample_user_3"); + Terms.Bucket bucket4 = mock(Terms.Bucket.class); + when(bucket4.getKeyAsString()).thenReturn("sample_user_4"); + List buckets = Arrays.asList(bucket1, bucket2, bucket3, bucket4); + Terms termsAgg = mock(Terms.class); + when(termsAgg.getBuckets()).thenAnswer(invocation -> buckets); + Aggregations aggregations = mock(Aggregations.class); + when(aggregations.get("issue_assignees")).thenReturn(termsAgg); + SearchResponse searchResponse = mock(SearchResponse.class); + when(searchResponse.status()).thenReturn(RestStatus.OK); + when(searchResponse.getAggregations()).thenReturn(aggregations); + OpenSearchUtil openSearchUtil = mock(OpenSearchUtil.class); + when(openSearchUtil.search(any(SearchRequest.class))).thenReturn(searchResponse); + ReleaseIssueChecker releaseIssueChecker = new ReleaseIssueChecker(); + String[] result = releaseIssueChecker.releaseOwners("2.16.0", "opensearch-build", openSearchUtil); + String[] expected = {"sample_user_1", "sample_user_2", "sample_user_3", "sample_user_4"}; + assertArrayEquals(expected, result); + } + + @Test + void testReleaseIssue() { + SearchHit hit1 = mock(SearchHit.class); + when(hit1.getSourceAsMap()).thenReturn(Map.of("html_url", "https://github.com/opensearch-project/opensearch-build/issues/4115")); + SearchHit hit2 = mock(SearchHit.class); + when(hit2.getSourceAsMap()).thenReturn(Map.of("html_url", "https://github.com/opensearch-project/opensearch-build/issues/4454")); + SearchHits searchHits = mock(SearchHits.class); + when(searchHits.getHits()).thenReturn(new SearchHit[]{hit1, hit2}); + SearchResponse searchResponse = mock(SearchResponse.class); + when(searchResponse.getHits()).thenReturn(searchHits); + when(searchResponse.status()).thenReturn(RestStatus.OK); + OpenSearchUtil openSearchUtil = mock(OpenSearchUtil.class); + when(openSearchUtil.search(any(SearchRequest.class))).thenReturn(searchResponse); + ReleaseIssueChecker releaseIssueChecker = new ReleaseIssueChecker(); + String result = releaseIssueChecker.releaseIssue("2.16.0", "opensearch-build", openSearchUtil); + assertEquals("https://github.com/opensearch-project/opensearch-build/issues/4115", result); + } +} diff --git a/src/test/java/org/opensearchmetrics/metrics/release/ReleaseMetricsTest.java b/src/test/java/org/opensearchmetrics/metrics/release/ReleaseMetricsTest.java index 9a6b83e..79af90d 100644 --- a/src/test/java/org/opensearchmetrics/metrics/release/ReleaseMetricsTest.java +++ b/src/test/java/org/opensearchmetrics/metrics/release/ReleaseMetricsTest.java @@ -41,6 +41,9 @@ public class ReleaseMetricsTest { private ReleaseNotesChecker releaseNotesChecker; + @Mock + private ReleaseIssueChecker releaseIssueChecker; + @Test public void testGetReleaseRepos() { MockitoAnnotations.openMocks(this); @@ -103,4 +106,24 @@ public void testGetReleaseBranch() { boolean result = releaseBranchChecker.releaseBranch("1.0.0", "testRepo"); assertEquals(expectedBranch, result); } + + @Test + public void testGetReleaseOwner() { + MockitoAnnotations.openMocks(this); + String[] releaseOwners = new String[]{"sample_user_1"}; + when(releaseIssueChecker.releaseOwners(anyString(), anyString(), any())) + .thenReturn(releaseOwners); + String[] result = releaseIssueChecker.releaseOwners("1.0.0", "testRepo", openSearchUtil); + assertEquals(releaseOwners, result); + } + + @Test + public void testGetReleaseIssue() { + MockitoAnnotations.openMocks(this); + String releaseIssue = "https://sample-release-issue/100"; + when(releaseIssueChecker.releaseIssue(anyString(), anyString(), any())) + .thenReturn(releaseIssue); + String result = releaseIssueChecker.releaseIssue("1.0.0", "testRepo", openSearchUtil); + assertEquals(releaseIssue, result); + } } diff --git a/src/test/java/org/opensearchmetrics/model/release/ReleaseMetricsDataTest.java b/src/test/java/org/opensearchmetrics/model/release/ReleaseMetricsDataTest.java index abaf41d..318c78b 100644 --- a/src/test/java/org/opensearchmetrics/model/release/ReleaseMetricsDataTest.java +++ b/src/test/java/org/opensearchmetrics/model/release/ReleaseMetricsDataTest.java @@ -21,6 +21,8 @@ public class ReleaseMetricsDataTest { private ReleaseMetricsData releaseMetricsData; + private static String[] SAMPLE_USERS = new String[]{"sample_user"}; + @BeforeEach void setUp() { MockitoAnnotations.openMocks(this); @@ -51,6 +53,12 @@ public void testReleaseVersion() { assertEquals("1.0", releaseMetricsData.getReleaseVersion()); } + @Test + public void testVersion() { + releaseMetricsData.setVersion("1.0"); + assertEquals("1.0", releaseMetricsData.getVersion()); + } + @Test public void testReleaseState() { releaseMetricsData.setReleaseState("planned"); @@ -104,6 +112,18 @@ public void testReleaseBranch() { releaseMetricsData.setReleaseBranch(true); assertEquals(true, releaseMetricsData.isReleaseBranch()); } + + @Test + public void testReleaseOwners() { + releaseMetricsData.setReleaseOwners(SAMPLE_USERS); + assertEquals(SAMPLE_USERS, releaseMetricsData.getReleaseOwners()); + } + + @Test + public void testReleaseIssue() { + releaseMetricsData.setReleaseIssue("https://sample-release-issue/100"); + assertEquals("https://sample-release-issue/100", releaseMetricsData.getReleaseIssue()); + } @Test void toJson() throws JsonProcessingException { // Arrange @@ -112,7 +132,10 @@ void toJson() throws JsonProcessingException { releaseMetricsData.setCurrentDate("2024-03-15"); releaseMetricsData.setRepository("test-repo"); releaseMetricsData.setReleaseVersion("1.0.0"); + releaseMetricsData.setVersion("1.0.0"); + releaseMetricsData.setReleaseIssue("https://sample-release-issue/100"); releaseMetricsData.setReleaseState("stable"); + releaseMetricsData.setReleaseOwners(SAMPLE_USERS); releaseMetricsData.setIssuesOpen(5L); releaseMetricsData.setAutocutIssuesOpen(2L); releaseMetricsData.setIssuesClosed(3L); @@ -127,6 +150,7 @@ void toJson() throws JsonProcessingException { expectedData.put("current_date", "2024-03-15"); expectedData.put("repository", "test-repo"); expectedData.put("release_version", "1.0.0"); + expectedData.put("version", "1.0.0"); expectedData.put("release_state", "stable"); expectedData.put("issues_open", 5L); expectedData.put("autocut_issues_open", 2L); @@ -136,6 +160,8 @@ void toJson() throws JsonProcessingException { expectedData.put("version_increment", true); expectedData.put("release_notes", true); expectedData.put("release_branch", false); + expectedData.put("release_owners", SAMPLE_USERS); + expectedData.put("release_issue","https://sample-release-issue/100"); when(objectMapper.writeValueAsString(expectedData)).thenReturn("expectedJson"); @@ -154,6 +180,7 @@ void getJson() throws JsonProcessingException { releaseMetricsData.setCurrentDate("2024-03-15"); releaseMetricsData.setRepository("test-repo"); releaseMetricsData.setReleaseVersion("1.0.0"); + releaseMetricsData.setVersion("1.0.0"); releaseMetricsData.setReleaseState("stable"); releaseMetricsData.setIssuesOpen(5L); releaseMetricsData.setAutocutIssuesOpen(2L); @@ -163,6 +190,8 @@ void getJson() throws JsonProcessingException { releaseMetricsData.setVersionIncrement(true); releaseMetricsData.setReleaseNotes(true); releaseMetricsData.setReleaseBranch(false); + releaseMetricsData.setReleaseOwners(SAMPLE_USERS); + releaseMetricsData.setReleaseIssue("https://sample-release-issue/100"); when(objectMapper.writeValueAsString(anyMap())).thenReturn("expectedJson"); @@ -181,6 +210,7 @@ void getJson_WithJsonProcessingException() throws JsonProcessingException { releaseMetricsData.setCurrentDate("2024-03-15"); releaseMetricsData.setRepository("test-repo"); releaseMetricsData.setReleaseVersion("1.0.0"); + releaseMetricsData.setVersion("1.0.0"); releaseMetricsData.setReleaseState("stable"); releaseMetricsData.setIssuesOpen(5L); releaseMetricsData.setAutocutIssuesOpen(2L); @@ -190,6 +220,8 @@ void getJson_WithJsonProcessingException() throws JsonProcessingException { releaseMetricsData.setVersionIncrement(true); releaseMetricsData.setReleaseNotes(true); releaseMetricsData.setReleaseBranch(false); + releaseMetricsData.setReleaseOwners(SAMPLE_USERS); + releaseMetricsData.setReleaseIssue("https://sample-release-issue/100"); when(objectMapper.writeValueAsString(anyMap())).thenThrow(JsonProcessingException.class);