Skip to content

Commit

Permalink
Rename "CI"-environment" subject type.
Browse files Browse the repository at this point in the history
Rename the "CI-environment" subject type to "Development environment".

Prepares for #3130.
  • Loading branch information
fniessink committed May 28, 2024
1 parent 989f89d commit 0f50f90
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 48 deletions.
99 changes: 56 additions & 43 deletions components/api_server/src/initialization/migrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,55 +12,50 @@
def perform_migrations(database: Database) -> None: # pragma: no feature-test-cover
"""Perform database migrations."""
for report in database.reports.find(filter={"last": True, "deleted": {"$exists": False}}):
change_accessibility_violation_metrics_to_violations(database, report)
fix_branch_parameters_without_value(database, report)
add_source_parameter_hash(database, report)


def change_accessibility_violation_metrics_to_violations( # pragma: no feature-test-cover
database: Database, report
) -> None:
"""Replace accessibility metrics with the violations metric."""
report_uuid = report["report_uuid"]
logging.info("Checking report for necessary updates: %s", report_uuid)
if any(
changes := [
change_accessibility_violation_metrics_to_violations(report),
fix_branch_parameters_without_value(report),
change_ci_subject_types_to_development_environment(report),
]
):
logging.info("Updating report %s to %s", report_uuid, " and to ".join(changes))
replace_document(database.reports, report)
logging.info("Checking report for necessary measurement updates: %s", report_uuid)
count = add_source_parameter_hash_to_latest_measurement(database, report)
logging.info("Updated %s measurements: %s", count, report_uuid)


def change_accessibility_violation_metrics_to_violations(report) -> str: # pragma: no feature-test-cover
"""Replace accessibility metrics with violations metrics. Return a description of the change, if any."""
# Added after Quality-time v5.5.0, see https://github.com/ICTU/quality-time/issues/562
report_uuid = report["report_uuid"]
logging.info("Checking report for accessibility metrics: %s", report_uuid)
changed = False
change = ""
for subject in report["subjects"].values():
for metric in subject["metrics"].values():
if metric["type"] == "accessibility":
change_accessibility_violations_metric_to_violations(metric)
changed = True
if changed:
logging.info("Updating report to change its accessibility metrics to violations metrics: %s", report_uuid)
replace_document(database.reports, report)
else:
logging.info("No accessibility metrics found in report: %s", report_uuid)


def change_accessibility_violations_metric_to_violations(metric: dict) -> None: # pragma: no feature-test-cover
"""Change the accessibility violations metric to violations metric."""
metric["type"] = "violations"
if not metric.get("name"):
metric["name"] = "Accessibility violations"
if not metric.get("unit"):
metric["unit"] = "accessibility violations"


def fix_branch_parameters_without_value(database: Database, report) -> None: # pragma: no feature-test-cover
"""Set the branch parameter of sources to 'master' (the previous default) if they have no value."""
metric["type"] = "violations"
if not metric.get("name"):
metric["name"] = "Accessibility violations"
if not metric.get("unit"):
metric["unit"] = "accessibility violations"
change = "change its accessibility metrics to violations metrics"
return change


def fix_branch_parameters_without_value(report) -> str: # pragma: no feature-test-cover
"""Set the branch parameter of sources to 'master' (the previous default) if they have no value.
Return a description of the change, if any.
"""
# Added after Quality-time v5.11.0, see https://github.com/ICTU/quality-time/issues/8045
report_uuid = report["report_uuid"]
logging.info("Checking report for sources with empty branch parameters: %s", report_uuid)
changed = False
change = ""
for source in sources_with_branch_parameter(report):
if not source["parameters"].get("branch"):
source["parameters"]["branch"] = "master"
changed = True
if changed:
logging.info("Updating report to change sources with empty branch parameter: %s", report_uuid)
replace_document(database.reports, report)
else:
logging.info("No sources with empty branch parameters found in report: %s", report_uuid)
change = "change sources with empty branch parameter"
return change


