Skip to content
This repository has been archived by the owner on May 15, 2020. It is now read-only.

Commit

Permalink
Merge pull request #39 from kpn/feature/create-release-on-new-pipelin…
Browse files Browse the repository at this point in the history
…e-run

NEW: Create a release object if necessary
  • Loading branch information
mjholtkamp authored Oct 11, 2019
2 parents 4b6c5c9 + f3abacc commit 84824f8
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 11 deletions.
28 changes: 26 additions & 2 deletions katka/signals.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import logging

from django.conf import settings
from django.db.models.signals import post_save
from django.dispatch import receiver

from .constants import PIPELINE_STATUS_INITIALIZING, STEP_FINAL_STATUSES
from .constants import PIPELINE_STATUS_INITIALIZING, RELEASE_STATUS_OPEN, STEP_FINAL_STATUSES
from .fields import username_on_model
from .models import SCMPipelineRun, SCMStepRun
from .models import SCMPipelineRun, SCMRelease, SCMStepRun

log = logging.getLogger('katka')


@receiver(post_save, sender=SCMStepRun)
Expand All @@ -29,6 +33,9 @@ def update_pipeline_from_steps(sender, **kwargs):
@receiver(post_save, sender=SCMPipelineRun)
def send_pipeline_change_notification(sender, **kwargs):
pipeline = kwargs['instance']
if kwargs['created'] is True:
create_release_if_necessary(pipeline)

if pipeline.status == PIPELINE_STATUS_INITIALIZING and kwargs['created'] is False:
# Do not send notifications when the pipeline is initializing. While initializing, steps are created and
# since this is done with several requests, several notifications would be sent, while the only one you
Expand All @@ -41,3 +48,20 @@ def send_pipeline_change_notification(sender, **kwargs):
session.post(
settings.PIPELINE_CHANGE_NOTIFICATION_URL, json={'public_identifier': str(pipeline.public_identifier)}
)


def create_release_if_necessary(pipeline):
releases = SCMRelease.objects.filter(
status=RELEASE_STATUS_OPEN, scm_pipeline_runs__application=pipeline.application
)
with username_on_model(SCMRelease, pipeline.modified_username):
if len(releases) == 0:
release = SCMRelease.objects.create()
elif len(releases) > 1:
log.error(f'Multiple open releases found for application {pipeline.application.pk}, picking newest')
release = releases.order_by('-created').first()
else:
release = releases[0]

release.scm_pipeline_runs.add(pipeline)
release.save()
16 changes: 8 additions & 8 deletions tests/integration/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,13 +378,13 @@ def deactivated_scm_step_run(scm_step_run):

@pytest.fixture
def scm_release(scm_pipeline_run):
scm_release = models.SCMRelease(name='Version 0.13.1',
from_hash='577fe3f6a091aa4bad996623b1548b87f4f9c1f8',
to_hash='a49954f060b1b7605e972c9448a74d4067547443')
scm_release = models.SCMRelease.objects.filter(scm_pipeline_runs__pk__exact=scm_pipeline_run.pk).first()

with username_on_model(models.SCMRelease, 'initial'):
scm_release.name = 'Version 0.13.1'
scm_release.from_hash = '577fe3f6a091aa4bad996623b1548b87f4f9c1f8'
scm_release.to_hash = 'a49954f060b1b7605e972c9448a74d4067547443'
scm_release.save()
scm_release.scm_pipeline_runs.set([scm_pipeline_run])

return scm_release

Expand All @@ -400,13 +400,13 @@ def deactivated_scm_release(scm_release):

@pytest.fixture
def another_scm_release(another_scm_pipeline_run):
scm_release = models.SCMRelease(name='Version 15.0',
from_hash='100763d7144e1f993289bd528dc698dd3906a807',
to_hash='38d72050370e6e0b43df649c9630f7135ef6de0d')
scm_release = models.SCMRelease.objects.filter(scm_pipeline_runs__pk__exact=another_scm_pipeline_run.pk).first()

with username_on_model(models.SCMRelease, 'initial'):
scm_release.name = 'Version 15.0'
scm_release.from_hash = '100763d7144e1f993289bd528dc698dd3906a807'
scm_release.to_hash = '38d72050370e6e0b43df649c9630f7135ef6de0d'
scm_release.save()
scm_release.scm_pipeline_runs.set([another_scm_pipeline_run])

return scm_release

Expand Down
100 changes: 99 additions & 1 deletion tests/integration/test_signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import pytest
from katka import constants
from katka.fields import username_on_model
from katka.models import SCMPipelineRun, SCMStepRun
from katka.models import SCMPipelineRun, SCMRelease, SCMStepRun


@pytest.mark.django_db
Expand Down Expand Up @@ -97,3 +97,101 @@ def test_send_on_create_pipeline(self, application):
pipeline_run.save()

assert len(session.post.call_args_list) == 2


