Skip to content

Commit

Permalink
Issue 1415 user story points (#1418)
Browse files Browse the repository at this point in the history
Rename the 'ready user story points' to 'user story points' as it can not just be used to count ready user stories, but rather any selection of user stories. Closes #1415.
  • Loading branch information
fniessink authored Aug 30, 2020
1 parent 23c3b17 commit 31f5534
Show file tree
Hide file tree
Showing 12 changed files with 122 additions and 71 deletions.
4 changes: 2 additions & 2 deletions components/collector/src/source_collectors/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Metric collectors per source."""

from .api_source_collectors.azure_devops import AzureDevopsIssues, AzureDevopsReadyUserStoryPoints
from .api_source_collectors.azure_devops import AzureDevopsIssues, AzureDevopsUserStoryPoints
from .api_source_collectors.cxsast import CxSASTSecurityWarnings, CxSASTSourceUpToDateness
from .api_source_collectors.gitlab import (
GitLabFailedJobs, GitLabSourceUpToDateness, GitLabUnmergedBranches, GitLabUnusedJobs)
Expand All @@ -9,7 +9,7 @@
from .api_source_collectors.jenkins import JenkinsFailedJobs, JenkinsJobs
from .api_source_collectors.jenkins_test_report import JenkinsTestReportSourceUpToDateness, JenkinsTestReportTests
from .api_source_collectors.jira import (
JiraIssues, JiraManualTestDuration, JiraManualTestExecution, JiraReadyUserStoryPoints)
JiraIssues, JiraManualTestDuration, JiraManualTestExecution, JiraUserStoryPoints)
from .api_source_collectors.owasp_dependency_check_jenkins_plugin import (
OWASPDependencyCheckJenkinsPluginSecurityWarnings, OWASPDependencyCheckJenkinsPluginSourceUpToDateness)
from .api_source_collectors.quality_time import QualityTimeMetrics, QualityTimeSourceUpToDateness
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ async def _work_items(responses: SourceResponses):
return (await responses[1].json())["value"] if len(responses) > 1 else []


class AzureDevopsReadyUserStoryPoints(AzureDevopsIssues):
"""Collector to get ready user story points from Azure Devops Server."""
class AzureDevopsUserStoryPoints(AzureDevopsIssues):
"""Collector to get user story points from Azure Devops Server."""

async def _parse_source_responses(self, responses: SourceResponses) -> SourceMeasurement:
measurement = await super()._parse_source_responses(responses)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,8 @@ def __value_of_field_to_sum(self, issue: Dict) -> Optional[float]:
return value if value is None else float(value)


class JiraReadyUserStoryPoints(JiraFieldSumBase):
"""Collector to get ready user story points from Jira."""
class JiraUserStoryPoints(JiraFieldSumBase):
"""Collector to get user story points from Jira."""

field_parameter = "story_points_field"
entity_key = "points"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,12 @@ async def test_issues(self):
url=self.work_item_url)])


class AzureDevopsReadyStoryPointsTest(AzureDevopsTestCase):
"""Unit tests for the Azure Devops Server ready story points metric."""
class AzureDevopsStoryPointsTest(AzureDevopsTestCase):
"""Unit tests for the Azure Devops Server story points metric."""

def setUp(self):
super().setUp()
self.metric = dict(type="ready_user_story_points", sources=self.sources, addition="sum")
self.metric = dict(type="user_story_points", sources=self.sources, addition="sum")

async def test_story_points(self):
"""Test that the number of story points are returned."""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,10 @@ async def test_nr_of_test_cases_with_field_name(self):
self.entity(key="1", last_test_date=str(parse(self.ten_days_ago).date()), desired_test_frequency="5")])


class JiraReadyUserStoryPointsTest(JiraTestCase):
"""Unit tests for the Jira ready story points collector."""
class JiraUserStoryPointsTest(JiraTestCase):
"""Unit tests for the Jira story points collector."""

METRIC_TYPE = "ready_user_story_points"
METRIC_TYPE = "user_story_points"

async def test_nr_story_points(self):
"""Test that the number of story points is returned."""
Expand Down
74 changes: 38 additions & 36 deletions components/server/src/data/datamodel.json
Original file line number Diff line number Diff line change
Expand Up @@ -352,29 +352,6 @@
"performance"
]
},
"ready_user_story_points": {
"name": "Ready user story points",
"description": "The number of points of user stories that are ready to implement.",
"scales": [
"count"
],
"default_scale": "count",
"unit": "user story points",
"addition": "sum",
"direction": ">",
"target": "100",
"near_target": "75",
"default_source": "azure_devops",
"sources": [
"azure_devops",
"jira",
"manual_number",
"random"
],
"tags": [
"process efficiency"
]
},
"remediation_effort": {
"name": "Violation remediation effort",
"description": "The amount of effort it takes to remediate violations.",
Expand Down Expand Up @@ -665,6 +642,29 @@
"ci"
]
},
"user_story_points": {
"name": "User story points",
"description": "The total number of points of a selection of user stories.",
"scales": [
"count"
],
"default_scale": "count",
"unit": "user story points",
"addition": "sum",
"direction": ">",
"target": "100",
"near_target": "75",
"default_source": "azure_devops",
"sources": [
"azure_devops",
"jira",
"manual_number",
"random"
],
"tags": [
"process efficiency"
]
},
"violations": {
"name": "Violations",
"description": "The number of violations of programming rules in the software.",
Expand Down Expand Up @@ -1047,7 +1047,7 @@
"metrics": [
"failed_jobs",
"issues",
"ready_user_story_points",
"user_story_points",
"source_up_to_dateness",
"tests",
"unmerged_branches",
Expand All @@ -1064,7 +1064,7 @@
"metrics": [
"failed_jobs",
"issues",
"ready_user_story_points",
"user_story_points",
"source_up_to_dateness",
"tests",
"unmerged_branches",
Expand All @@ -1080,7 +1080,7 @@
"default_value": "",
"metrics": [
"issues",
"ready_user_story_points"
"user_story_points"
]
},
"file_path": {
Expand Down Expand Up @@ -1402,7 +1402,7 @@
}
]
},
"ready_user_story_points": {
"user_story_points": {
"name": "user story",
"name_plural": "user stories",
"measured_attribute": "story_points",
Expand Down Expand Up @@ -2574,7 +2574,7 @@
"issues",
"manual_test_duration",
"manual_test_execution",
"ready_user_story_points"
"user_story_points"
]
},
"jql": {
Expand All @@ -2588,7 +2588,7 @@
"issues",
"manual_test_duration",
"manual_test_execution",
"ready_user_story_points"
"user_story_points"
]
},
"username": {
Expand All @@ -2601,7 +2601,7 @@
"issues",
"manual_test_duration",
"manual_test_execution",
"ready_user_story_points"
"user_story_points"
]
},
"password": {
Expand All @@ -2614,7 +2614,7 @@
"issues",
"manual_test_duration",
"manual_test_execution",
"ready_user_story_points"
"user_story_points"
]
},
"manual_test_duration_field": {
Expand Down Expand Up @@ -2660,7 +2660,7 @@
"mandatory": true,
"default_value": "Story Points",
"metrics": [
"ready_user_story_points"
"user_story_points"
]
}
},
Expand Down Expand Up @@ -2736,7 +2736,7 @@
}
]
},
"ready_user_story_points": {
"user_story_points": {
"name": "user story",
"name_plural": "user stories",
"measured_attribute": "points",
Expand Down Expand Up @@ -2917,7 +2917,7 @@
"metrics",
"performancetest_duration",
"performancetest_stability",
"ready_user_story_points",
"user_story_points",
"scalability",
"slow_transactions",
"security_warnings",
Expand Down Expand Up @@ -4039,6 +4039,7 @@
"Tests",
"Unmerged branches",
"Unused CI-jobs",
"User story points",
"Violations"
],
"api_values": {
Expand Down Expand Up @@ -4068,6 +4069,7 @@
"Tests": "tests",
"Unmerged branches": "unmerged_branches",
"Unused CI-jobs": "unused_jobs",
"User story points": "user_story_points",
"Violations": "violations",
"Violation remediation effort": "remediation_effort"
},
Expand Down Expand Up @@ -5438,7 +5440,7 @@
"issues",
"manual_test_duration",
"manual_test_execution",
"ready_user_story_points",
"user_story_points",
"source_up_to_dateness",
"unmerged_branches"
]
Expand Down Expand Up @@ -5468,7 +5470,7 @@
"long_units",
"performancetest_duration",
"performancetest_stability",
"ready_user_story_points",
"user_story_points",
"scalability",
"security_warnings",
"slow_transactions",
Expand Down
21 changes: 21 additions & 0 deletions components/server/src/initialization/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

# For some reason the init_database() function gets reported as partially uncovered by the feature tests. Ignore.


def init_database() -> Database: # pragma: no cover-behave
"""Initialize the database connection and contents."""
database_url = os.environ.get("DATABASE_URL", "mongodb://root:root@localhost:27017")
Expand All @@ -25,6 +26,7 @@ def init_database() -> Database: # pragma: no cover-behave
if os.environ.get("LOAD_EXAMPLE_REPORTS", "True").lower() == "true":
import_example_reports(database)
add_last_flag_to_reports(database)
rename_ready_user_story_points_metric(database)
return database


Expand All @@ -44,3 +46,22 @@ def add_last_flag_to_reports(database: Database) -> None:
filter={"report_uuid": report_uuid}, sort=[("timestamp", pymongo.DESCENDING)])
report_ids.append(report["_id"])
database.reports.update_many({"_id": {"$in": report_ids}}, {"$set": {"last": True}})


def rename_ready_user_story_points_metric(database: Database) -> None: # pragma: no cover-behave
"""Rename the ready_user_story_points metric to user_story_points."""
# Introduced when the most recent version of Quality-time was 3.3.0.
reports = list(database.reports.find({"last": True, "deleted": {"$exists": False}}))
for report in reports:
changed = False
for subject in report["subjects"].values():
for metric in subject["metrics"].values():
if metric["type"] == "ready_user_story_points":
metric["type"] = "user_story_points"
changed = True
if not metric.get("name"):
metric["name"] = "Ready user story points"
if changed:
report_id = report["_id"]
del report["_id"]
database.reports.replace_one({"_id": report_id}, report)
2 changes: 2 additions & 0 deletions components/server/tests/data/test_datamodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,11 +245,13 @@ def test_quality_time_source_type_parameter(self):
def test_quality_time_metric_type_parameter(self):
"""Test that the metric type parameter of the Quality-time source lists all metric types."""
all_metric_names = {metric["name"] for metric in self.data_model["metrics"].values()}
all_metric_names.add("Ready user story points") # Removed in first non-patch version after Quality-time v3.3.0
quality_time_metric_names = set(
self.data_model["sources"]["quality_time"]["parameters"]["metric_type"]["values"])
self.assertEqual(all_metric_names, quality_time_metric_names)
all_metric_api_values = {
(metric["name"], metric_id) for metric_id, metric in self.data_model["metrics"].items()}
all_metric_api_values.add(("Ready user story points", "ready_user_story_points"))
quality_time_api_values = set(
self.data_model["sources"]["quality_time"]["parameters"]["metric_type"]["api_values"].items())
self.assertEqual(all_metric_api_values, quality_time_api_values)
20 changes: 20 additions & 0 deletions components/server/tests/initialization/test_database.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,23 @@ def test_add_last_flag_to_reports(self):
self.database.reports.find_one.return_value = {"_id": "1"}
self.init_database("{}")
self.database.reports.update_many.assert_called_once()

def test_rename_ready_user_story_points(self):
"""Test that the ready user story points metric is correctly renamed."""
self.database.reports.find.return_value = [
{"_id": "1", "subjects": {}},
{"_id": "2", "subjects": {"subject1": {"metrics": {}}}},
{"_id": "3", "subjects": {
"subject2": {
"metrics": {
"metric1": {"type": "violations"},
"metric2": {"type": "ready_user_story_points"},
"metric3": {"type": "ready_user_story_points", "name": "Don't change the name"}}}}}]
self.init_database("{}")
self.database.reports.replace_one.assert_called_once_with(
{"_id": "3"},
{"subjects": {
"subject2": {
"metrics": {"metric1": {"type": "violations"},
"metric2": {"type": "user_story_points", "name": "Ready user story points"},
"metric3": {"type": "user_story_points", "name": "Don't change the name"}}}}})
6 changes: 6 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

<!-- The line "## <square-bracket>Unreleased</square-bracket>" is replaced by the ci/release.py script with the new release version and release date. -->

## [Unreleased]

### Changed

- Rename the 'ready user story points' to 'user story points' as it can not just be used to count ready user stories, but rather any selection of user stories. Closes [#1415](https://github.com/ICTU/quality-time/issues/1415).

## [3.3.0] - [2020-08-29]

### Fixed
Expand Down
Loading

0 comments on commit 31f5534

Please sign in to comment.