METRICS_WITH_SOURCES_WITH_BRANCH_PARAMETER = {
Expand Down Expand Up @@ -93,9 +88,25 @@ def sources_with_branch_parameter(report: dict): # pragma: no feature-test-cove
yield source


def add_source_parameter_hash(database: Database, report) -> None: # pragma: no feature-test-cover
"""Add source parameter hashes to the latest measurements."""
def change_ci_subject_types_to_development_environment(report) -> str: # pragma: no feature-test-cover
"""Change the CI subject type to development environment. Return a description of the change, if any."""
# Added after Quality-time v5.13.0, see https://github.com/ICTU/quality-time/issues/3130
change = ""
for subject in report["subjects"].values():
if subject["type"] == "ci":
subject["type"] = "development_environment"
if not subject.get("name"):
subject["name"] = "CI-environment"
if not subject.get("description"):
subject["description"] = "A continuous integration environment."
change = "change subjects with type 'ci'"
return change


def add_source_parameter_hash_to_latest_measurement(database: Database, report) -> int: # pragma: no feature-test-cover
"""Add source parameter hashes to the latest measurements. Return the number of measurements changed."""
# Added after Quality-time v5.12.0, see https://github.com/ICTU/quality-time/issues/8736
count = 0
for subject in report["subjects"].values():
for metric_uuid, metric in subject["metrics"].items():
latest_measurement = database.measurements.find_one(
Expand All @@ -108,6 +119,8 @@ def add_source_parameter_hash(database: Database, report) -> None: # pragma: no
continue
latest_measurement["source_parameter_hash"] = Metric({}, metric, metric_uuid).source_parameter_hash()
replace_document(database.measurements, latest_measurement)
count += 1
return count


def replace_document(collection: Collection, document) -> None: # pragma: no feature-test-cover
Expand Down
62 changes: 60 additions & 2 deletions components/api_server/tests/initialization/test_migrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def existing_report(self, metric_type: str):
return {
"_id": "id",
"report_uuid": REPORT_ID,
"subjects": {SUBJECT_ID: {"metrics": {METRIC_ID: {"type": metric_type}}}},
"subjects": {SUBJECT_ID: {"type": "software", "metrics": {METRIC_ID: {"type": metric_type}}}},
}

def inserted_report(self, **kwargs):
Expand Down Expand Up @@ -71,6 +71,12 @@ def inserted_report(
metric_type="violations", metric_name=metric_name, metric_unit=metric_unit, **kwargs
)

def test_report_without_accessibility_metrics(self):
"""Test that the migration succeeds with reports, but without accessibility metrics."""
self.database.reports.find.return_value = [self.existing_report(metric_type="loc")]
perform_migrations(self.database)
self.database.reports.replace_one.assert_not_called()

def test_report_with_accessibility_metric(self):
"""Test that the migration succeeds with an accessibility metric."""
self.database.reports.find.return_value = [self.existing_report()]
Expand Down Expand Up @@ -105,9 +111,15 @@ def existing_report(
"""Extend to add sources and an extra metric without sources."""
report = super().existing_report(metric_type=metric_type)
report["subjects"][SUBJECT_ID]["metrics"][METRIC_ID2] = {"type": "issues"}
report["subjects"][SUBJECT_ID]["metrics"][METRIC_ID]["sources"] = sources
report["subjects"][SUBJECT_ID]["metrics"][METRIC_ID]["sources"] = sources or {}
return report

def test_report_without_branch_parameter(self):
"""Test that the migration succeeds with reports, but without metrics with a branch parameter."""
self.database.reports.find.return_value = [self.existing_report()]
perform_migrations(self.database)
self.database.reports.replace_one.assert_not_called()

def test_report_with_non_empty_branch_parameter(self):
"""Test that the migration succeeds when the branch parameter is not empty."""
self.database.reports.find.return_value = [
Expand Down Expand Up @@ -164,3 +176,49 @@ def test_metric_without_measurement(self):
self.database.reports.find.return_value = [self.existing_report(sources={SOURCE_ID: {"type": "cloc"}})]
perform_migrations(self.database)
self.database.measurements.replace_one.assert_not_called()


class CIEnvironmentTest(MigrationTestCase):
"""Unit tests for the CI-environment subject type database migration."""

def existing_report(self, subject_type: str = "", subject_name: str = "", subject_description: str = ""):
"""Extend to set the subject type to CI-environment."""
report = super().existing_report(metric_type="issues")
if subject_type:
report["subjects"][SUBJECT_ID]["type"] = subject_type
if subject_name:
report["subjects"][SUBJECT_ID]["name"] = subject_name
if subject_description:
report["subjects"][SUBJECT_ID]["description"] = subject_description
return report

def inserted_report(self, **kwargs):
"""Extend to set the subject type to development environment."""
report = super().inserted_report(**kwargs)
report["subjects"][SUBJECT_ID]["type"] = "development_environment"
return report

def test_report_without_ci_environment(self):
"""Test that the migration succeeds without CI-environment subject."""
self.database.reports.find.return_value = [self.existing_report()]
perform_migrations(self.database)
self.database.reports.replace_one.assert_not_called()

def test_report_with_ci_environment(self):
"""Test that the migration succeeds with CI-environment subject."""
self.database.reports.find.return_value = [self.existing_report(subject_type="ci")]
perform_migrations(self.database)
inserted_report = self.inserted_report(
subject_name="CI-environment",
subject_description="A continuous integration environment.",
)
self.database.reports.replace_one.assert_called_once_with({"_id": "id"}, inserted_report)

def test_ci_environment_with_title_and_subtitle(self):
"""Test that the migration succeeds with an CI-environment subject, and existing title and subtitle are kept."""
self.database.reports.find.return_value = [
self.existing_report(subject_type="ci", subject_name="CI", subject_description="My CI")
]
perform_migrations(self.database)
inserted_report = self.inserted_report(subject_name="CI", subject_description="My CI")
self.database.reports.replace_one.assert_called_once_with({"_id": "id"}, inserted_report)
7 changes: 4 additions & 3 deletions components/shared_code/src/shared_data_model/subjects.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
from .meta.subject import Subject

SUBJECTS = {
"ci": Subject(
name="CI-environment",
description="A continuous integration environment.",
"development_environment": Subject(
name="Development environment",
description="A software development and/or maintenance environment, consisting of infrastructure, pipelines, "
"and tools needed to build, test, and deploy software.",
metrics=[
"failed_jobs",
"job_runs_within_time_period",
Expand Down
4 changes: 4 additions & 0 deletions docs/src/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ If your currently installed *Quality-time* version is v4.10.0 or older, please r

- When using Dependency-Track as source for dependencies, security warnings, or source-up-to-dateness, allow for filtering by project name and version. Closes [#8686](https://github.com/ICTU/quality-time/issues/8686).

### Changed

- Rename the "CI-environment" subject type to "Development environment". Prepares for [#3130](https://github.com/ICTU/quality-time/issues/3130).

## v5.12.0 - 2024-05-17

### Deployment notes
Expand Down

0 comments on commit 0f50f90

Please sign in to comment.