@pytest.mark.django_db
class TestReleaseSignal:
def test_release_created_when_pipeline_run_created(self, application):
assert SCMRelease.objects.count() == 0

session = mock.MagicMock()
overrides = {'PIPELINE_CHANGE_NOTIFICATION_SESSION': session}
with override_settings(**overrides), username_on_model(SCMPipelineRun, 'signal_tester'):
pipeline_run = SCMPipelineRun.objects.create(application=application)

assert SCMRelease.objects.count() == 1
assert SCMRelease.objects.filter(scm_pipeline_runs__pk__exact=pipeline_run.pk).count() == 1

def test_release_not_created_when_updating(self, scm_pipeline_run):
session = mock.MagicMock()
overrides = {'PIPELINE_CHANGE_NOTIFICATION_SESSION': session}

# before
assert SCMRelease.objects.count() == 1
with override_settings(**overrides), username_on_model(SCMPipelineRun, 'signal_tester'):
scm_pipeline_run.status = 'success'
scm_pipeline_run.save()

# after
assert SCMRelease.objects.count() == 1

def test_new_pipeline_gets_added_to_open_release(self, scm_pipeline_run, application):
"""When a release is still open, NO new release should be created when a new pipeline is created"""
assert SCMRelease.objects.count() == 1

session = mock.MagicMock()
overrides = {'PIPELINE_CHANGE_NOTIFICATION_SESSION': session}
with override_settings(**overrides), username_on_model(SCMPipelineRun, 'signal_tester'):
pipeline_run = SCMPipelineRun.objects.create(application=application)

assert SCMRelease.objects.count() == 1
release = SCMRelease.objects.first()
assert len(release.scm_pipeline_runs.all()) == 2
assert release.scm_pipeline_runs.filter(pk__exact=scm_pipeline_run.pk).count() == 1
assert release.scm_pipeline_runs.filter(pk__exact=pipeline_run.pk).count() == 1

def test_new_pipeline_gets_added_to_new_release(self, scm_pipeline_run, scm_release, application):
"""When a release is closed, a new release should be created when a new pipeline is created"""
assert SCMRelease.objects.count() == 1

session = mock.MagicMock()
overrides = {'PIPELINE_CHANGE_NOTIFICATION_SESSION': session}
with override_settings(**overrides), username_on_model(SCMRelease, 'signal_tester'):
scm_release.status = 'closed'
scm_release.save()

with override_settings(**overrides), username_on_model(SCMPipelineRun, 'signal_tester'):
pipeline_run = SCMPipelineRun.objects.create(application=application)

assert SCMRelease.objects.count() == 2
release = SCMRelease.objects.filter(scm_pipeline_runs__pk__exact=pipeline_run.pk).first()
assert release.pk != scm_release.pk

assert len(scm_release.scm_pipeline_runs.all()) == 1
assert scm_release.scm_pipeline_runs.filter(pk__exact=scm_pipeline_run.pk).count() == 1

assert len(release.scm_pipeline_runs.all()) == 1
assert release.scm_pipeline_runs.filter(pk__exact=pipeline_run.pk).count() == 1

def test_multiple_applications(self, scm_pipeline_run, another_scm_pipeline_run, scm_release, another_scm_release):
"""Different releases should be created for pipeline_runs of different applications"""
assert SCMRelease.objects.count() == 2
assert another_scm_release.pk != scm_release.pk

assert len(scm_release.scm_pipeline_runs.all()) == 1
assert scm_release.scm_pipeline_runs.filter(pk__exact=scm_pipeline_run.pk).count() == 1

assert len(another_scm_release.scm_pipeline_runs.all()) == 1
assert another_scm_release.scm_pipeline_runs.filter(pk__exact=another_scm_pipeline_run.pk).count() == 1

def test_pick_newest_on_duplicate_open_releases(self, application, scm_release, scm_pipeline_run, caplog):
"""This should not happen, but if it happens, handle it gracefully"""
session = mock.MagicMock()
overrides = {'PIPELINE_CHANGE_NOTIFICATION_SESSION': session}
with override_settings(**overrides), username_on_model(SCMRelease, 'signal_tester'):
open_release_2 = SCMRelease.objects.create()
open_release_2.scm_pipeline_runs.add(scm_pipeline_run)
open_release_2.save()

assert scm_release.created < open_release_2.created

with override_settings(**overrides), username_on_model(SCMPipelineRun, 'signal_tester'):
pipeline_run = SCMPipelineRun.objects.create(application=application)

assert SCMRelease.objects.count() == 2
assert not scm_release.scm_pipeline_runs.filter(pk=pipeline_run.pk).exists()
assert open_release_2.scm_pipeline_runs.filter(pk=pipeline_run.pk).exists()
katka_records = [record.message for record in caplog.records if record.name == 'katka']
assert len(katka_records) == 1
assert 'Multiple open releases found' in katka_records[0]
assert 'picking newest' in katka_records[0]

0 comments on commit 84824f8

Please sign in to comment.