Commit b3020aaf authored by Shinya Maeda's avatar Shinya Maeda

Squashed commit of the following:

commit 931d6ab0e025b0268d94e455f736b09a025e0578
Merge: b34d165320d 93846eb1
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Nov 5 09:36:58 2018 +0900

    Merge branch 'master-ce' into stateful_deployments

commit b34d165320d6f3298c8b776ba66270a59c217412
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Nov 2 18:07:08 2018 +0900

    Fix flaky spec

commit b5e0527c5d4fe8f18b2fdda5916bae9b8cd859a4
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Nov 2 15:32:03 2018 +0900

    Fix spec

commit f78a5e96e66fe2d25086df495e339b470a274df8
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Nov 2 14:59:29 2018 +0900

    Remove unnecessary line in schema.rb

commit 6ce7c483e0591b5d6f9588a99853834327b80031
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Nov 2 14:55:48 2018 +0900

    Add partial index for filling deployment at migration

commit aecccfb5118c8982db3ba502fdf37b5e639fbfc6
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Nov 2 14:42:24 2018 +0900

    Fix fill empty finished at migration

commit 0199e1761ad1b391ae87a53a9a113d3256529e0e
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Nov 2 14:19:44 2018 +0900

    Fix flaky spec

commit 56ac84cd8095afab5b909119445537b7da06a2ff
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Nov 2 10:06:49 2018 +0900

    Fix guard clause to prevent multiple deployments to a job

commit 521561b6b303b54635c30cb23d78e49d14cec53d
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Nov 1 20:19:24 2018 +0900

    Fix spec

commit 2878da0d29b9bd2dde69a1b216203df118dd59a1
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Nov 1 19:38:59 2018 +0900

    Simplify the factory

commit 22fd7df02133f3a21828554965fd5619905eac2c
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Nov 1 19:33:50 2018 +0900

    Simplify the Deployable and BuildSuccessWorker

commit 41108959677ed614f4548443a2f4303c4c04925a
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Nov 1 18:34:20 2018 +0900

    Fix spec

commit ae75fe7461ac72f621498797f478d42331342b84
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Nov 1 17:19:12 2018 +0900

    Fix weird virtual deployment status

commit 380fee7494d06407dccc292c3cbedbcee7b6e235
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Nov 1 15:59:31 2018 +0900

    Fix spec

commit 29889fcbaadb3bbfd2f11c10bfbf5dceb3e3ddba
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Nov 1 15:07:10 2018 +0900

    Fix coding offence

commit 36ac13f345f5ef25725c2236a791a40a3a9e6126
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Nov 1 14:22:17 2018 +0900

    Squashed commit of the following:

    commit ba9aede922e1643db3f06c56736d46d6d86d356b
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Thu Nov 1 14:21:33 2018 +0900

        Fix ambiguious factory specification in update deployment service spec

    commit 013afb5668cb30dc4ca5b21945c17b341e7ea7f9
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Thu Nov 1 14:10:24 2018 +0900

        Fix spec

    commit 78793670d049e2dfb5fc98177eb4d10f20b9310b
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Wed Oct 31 18:26:12 2018 +0900

        Fix spec

    commit 73d27e87c66698f2e3a817bb8728f02475b7ba4f
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Wed Oct 31 16:22:14 2018 +0900

        Fix index

    commit 8580a226ea68bf5e49b35bfb5f404968bbfaf8e9
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Wed Oct 31 15:34:57 2018 +0900

        Fix deployment relationships in Ci::Build

    commit d6d28b55afd1179200b4f5188e0b53079ff3c1a7
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Wed Oct 31 15:27:53 2018 +0900

        Fix spec

    commit 94eb754e2e1bb9a1fe627f86823f571a8298d27b
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Wed Oct 31 14:07:11 2018 +0900

        Fix spec

    commit 0b30f80bcd08a7a06bdde3378ec1733f865284be
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Tue Oct 30 20:15:31 2018 +0900

        Fix spec

    commit 466bdcdb6af8cdb475c9fa16bd7d1dff23b11e40
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Tue Oct 30 19:28:51 2018 +0900

        Fix spec

    commit a7c3caac99139e70fe3f1f3d14856939fa25c527
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Tue Oct 30 17:33:47 2018 +0900

        Fix factory

    commit cea28ae100532e6711ce1d22676719a94e2da8a0
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Tue Oct 30 16:28:18 2018 +0900

        Drop leagacy success

    commit 3785d685eabc10b6597cf3db67bf08385ccf298a
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Tue Oct 30 15:37:28 2018 +0900

        Remove unnecessary migration file

    commit 0d597fa46eeffdbb9a4afb53005a8183e433c6bf
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Tue Oct 30 15:35:53 2018 +0900

        Fix schema.rb

    commit ec3c2abc6944e09f6410468ae5e356865ec7b02b
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Tue Oct 30 15:34:21 2018 +0900

        Rename post migration file

    commit 0e7281885a84656acf95f0f423732680f8fec076
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Tue Oct 30 15:31:01 2018 +0900

        Remove include EnumWithNil

    commit b3846d59c07e07275126c70361bde7f30810729e
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Tue Oct 30 15:05:50 2018 +0900

        Decouple action

    commit c9f9ba4eae9ca1edc7d8751e1d2e0572cb222d9c
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Tue Oct 30 14:23:29 2018 +0900

        Remove status mock

    commit d95bfea1ca67b3a27a3226a669c2b1266d696682
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Tue Oct 30 14:17:14 2018 +0900

        Add action

    commit 0cec39e0f76c22a18498f46d65ad7226fb30c3f8
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Tue Oct 30 13:44:07 2018 +0900

        Remove unnecessary line in schema.rb

    commit 7b4c5f8e1b00dd8e6aa944352f9d8a9f3ae6f1c7
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Mon Oct 29 19:59:41 2018 +0900

        Revert build success worker

    commit 0c52ffa4a23eea488c187317e8b400369846f399
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Mon Oct 29 19:11:47 2018 +0900

        Use add_column_with_default properly

    commit ba9bae357da5dfd2f6ec05f7f9db9d0b31224f48
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Mon Oct 29 18:40:55 2018 +0900

        Fix with_status

    commit 75dffc97b9c5f6fa73d9d09b125c8f849fa2caae
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Mon Oct 29 16:26:56 2018 +0900

        Remove unnecessary line in schema.rb

    commit 25188ccc52fb29ca63b9205c4d95ffc2e0afadee
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Mon Oct 29 16:26:17 2018 +0900

        Set default values in regular migration

    commit 98ea037fbf39c8d9f0db77fb50e2d08382425158
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Fri Oct 26 17:27:49 2018 +0900

        Fix static analysis

    commit e7d1765f77f9ff9b94a34985a7855bdaab1da675
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Fri Oct 26 16:37:10 2018 +0900

        Remove empty spec

    commit 0033f521ed1eae8117dba231961aa47c068bbcfb
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Fri Oct 26 16:34:55 2018 +0900

        Simplify spec changes

    commit 0be4c6b3ade6d9a8bf28bcd177c66ebd7bb7d20a
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Fri Oct 26 16:32:45 2018 +0900

        Simplify spec changes

    commit a93d25d79df7e25bdf688fc938c712922f9dc4df
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Fri Oct 26 16:02:31 2018 +0900

        Fix flaky spec

    commit 339ad50cf471ca706b29f008ccd2bb881dd5b776
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Fri Oct 26 15:06:22 2018 +0900

        Rename Deployments Success worker

    commit bd69c78085adcb9b0f8ff9b7041ae355953ad7ab
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Fri Oct 26 14:43:03 2018 +0900

        Fix coding offence

    commit 004748b2a9c5236ec13eb01289418f3d6571c92c
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Thu Oct 25 20:09:10 2018 +0900

        Rename to update deployment service

    commit b04a85e761de501f030f3844fd485a2b9e46f7f7
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Thu Oct 25 18:46:52 2018 +0900

        Add spec for Project

    commit 548af23a5a07f0c20b72849d03aa0b98a0b49134
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Thu Oct 25 18:43:25 2018 +0900

        Fix spec

    commit c977e4d3f17194c46a1bf857b473017ce21ef7e9
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Thu Oct 25 17:58:07 2018 +0900

        Add spec for Environment

    commit 73feb9010f8d8093bee4b46e56d30cfef3e8e34a
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Thu Oct 25 17:39:24 2018 +0900

        Add spec for Deployment model

    commit 9a3cfbf766f402571588839375cf311bb9807035
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Thu Oct 25 17:18:02 2018 +0900

        Fix statis analysis

    commit a30d28dbc631a29855883ca89c592a10c012f1d2
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Thu Oct 25 17:17:32 2018 +0900

        Ignore nil instance

    commit fa6fdd89f380e588a6bcf14b1f9aef0d14d3854b
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Thu Oct 25 16:20:40 2018 +0900

        Add spec for deployable concern

    commit aa91186821dc671df2c7a641e37586dd5dfc1008
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Thu Oct 25 15:37:23 2018 +0900

        Clean up deployable

    commit 34d3e18731f7906a3db250b105a64d1db83c2fca
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Thu Oct 25 15:13:05 2018 +0900

        Fix 17 cycle analytics

    commit 8dc9e00408f9b390175e7d5ea743eed4fb9e3f79
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Thu Oct 25 13:56:51 2018 +0900

        Fix static analysys

    commit 5c4175807a537bafc4b889b0a97e8f96f0e483cd
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Wed Oct 24 15:05:05 2018 +0900

        Skip unnecessary sidekiq worker

    commit 9d8b5d423f49cc247c96ce3767d03b4af305809f
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Wed Oct 24 14:53:13 2018 +0900

        Add changelog

    commit c8cabba496722240cadf7c161c80bceb09727cba
    Author: Shinya Maeda <shinya@gitlab.com>
    Date:   Wed Oct 24 14:44:45 2018 +0900

        Squashed commit of the following:

        commit f7643885ac2329e18d690a4e4f2d7614b732c793
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Tue Oct 23 19:38:45 2018 +0900

            Fix deployment widget specs

        commit 03bd04b5c98b634dff6a0ab4292c150a9031995c
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Tue Oct 23 17:50:16 2018 +0900

            Fix env status spec

        commit 4a49c6502b161a12f0f62d5ec167dff777047dab
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Tue Oct 23 17:48:59 2018 +0900

            Fix environment spec

        commit 4044822887987e20a703990ff20352a532eeb965
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Tue Oct 23 17:47:17 2018 +0900

            Fix environment spec

        commit 9939d44b7eb9da371de74c0f04fed1eb3db37ad3
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Tue Oct 23 15:45:43 2018 +0900

            Add a new spec for deployment success worker

        commit f61c4d3657b5ef13b5da171460da68a6643ad4b5
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Tue Oct 23 15:38:11 2018 +0900

            Fix cycle analytics helper

        commit b6242615e8298fb7fc047c8df8006c25ad717c70
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Tue Oct 23 14:41:54 2018 +0900

            Fix cycle analysis helper

        commit 9a001cb4c4ed6f3b87dc612bdffc60a6b2b0a132
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Tue Oct 23 14:37:08 2018 +0900

            Ignore coding offence in build success worker's spec

        commit 1fb88583025bac8a56172cbd59be04258ea4c5f3
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Tue Oct 23 14:33:11 2018 +0900

            Added more spec for deployments

        commit 1a6ba97ababbf62e8dd0ae0c56d75ab1268fd0ce
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Mon Oct 22 19:36:50 2018 +0900

            Move after create hookd into success worker

        commit 09de5fed5d6f108423779cf9d9e7f1d21f3c1c91
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Mon Oct 22 19:30:06 2018 +0900

            Fix build spec

        commit 73a55cbcabbb1e928eca3e53e8ff75dec178bc90
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Mon Oct 22 19:08:43 2018 +0900

            Fix update_deployment_metrics_service_spec.rb

        commit ee05136a02ae9fa348b4b89b9a69937ebb9697dd
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Mon Oct 22 17:32:05 2018 +0900

            Remove unnecessary degelate

        commit e246ddeebc01a807ccc36fdb484c3e72ad91e680
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Mon Oct 22 16:07:39 2018 +0900

            Remove unnecessary optimistic locking

        commit dcc225c8237b90e3bc8dcc3dc2e3252e0b0be093
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Mon Oct 22 16:00:22 2018 +0900

            Simplify status replication

        commit 13a5fd7afb67ba2712fcaecaea5fedf05f9ad177
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Mon Oct 22 15:29:24 2018 +0900

            Fix sidekiq queue names

        commit dcc796f48d523538e1c91b9cd3e1c7065e5329b1
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Mon Oct 22 15:23:55 2018 +0900

            Revert success check in update_merge_request_metrics

        commit 129ef083d637d4acb8c97a6d9ab96deb2ff6efcd
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Mon Oct 22 15:18:31 2018 +0900

            Fix queue name of deployment success worker

        commit 10fe5a6484f4f02322ce5bb16844fc7b1d565963
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Mon Oct 22 15:09:42 2018 +0900

            Introduce deployable module

        commit d91260bbe105bf46f6c06d9e9593c8c4cd5139cf
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Mon Oct 22 14:05:31 2018 +0900

            Add database index for successful deployments

        commit 74274147263de4b60870065a19935498ce662e30
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Mon Oct 22 13:51:59 2018 +0900

            Fix invalid state transition

        commit ff18463cc847bf3cf5a3e49f3651eedfdf67c7e6
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Fri Oct 19 20:05:15 2018 +0900

            Fix coding style offence

        commit 0202c0f5b631601edab7b359b087b307f5eb7ba3
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Fri Oct 19 18:34:07 2018 +0900

            Target only successful deployments from other relations

        commit 1f2758cb030dec1df5dda30f6bc3e25b6d0841c9
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Fri Oct 19 18:21:28 2018 +0900

            Add namespace explicitly

        commit 3d9227b6e5642cecde88d4edac925125f6474b11
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Fri Oct 19 17:42:30 2018 +0900

            Fix spec in DeleteInconsistentInternalIdRecords

        commit 3e0cc99ff6c5c7188511618228a6ec027752ce69
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Fri Oct 19 16:10:16 2018 +0900

            Fixed spec

        commit 8de09b8bb31f7b9f24ecdf9f2dd8ef358a260263
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Fri Oct 19 14:22:35 2018 +0900

            Fix create deployment service

        commit 31957570b4444492eeb412e765f96a56416c25f3
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Thu Oct 18 20:21:26 2018 +0900

            Move CreateDeploymentService. Fix Cycle analytics spec and fixture.

        commit d2eb433a1bb9710c0d4778c4f34c12b6b64f60e6
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Thu Oct 18 20:11:22 2018 +0900

            Fix build success worker

        commit 25e6cd87138bcdb69de8785ca367e479c8dbcc59
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Thu Oct 18 19:49:13 2018 +0900

            Fix create deployment service spec

        commit d268bf410bf65e86c81eb76d50aa8e145b32d249
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Thu Oct 18 19:01:23 2018 +0900

            Fix cycle analysys spec's deployment

        commit 525ade8aa1e4394ed8a759bb0437e407fbe74a35
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Thu Oct 18 18:24:04 2018 +0900

            Fix factory to set legacy status by default

        commit c6a990821ac0a1ffa49e20e2d78d94b8ce075914
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Thu Oct 18 17:25:40 2018 +0900

            Remove unnecessary lib from deployment

        commit a6107e0e85ac26ee09da3316ebc11de32f067d82
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Wed Oct 17 17:38:58 2018 +0900

            Fix recursive call

        commit 15c5f3b64061a75af3c3039ca7f49b1cc4ff3068
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Wed Oct 17 17:30:44 2018 +0900

            Add finished_at

        commit c8d3d70366f694d78acb7e30d342c7697798b922
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Wed Oct 17 15:55:31 2018 +0900

            Fix last_deployment methods as it used to return successful deployment always

        commit 96bbe8670cece021766fde95fe573cbbe23d1e55
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Wed Oct 17 15:49:57 2018 +0900

            Redefine statuses

        commit c86a9d0bd2ab3e7a00bf61f094a96ee99b76b289
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Wed Oct 17 14:50:27 2018 +0900

            Fix schema.rb

        commit 9ff5f0eaafbc08795018c7bb282b19f6327dee21
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Wed Oct 17 14:18:04 2018 +0900

            Default status nil to success

        commit 5928bd9bb94e1e8908ed1561e01595be84d5f4ec
        Author: Shinya Maeda <shinya@gitlab.com>
        Date:   Tue Oct 16 15:13:48 2018 +0900

            Add status to Deployment
parent 57bc28e7
...@@ -9,19 +9,18 @@ module Ci ...@@ -9,19 +9,18 @@ module Ci
include Presentable include Presentable
include Importable include Importable
include Gitlab::Utils::StrongMemoize include Gitlab::Utils::StrongMemoize
include Deployable
belongs_to :project, inverse_of: :builds belongs_to :project, inverse_of: :builds
belongs_to :runner belongs_to :runner
belongs_to :trigger_request belongs_to :trigger_request
belongs_to :erased_by, class_name: 'User' belongs_to :erased_by, class_name: 'User'
has_many :deployments, as: :deployable
RUNNER_FEATURES = { RUNNER_FEATURES = {
upload_multiple_artifacts: -> (build) { build.publishes_artifacts_reports? } upload_multiple_artifacts: -> (build) { build.publishes_artifacts_reports? }
}.freeze }.freeze
has_one :last_deployment, -> { order('deployments.id DESC') }, as: :deployable, class_name: 'Deployment' has_one :deployment, as: :deployable, class_name: 'Deployment'
has_many :trace_sections, class_name: 'Ci::BuildTraceSection' has_many :trace_sections, class_name: 'Ci::BuildTraceSection'
has_many :trace_chunks, class_name: 'Ci::BuildTraceChunk', foreign_key: :build_id has_many :trace_chunks, class_name: 'Ci::BuildTraceChunk', foreign_key: :build_id
...@@ -195,6 +194,8 @@ module Ci ...@@ -195,6 +194,8 @@ module Ci
end end
after_transition pending: :running do |build| after_transition pending: :running do |build|
build.deployment&.run
build.run_after_commit do build.run_after_commit do
BuildHooksWorker.perform_async(id) BuildHooksWorker.perform_async(id)
end end
...@@ -207,14 +208,18 @@ module Ci ...@@ -207,14 +208,18 @@ module Ci
end end
after_transition any => [:success] do |build| after_transition any => [:success] do |build|
build.deployment&.succeed
build.run_after_commit do build.run_after_commit do
BuildSuccessWorker.perform_async(id)
PagesWorker.perform_async(:deploy, id) if build.pages_generator? PagesWorker.perform_async(:deploy, id) if build.pages_generator?
end end
end end
before_transition any => [:failed] do |build| before_transition any => [:failed] do |build|
next unless build.project next unless build.project
build.deployment&.drop
next if build.retries_max.zero? next if build.retries_max.zero?
if build.retries_count < build.retries_max if build.retries_count < build.retries_max
...@@ -233,6 +238,10 @@ module Ci ...@@ -233,6 +238,10 @@ module Ci
after_transition running: any do |build| after_transition running: any do |build|
Ci::BuildRunnerSession.where(build: build).delete_all Ci::BuildRunnerSession.where(build: build).delete_all
end end
after_transition any => [:skipped, :canceled] do |build|
build.deployment&.cancel
end
end end
def ensure_metadata def ensure_metadata
...@@ -342,8 +351,12 @@ module Ci ...@@ -342,8 +351,12 @@ module Ci
self.options.fetch(:environment, {}).fetch(:action, 'start') if self.options self.options.fetch(:environment, {}).fetch(:action, 'start') if self.options
end end
def has_deployment?
!!self.deployment
end
def outdated_deployment? def outdated_deployment?
success? && !last_deployment.try(:last?) success? && !deployment.try(:last?)
end end
def depends_on_builds def depends_on_builds
...@@ -358,6 +371,10 @@ module Ci ...@@ -358,6 +371,10 @@ module Ci
user == current_user user == current_user
end end
def on_stop
options&.dig(:environment, :on_stop)
end
# A slugified version of the build ref, suitable for inclusion in URLs and # A slugified version of the build ref, suitable for inclusion in URLs and
# domain names. Rules: # domain names. Rules:
# #
...@@ -725,7 +742,7 @@ module Ci ...@@ -725,7 +742,7 @@ module Ci
if success? if success?
return successful_deployment_status return successful_deployment_status
elsif complete? && !success? elsif failed?
return :failed return :failed
end end
...@@ -742,13 +759,11 @@ module Ci ...@@ -742,13 +759,11 @@ module Ci
end end
def successful_deployment_status def successful_deployment_status
if success? && last_deployment&.last? if deployment&.last?
return :last :last
elsif success? && last_deployment.present? else
return :out_of_date :out_of_date
end end
:creating
end end
def each_report(report_types) def each_report(report_types)
......
# frozen_string_literal: true
module Deployable
extend ActiveSupport::Concern
included do
after_create :create_deployment
def create_deployment
return unless has_environment? && !has_deployment?
environment = project.environments.find_or_create_by(
name: expanded_environment_name
)
environment.deployments.create!(
project_id: environment.project_id,
environment: environment,
ref: ref,
tag: tag,
sha: sha,
user: user,
deployable: self,
on_stop: on_stop).tap do |_|
self.reload # Reload relationships
end
end
end
end
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
class Deployment < ActiveRecord::Base class Deployment < ActiveRecord::Base
include AtomicInternalId include AtomicInternalId
include IidRoutes include IidRoutes
include AfterCommitQueue
belongs_to :project, required: true belongs_to :project, required: true
belongs_to :environment, required: true belongs_to :environment, required: true
...@@ -16,11 +17,44 @@ class Deployment < ActiveRecord::Base ...@@ -16,11 +17,44 @@ class Deployment < ActiveRecord::Base
delegate :name, to: :environment, prefix: true delegate :name, to: :environment, prefix: true
after_create :create_ref
after_create :invalidate_cache
scope :for_environment, -> (environment) { where(environment_id: environment) } scope :for_environment, -> (environment) { where(environment_id: environment) }
state_machine :status, initial: :created do
event :run do
transition created: :running
end
event :succeed do
transition any - [:success] => :success
end
event :drop do
transition any - [:failed] => :failed
end
event :cancel do
transition any - [:canceled] => :canceled
end
before_transition any => [:success, :failed, :canceled] do |deployment|
deployment.finished_at = Time.now
end
after_transition any => :success do |deployment|
deployment.run_after_commit do
Deployments::SuccessWorker.perform_async(id)
end
end
end
enum status: {
created: 0,
running: 1,
success: 2,
failed: 3,
canceled: 4
}
def self.last_for_environment(environment) def self.last_for_environment(environment)
ids = self ids = self
.for_environment(environment) .for_environment(environment)
...@@ -69,15 +103,15 @@ class Deployment < ActiveRecord::Base ...@@ -69,15 +103,15 @@ class Deployment < ActiveRecord::Base
end end
def update_merge_request_metrics! def update_merge_request_metrics!
return unless environment.update_merge_request_metrics? return unless environment.update_merge_request_metrics? && success?
merge_requests = project.merge_requests merge_requests = project.merge_requests
.joins(:metrics) .joins(:metrics)
.where(target_branch: self.ref, merge_request_metrics: { first_deployed_to_production_at: nil }) .where(target_branch: self.ref, merge_request_metrics: { first_deployed_to_production_at: nil })
.where("merge_request_metrics.merged_at <= ?", self.created_at) .where("merge_request_metrics.merged_at <= ?", finished_at)
if previous_deployment if previous_deployment
merge_requests = merge_requests.where("merge_request_metrics.merged_at >= ?", previous_deployment.created_at) merge_requests = merge_requests.where("merge_request_metrics.merged_at >= ?", previous_deployment.finished_at)
end end
# Need to use `map` instead of `select` because MySQL doesn't allow `SELECT`ing from the same table # Need to use `map` instead of `select` because MySQL doesn't allow `SELECT`ing from the same table
...@@ -91,7 +125,7 @@ class Deployment < ActiveRecord::Base ...@@ -91,7 +125,7 @@ class Deployment < ActiveRecord::Base
MergeRequest::Metrics MergeRequest::Metrics
.where(merge_request_id: merge_request_ids, first_deployed_to_production_at: nil) .where(merge_request_id: merge_request_ids, first_deployed_to_production_at: nil)
.update_all(first_deployed_to_production_at: self.created_at) .update_all(first_deployed_to_production_at: finished_at)
end end
def previous_deployment def previous_deployment
...@@ -109,8 +143,18 @@ class Deployment < ActiveRecord::Base ...@@ -109,8 +143,18 @@ class Deployment < ActiveRecord::Base
@stop_action ||= manual_actions.find_by(name: on_stop) @stop_action ||= manual_actions.find_by(name: on_stop)
end end
def finished_at
read_attribute(:finished_at) || legacy_finished_at
end
def deployed_at
return unless success?
finished_at
end
def formatted_deployment_time def formatted_deployment_time
created_at.to_time.in_time_zone.to_s(:medium) deployed_at&.to_time&.in_time_zone&.to_s(:medium)
end end
def has_metrics? def has_metrics?
...@@ -118,21 +162,17 @@ class Deployment < ActiveRecord::Base ...@@ -118,21 +162,17 @@ class Deployment < ActiveRecord::Base
end end
def metrics def metrics
return {} unless has_metrics? return {} unless has_metrics? && success?
metrics = prometheus_adapter.query(:deployment, self) metrics = prometheus_adapter.query(:deployment, self)
metrics&.merge(deployment_time: created_at.to_i) || {} metrics&.merge(deployment_time: finished_at.to_i) || {}
end end
def additional_metrics def additional_metrics
return {} unless has_metrics? return {} unless has_metrics? && success?
metrics = prometheus_adapter.query(:additional_metrics_deployment, self) metrics = prometheus_adapter.query(:additional_metrics_deployment, self)
metrics&.merge(deployment_time: created_at.to_i) || {} metrics&.merge(deployment_time: finished_at.to_i) || {}
end
def status
'success'
end end
private private
...@@ -144,4 +184,8 @@ class Deployment < ActiveRecord::Base ...@@ -144,4 +184,8 @@ class Deployment < ActiveRecord::Base
def ref_path def ref_path
File.join(environment.ref_path, 'deployments', iid.to_s) File.join(environment.ref_path, 'deployments', iid.to_s)
end end
def legacy_finished_at
self.created_at if success? && !read_attribute(:finished_at)
end
end end
...@@ -8,9 +8,9 @@ class Environment < ActiveRecord::Base ...@@ -8,9 +8,9 @@ class Environment < ActiveRecord::Base
belongs_to :project, required: true belongs_to :project, required: true
has_many :deployments, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent has_many :deployments, -> { success }, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_one :last_deployment, -> { order('deployments.id DESC') }, class_name: 'Deployment' has_one :last_deployment, -> { success.order('deployments.id DESC') }, class_name: 'Deployment'
before_validation :nullify_external_url before_validation :nullify_external_url
before_validation :generate_slug, if: ->(env) { env.slug.blank? } before_validation :generate_slug, if: ->(env) { env.slug.blank? }
......
...@@ -8,8 +8,8 @@ class EnvironmentStatus ...@@ -8,8 +8,8 @@ class EnvironmentStatus
delegate :id, to: :environment delegate :id, to: :environment
delegate :name, to: :environment delegate :name, to: :environment
delegate :project, to: :environment delegate :project, to: :environment
delegate :deployed_at, to: :deployment, allow_nil: true
delegate :status, to: :deployment delegate :status, to: :deployment
delegate :deployed_at, to: :deployment
def self.for_merge_request(mr, user) def self.for_merge_request(mr, user)
build_environments_status(mr, user, mr.head_pipeline) build_environments_status(mr, user, mr.head_pipeline)
...@@ -33,10 +33,6 @@ class EnvironmentStatus ...@@ -33,10 +33,6 @@ class EnvironmentStatus
end end
end end
def deployed_at
deployment&.created_at
end
def changes def changes
return [] if project.route_map_for(sha).nil? return [] if project.route_map_for(sha).nil?
......
...@@ -254,7 +254,7 @@ class Project < ActiveRecord::Base ...@@ -254,7 +254,7 @@ class Project < ActiveRecord::Base
has_many :variables, class_name: 'Ci::Variable' has_many :variables, class_name: 'Ci::Variable'
has_many :triggers, class_name: 'Ci::Trigger' has_many :triggers, class_name: 'Ci::Trigger'
has_many :environments has_many :environments
has_many :deployments has_many :deployments, -> { success }
has_many :pipeline_schedules, class_name: 'Ci::PipelineSchedule' has_many :pipeline_schedules, class_name: 'Ci::PipelineSchedule'
has_many :project_deploy_tokens has_many :project_deploy_tokens
has_many :deploy_tokens, through: :project_deploy_tokens has_many :deploy_tokens, through: :project_deploy_tokens
......
# frozen_string_literal: true # frozen_string_literal: true
class CreateDeploymentService class UpdateDeploymentService
attr_reader :job attr_reader :deployment
attr_reader :deployable
delegate :expanded_environment_name, delegate :environment, to: :deployment
:variables, delegate :variables, to: :deployable
:project,
to: :job
def initialize(job) def initialize(deployment)
@job = job @deployment = deployment
@deployable = deployment.deployable
end end
def execute def execute
return unless executable? deployment.create_ref
deployment.invalidate_cache
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
environment.external_url = expanded_environment_url if environment.external_url = expanded_environment_url if
...@@ -24,50 +25,28 @@ class CreateDeploymentService ...@@ -24,50 +25,28 @@ class CreateDeploymentService
break unless environment.save break unless environment.save
break if environment.stopped? break if environment.stopped?
deploy.tap(&:update_merge_request_metrics!) deployment.tap(&:update_merge_request_metrics!)
end end
end end
private private
def executable?
project && job.environment.present? && environment
end
def deploy
project.deployments.create(
environment: environment,
ref: job.ref,
tag: job.tag,
sha: job.sha,
user: job.user,
deployable: job,
on_stop: on_stop)
end
def environment
@environment ||= job.persisted_environment
end
def environment_options def environment_options
@environment_options ||= job.options&.dig(:environment) || {} @environment_options ||= deployable.options&.dig(:environment) || {}
end end
def expanded_environment_url def expanded_environment_url
return @expanded_environment_url if defined?(@expanded_environment_url) return @expanded_environment_url if defined?(@expanded_environment_url)
return unless environment_url
@expanded_environment_url = @expanded_environment_url =
ExpandVariables.expand(environment_url, variables) if environment_url ExpandVariables.expand(environment_url, variables)
end end
def environment_url def environment_url
environment_options[:url] environment_options[:url]
end end
def on_stop
environment_options[:on_stop]
end
def action def action
environment_options[:action] || 'start' environment_options[:action] || 'start'
end end
......
...@@ -73,6 +73,8 @@ ...@@ -73,6 +73,8 @@
- pipeline_processing:update_head_pipeline_for_merge_request - pipeline_processing:update_head_pipeline_for_merge_request
- pipeline_processing:ci_build_schedule - pipeline_processing:ci_build_schedule
- deployment:deployments_success
- repository_check:repository_check_clear - repository_check:repository_check_clear
- repository_check:repository_check_batch - repository_check:repository_check_batch
- repository_check:repository_check_single_repository - repository_check:repository_check_single_repository
......
...@@ -16,7 +16,14 @@ class BuildSuccessWorker ...@@ -16,7 +16,14 @@ class BuildSuccessWorker
private private
##
# Deprecated:
# As of 11.5, we started creating a deployment record when ci_builds record is created.
# Therefore we no longer need to create a deployment, after a build succeeded.
# We're leaving this code for the transition period, but we can remove this code in 11.6.
def create_deployment(build) def create_deployment(build)
CreateDeploymentService.new(build).execute build.create_deployment.try do |deployment|
deployment.succeed
end
end end
end end
# frozen_string_literal: true
module Deployments
class SuccessWorker
include ApplicationWorker
queue_namespace :deployment
def perform(deployment_id)
Deployment.find_by_id(deployment_id).try do |deployment|
break unless deployment.success?
UpdateDeploymentService.new(deployment).execute
end
end
end
end
---
title: Add status to Deployment
merge_request: 22380
author:
type: changed
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
- [pipeline_creation, 4] - [pipeline_creation, 4]
- [pipeline_default, 3] - [pipeline_default, 3]
- [pipeline_cache, 3] - [pipeline_cache, 3]
- [deployment, 3]
- [pipeline_hooks, 2] - [pipeline_hooks, 2]
- [gitlab_shell, 2] - [gitlab_shell, 2]
- [email_receiver, 2] - [email_receiver, 2]
......
...@@ -180,11 +180,8 @@ class Gitlab::Seeder::CycleAnalytics ...@@ -180,11 +180,8 @@ class Gitlab::Seeder::CycleAnalytics
ref: "refs/heads/#{merge_request.source_branch}") ref: "refs/heads/#{merge_request.source_branch}")
pipeline = service.execute(:push, ignore_skip_ci: true, save_on_errors: false) pipeline = service.execute(:push, ignore_skip_ci: true, save_on_errors: false)
pipeline.run! pipeline.builds.map(&:run!)
Timecop.travel rand(1..6).hours.from_now pipeline.update_status
pipeline.succeed!
PipelineMetricsWorker.new.perform(pipeline.id)
end end
end end
...@@ -204,7 +201,8 @@ class Gitlab::Seeder::CycleAnalytics ...@@ -204,7 +201,8 @@ class Gitlab::Seeder::CycleAnalytics
job = merge_request.head_pipeline.builds.where.not(environment: nil).last job = merge_request.head_pipeline.builds.where.not(environment: nil).last
CreateDeploymentService.new(job).execute job.success!
pipeline.update_status
end end
end end
end end
......
# frozen_string_literal: true
class AddFinishedAtToDeployments < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
add_column :deployments, :finished_at, :datetime_with_timezone
end
def down
remove_column :deployments, :finished_at, :datetime_with_timezone
end
end
# frozen_string_literal: true
class AddStatusToDeployments < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DEPLOYMENT_STATUS_SUCCESS = 2 # Equivalent to Deployment.state_machine.states['success'].value
DOWNTIME = false
disable_ddl_transaction!
##
# NOTE:
# Ideally, `status` column should not have default value because it should be leveraged by state machine (i.e. application level).
# However, we have to use the default value for avoiding `NOT NULL` violation during the transition period.
# The default value should be removed in the future release.
def up
add_column_with_default(:deployments,
:status,
:integer,
limit: 2,
default: DEPLOYMENT_STATUS_SUCCESS,
allow_null: false)
end
def down
remove_column(:deployments, :status)
end
end
# frozen_string_literal: true
class AddIndexOnStatusToDeployments < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :deployments, [:project_id, :status]
add_concurrent_index :deployments, [:environment_id, :status]
end
def down
remove_concurrent_index :deployments, [:project_id, :status]
remove_concurrent_index :deployments, [:environment_id, :status]
end
end
# frozen_string_literal: true
class AddPartialIndexForLegacySuccessfulDeployments < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
INDEX_NAME = 'partial_index_deployments_for_legacy_successful_deployments'.freeze
disable_ddl_transaction!
def up
add_concurrent_index(:deployments, :id, where: "finished_at IS NULL AND status = 2", name: INDEX_NAME)
end
def down
remove_concurrent_index_by_name(:deployments, INDEX_NAME)
end
end
# frozen_string_literal: true
class FillEmptyFinishedAtInDeployments < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
DEPLOYMENT_STATUS_SUCCESS = 2 # Equivalent to Deployment.statuses[:success]
class Deployments < ActiveRecord::Base
self.table_name = 'deployments'
include EachBatch
end
def up
FillEmptyFinishedAtInDeployments::Deployments
.where('finished_at IS NULL')
.where('status = ?', DEPLOYMENT_STATUS_SUCCESS)
.each_batch(of: 10_000) do |relation|
relation.update_all('finished_at=created_at')
end
end
def down
# no-op
end
end
...@@ -825,13 +825,18 @@ ActiveRecord::Schema.define(version: 20181101144347) do ...@@ -825,13 +825,18 @@ ActiveRecord::Schema.define(version: 20181101144347) do
t.datetime "created_at" t.datetime "created_at"
t.datetime "updated_at" t.datetime "updated_at"
t.string "on_stop" t.string "on_stop"
t.integer "status", limit: 2, default: 2, null: false
t.datetime_with_timezone "finished_at"
end end
add_index "deployments", ["created_at"], name: "index_deployments_on_created_at", using: :btree add_index "deployments", ["created_at"], name: "index_deployments_on_created_at", using: :btree
add_index "deployments", ["deployable_type", "deployable_id"], name: "index_deployments_on_deployable_type_and_deployable_id", using: :btree add_index "deployments", ["deployable_type", "deployable_id"], name: "index_deployments_on_deployable_type_and_deployable_id", using: :btree
add_index "deployments", ["environment_id", "id"], name: "index_deployments_on_environment_id_and_id", using: :btree add_index "deployments", ["environment_id", "id"], name: "index_deployments_on_environment_id_and_id", using: :btree
add_index "deployments", ["environment_id", "iid", "project_id"], name: "index_deployments_on_environment_id_and_iid_and_project_id", using: :btree add_index "deployments", ["environment_id", "iid", "project_id"], name: "index_deployments_on_environment_id_and_iid_and_project_id", using: :btree
add_index "deployments", ["environment_id", "status"], name: "index_deployments_on_environment_id_and_status", using: :btree
add_index "deployments", ["id"], name: "partial_index_deployments_for_legacy_successful_deployments", where: "((finished_at IS NULL) AND (status = 2))", using: :btree
add_index "deployments", ["project_id", "iid"], name: "index_deployments_on_project_id_and_iid", unique: true, using: :btree add_index "deployments", ["project_id", "iid"], name: "index_deployments_on_project_id_and_iid", unique: true, using: :btree
add_index "deployments", ["project_id", "status"], name: "index_deployments_on_project_id_and_status", using: :btree
create_table "emails", force: :cascade do |t| create_table "emails", force: :cascade do |t|
t.integer "user_id", null: false t.integer "user_id", null: false
......
...@@ -7,26 +7,11 @@ module Gitlab ...@@ -7,26 +7,11 @@ module Gitlab
class Create < Chain::Base class Create < Chain::Base
include Chain::Helpers include Chain::Helpers
# rubocop: disable CodeReuse/ActiveRecord
def perform! def perform!
::Ci::Pipeline.transaction do
pipeline.save! pipeline.save!
##
# Create environments before the pipeline starts.
#
pipeline.builds.each do |build|
if build.has_environment?
project.environments.find_or_create_by(
name: build.expanded_environment_name
)
end
end
end
rescue ActiveRecord::RecordInvalid => e rescue ActiveRecord::RecordInvalid => e
error("Failed to persist the pipeline: #{e}") error("Failed to persist the pipeline: #{e}")
end end
# rubocop: enable CodeReuse/ActiveRecord
def break? def break?
!pipeline.persisted? !pipeline.persisted?
......
...@@ -15,9 +15,9 @@ describe Projects::DeploymentsController do ...@@ -15,9 +15,9 @@ describe Projects::DeploymentsController do
describe 'GET #index' do describe 'GET #index' do
it 'returns list of deployments from last 8 hours' do it 'returns list of deployments from last 8 hours' do
create(:deployment, environment: environment, created_at: 9.hours.ago) create(:deployment, :success, environment: environment, created_at: 9.hours.ago)
create(:deployment, environment: environment, created_at: 7.hours.ago) create(:deployment, :success, environment: environment, created_at: 7.hours.ago)
create(:deployment, environment: environment) create(:deployment, :success, environment: environment)
get :index, deployment_params(after: 8.hours.ago) get :index, deployment_params(after: 8.hours.ago)
...@@ -27,7 +27,7 @@ describe Projects::DeploymentsController do ...@@ -27,7 +27,7 @@ describe Projects::DeploymentsController do
end end
it 'returns a list with deployments information' do it 'returns a list with deployments information' do
create(:deployment, environment: environment) create(:deployment, :success, environment: environment)
get :index, deployment_params get :index, deployment_params
...@@ -37,7 +37,7 @@ describe Projects::DeploymentsController do ...@@ -37,7 +37,7 @@ describe Projects::DeploymentsController do
end end
describe 'GET #metrics' do describe 'GET #metrics' do
let(:deployment) { create(:deployment, project: project, environment: environment) } let(:deployment) { create(:deployment, :success, project: project, environment: environment) }
before do before do
allow(controller).to receive(:deployment).and_return(deployment) allow(controller).to receive(:deployment).and_return(deployment)
...@@ -110,7 +110,7 @@ describe Projects::DeploymentsController do ...@@ -110,7 +110,7 @@ describe Projects::DeploymentsController do
end end
describe 'GET #additional_metrics' do describe 'GET #additional_metrics' do
let(:deployment) { create(:deployment, project: project, environment: environment) } let(:deployment) { create(:deployment, :success, project: project, environment: environment) }
before do before do
allow(controller).to receive(:deployment).and_return(deployment) allow(controller).to receive(:deployment).and_return(deployment)
......
...@@ -231,7 +231,7 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do ...@@ -231,7 +231,7 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do
context 'with deployment' do context 'with deployment' do
let(:merge_request) { create(:merge_request, source_project: project) } let(:merge_request) { create(:merge_request, source_project: project) }
let(:environment) { create(:environment, project: project, name: 'staging', state: :available) } let(:environment) { create(:environment, project: project, name: 'staging', state: :available) }
let(:job) { create(:ci_build, :success, environment: environment.name, pipeline: pipeline) } let(:job) { create(:ci_build, :running, environment: environment.name, pipeline: pipeline) }
it 'exposes the deployment information' do it 'exposes the deployment information' do
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
......
...@@ -755,7 +755,7 @@ describe Projects::MergeRequestsController do ...@@ -755,7 +755,7 @@ describe Projects::MergeRequestsController do
let(:environment) { create(:environment, project: forked) } let(:environment) { create(:environment, project: forked) }
let(:pipeline) { create(:ci_pipeline, sha: sha, project: forked) } let(:pipeline) { create(:ci_pipeline, sha: sha, project: forked) }
let(:build) { create(:ci_build, pipeline: pipeline) } let(:build) { create(:ci_build, pipeline: pipeline) }
let!(:deployment) { create(:deployment, environment: environment, sha: sha, ref: 'master', deployable: build) } let!(:deployment) { create(:deployment, :succeed, environment: environment, sha: sha, ref: 'master', deployable: build) }
let(:merge_request) do let(:merge_request) do
create(:merge_request, source_project: forked, target_project: project, target_branch: 'master', head_pipeline: pipeline) create(:merge_request, source_project: forked, target_project: project, target_branch: 'master', head_pipeline: pipeline)
...@@ -780,7 +780,7 @@ describe Projects::MergeRequestsController do ...@@ -780,7 +780,7 @@ describe Projects::MergeRequestsController do
let(:merge_commit_sha) { project.repository.merge(user, forked.commit.id, merge_request, "merged in test") } let(:merge_commit_sha) { project.repository.merge(user, forked.commit.id, merge_request, "merged in test") }
let(:post_merge_pipeline) { create(:ci_pipeline, sha: merge_commit_sha, project: project) } let(:post_merge_pipeline) { create(:ci_pipeline, sha: merge_commit_sha, project: project) }
let(:post_merge_build) { create(:ci_build, pipeline: post_merge_pipeline) } let(:post_merge_build) { create(:ci_build, pipeline: post_merge_pipeline) }
let!(:source_deployment) { create(:deployment, environment: source_environment, sha: merge_commit_sha, ref: 'master', deployable: post_merge_build) } let!(:source_deployment) { create(:deployment, :succeed, environment: source_environment, sha: merge_commit_sha, ref: 'master', deployable: post_merge_build) }
before do before do
merge_request.update!(merge_commit_sha: merge_commit_sha) merge_request.update!(merge_commit_sha: merge_commit_sha)
......
...@@ -100,6 +100,30 @@ FactoryBot.define do ...@@ -100,6 +100,30 @@ FactoryBot.define do
url: 'http://staging.example.com/$CI_JOB_NAME' } url: 'http://staging.example.com/$CI_JOB_NAME' }
end end
trait :deploy_to_production do
environment 'production'
options environment: { name: 'production',
url: 'http://prd.example.com/$CI_JOB_NAME' }
end
trait :start_review_app do
environment 'review/$CI_COMMIT_REF_NAME'
options environment: { name: 'review/$CI_COMMIT_REF_NAME',
url: 'http://staging.example.com/$CI_JOB_NAME',
on_stop: 'stop_review_app' }
end
trait :stop_review_app do
name 'stop_review_app'
environment 'review/$CI_COMMIT_REF_NAME'
options environment: { name: 'review/$CI_COMMIT_REF_NAME',
url: 'http://staging.example.com/$CI_JOB_NAME',
action: 'stop' }
end
trait :allowed_to_fail do trait :allowed_to_fail do
allow_failure true allow_failure true
end end
......
...@@ -21,5 +21,31 @@ FactoryBot.define do ...@@ -21,5 +21,31 @@ FactoryBot.define do
sha { TestEnv::BRANCH_SHA['pages-deploy'] } sha { TestEnv::BRANCH_SHA['pages-deploy'] }
ref 'pages-deploy' ref 'pages-deploy'
end end
trait :running do
status :running
end
trait :success do
status :success
finished_at { Time.now }
end
trait :failed do
status :failed
finished_at { Time.now }
end
trait :canceled do
status :canceled
finished_at { Time.now }
end
# This trait hooks the state maechine's events
trait :succeed do
after(:create) do |deployment, evaluator|
deployment.succeed!
end
end
end end
end end
...@@ -22,6 +22,7 @@ FactoryBot.define do ...@@ -22,6 +22,7 @@ FactoryBot.define do
pipeline: pipeline) pipeline: pipeline)
deployment = create(:deployment, deployment = create(:deployment,
:success,
environment: environment, environment: environment,
project: environment.project, project: environment.project,
deployable: deployable, deployable: deployable,
......
...@@ -11,7 +11,7 @@ describe 'Merge request > User sees deployment widget', :js do ...@@ -11,7 +11,7 @@ describe 'Merge request > User sees deployment widget', :js do
let(:sha) { project.commit(ref).id } let(:sha) { project.commit(ref).id }
let(:pipeline) { create(:ci_pipeline_without_jobs, sha: sha, project: project, ref: ref) } let(:pipeline) { create(:ci_pipeline_without_jobs, sha: sha, project: project, ref: ref) }
let(:build) { create(:ci_build, :success, pipeline: pipeline) } let(:build) { create(:ci_build, :success, pipeline: pipeline) }
let!(:deployment) { create(:deployment, environment: environment, sha: sha, ref: ref, deployable: build) } let!(:deployment) { create(:deployment, :succeed, environment: environment, sha: sha, ref: ref, deployable: build) }
let!(:manual) { } let!(:manual) { }
before do before do
......
...@@ -45,7 +45,8 @@ describe 'Merge request > User sees merge widget', :js do ...@@ -45,7 +45,8 @@ describe 'Merge request > User sees merge widget', :js do
let(:build) { create(:ci_build, :success, pipeline: pipeline) } let(:build) { create(:ci_build, :success, pipeline: pipeline) }
let!(:deployment) do let!(:deployment) do
create(:deployment, environment: environment, create(:deployment, :succeed,
environment: environment,
ref: merge_request.source_branch, ref: merge_request.source_branch,
deployable: build, deployable: build,
sha: sha) sha: sha)
......
...@@ -33,7 +33,7 @@ describe 'Environment' do ...@@ -33,7 +33,7 @@ describe 'Environment' do
context 'with deployments' do context 'with deployments' do
context 'when there is no related deployable' do context 'when there is no related deployable' do
let(:deployment) do let(:deployment) do
create(:deployment, environment: environment, deployable: nil) create(:deployment, :success, environment: environment, deployable: nil)
end end
it 'does show deployment SHA' do it 'does show deployment SHA' do
...@@ -48,7 +48,7 @@ describe 'Environment' do ...@@ -48,7 +48,7 @@ describe 'Environment' do
let(:build) { create(:ci_build, pipeline: pipeline) } let(:build) { create(:ci_build, pipeline: pipeline) }
let(:deployment) do let(:deployment) do
create(:deployment, environment: environment, deployable: build) create(:deployment, :success, environment: environment, deployable: build)
end end
it 'does show build name' do it 'does show build name' do
...@@ -108,7 +108,7 @@ describe 'Environment' do ...@@ -108,7 +108,7 @@ describe 'Environment' do
context 'with external_url' do context 'with external_url' do
let(:environment) { create(:environment, project: project, external_url: 'https://git.gitlab.com') } let(:environment) { create(:environment, project: project, external_url: 'https://git.gitlab.com') }
let(:build) { create(:ci_build, pipeline: pipeline) } let(:build) { create(:ci_build, pipeline: pipeline) }
let(:deployment) { create(:deployment, environment: environment, deployable: build) } let(:deployment) { create(:deployment, :success, environment: environment, deployable: build) }
it 'does show an external link button' do it 'does show an external link button' do
expect(page).to have_link(nil, href: environment.external_url) expect(page).to have_link(nil, href: environment.external_url)
...@@ -169,7 +169,8 @@ describe 'Environment' do ...@@ -169,7 +169,8 @@ describe 'Environment' do
end end
let(:deployment) do let(:deployment) do
create(:deployment, environment: environment, create(:deployment, :success,
environment: environment,
deployable: build, deployable: build,
on_stop: 'close_app') on_stop: 'close_app')
end end
......
...@@ -132,7 +132,8 @@ describe 'Environments page', :js do ...@@ -132,7 +132,8 @@ describe 'Environments page', :js do
let(:project) { create(:project, :repository) } let(:project) { create(:project, :repository) }
let!(:deployment) do let!(:deployment) do
create(:deployment, environment: environment, create(:deployment, :success,
environment: environment,
sha: project.commit.id) sha: project.commit.id)
end end
...@@ -152,7 +153,8 @@ describe 'Environments page', :js do ...@@ -152,7 +153,8 @@ describe 'Environments page', :js do
end end
let!(:deployment) do let!(:deployment) do
create(:deployment, environment: environment, create(:deployment, :success,
environment: environment,
deployable: build, deployable: build,
sha: project.commit.id) sha: project.commit.id)
end end
...@@ -196,7 +198,7 @@ describe 'Environments page', :js do ...@@ -196,7 +198,7 @@ describe 'Environments page', :js do
context 'with external_url' do context 'with external_url' do
let(:environment) { create(:environment, project: project, external_url: 'https://git.gitlab.com') } let(:environment) { create(:environment, project: project, external_url: 'https://git.gitlab.com') }
let(:build) { create(:ci_build, pipeline: pipeline) } let(:build) { create(:ci_build, pipeline: pipeline) }
let(:deployment) { create(:deployment, environment: environment, deployable: build) } let(:deployment) { create(:deployment, :success, environment: environment, deployable: build) }
it 'shows an external link button' do it 'shows an external link button' do
expect(page).to have_link(nil, href: environment.external_url) expect(page).to have_link(nil, href: environment.external_url)
...@@ -209,7 +211,8 @@ describe 'Environments page', :js do ...@@ -209,7 +211,8 @@ describe 'Environments page', :js do
end end
let(:deployment) do let(:deployment) do
create(:deployment, environment: environment, create(:deployment, :success,
environment: environment,
deployable: build, deployable: build,
on_stop: 'close_app') on_stop: 'close_app')
end end
......
...@@ -396,8 +396,8 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do ...@@ -396,8 +396,8 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
end end
context 'job is successful and has deployment' do context 'job is successful and has deployment' do
let(:build) { create(:ci_build, :success, :trace_live, environment: environment.name, pipeline: pipeline) } let(:build) { create(:ci_build, :success, :trace_live, environment: environment.name, pipeline: pipeline, deployment: deployment) }
let!(:deployment) { create(:deployment, environment: environment, project: environment.project, deployable: build) } let(:deployment) { create(:deployment, :success, environment: environment, project: environment.project) }
it 'shows a link for the job' do it 'shows a link for the job' do
expect(page).to have_link environment.name expect(page).to have_link environment.name
...@@ -419,7 +419,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do ...@@ -419,7 +419,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
end end
context 'deployment still not finished' do context 'deployment still not finished' do
let(:build) { create(:ci_build, :success, environment: environment.name, pipeline: pipeline) } let(:build) { create(:ci_build, :running, environment: environment.name, pipeline: pipeline) }
it 'shows a link to latest deployment' do it 'shows a link to latest deployment' do
expect(page).to have_link environment.name expect(page).to have_link environment.name
...@@ -456,6 +456,8 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do ...@@ -456,6 +456,8 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
describe 'environment info in job view', :js do describe 'environment info in job view', :js do
before do before do
allow_any_instance_of(Ci::Build).to receive(:create_deployment)
visit project_job_path(project, job) visit project_job_path(project, job)
wait_for_requests wait_for_requests
end end
...@@ -464,8 +466,8 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do ...@@ -464,8 +466,8 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
let(:job) { create(:ci_build, :success, :trace_artifact, environment: 'staging', pipeline: pipeline) } let(:job) { create(:ci_build, :success, :trace_artifact, environment: 'staging', pipeline: pipeline) }
let(:second_build) { create(:ci_build, :success, :trace_artifact, environment: 'staging', pipeline: pipeline) } let(:second_build) { create(:ci_build, :success, :trace_artifact, environment: 'staging', pipeline: pipeline) }
let(:environment) { create(:environment, name: 'staging', project: project) } let(:environment) { create(:environment, name: 'staging', project: project) }
let!(:first_deployment) { create(:deployment, environment: environment, deployable: job) } let!(:first_deployment) { create(:deployment, :success, environment: environment, deployable: job) }
let!(:second_deployment) { create(:deployment, environment: environment, deployable: second_build) } let!(:second_deployment) { create(:deployment, :success, environment: environment, deployable: second_build) }
it 'shows deployment message' do it 'shows deployment message' do
expected_text = 'This job is an out-of-date deployment ' \ expected_text = 'This job is an out-of-date deployment ' \
...@@ -505,7 +507,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do ...@@ -505,7 +507,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
end end
context 'when it has deployment' do context 'when it has deployment' do
let!(:deployment) { create(:deployment, environment: environment) } let!(:deployment) { create(:deployment, :success, environment: environment) }
it 'shows that deployment will be overwritten' do it 'shows that deployment will be overwritten' do
expected_text = 'This job is creating a deployment to staging' expected_text = 'This job is creating a deployment to staging'
......
...@@ -44,7 +44,7 @@ describe 'View on environment', :js do ...@@ -44,7 +44,7 @@ describe 'View on environment', :js do
context 'and an active deployment' do context 'and an active deployment' do
let(:sha) { project.commit(branch_name).sha } let(:sha) { project.commit(branch_name).sha }
let(:environment) { create(:environment, project: project, name: 'review/feature', external_url: 'http://feature.review.example.com') } let(:environment) { create(:environment, project: project, name: 'review/feature', external_url: 'http://feature.review.example.com') }
let!(:deployment) { create(:deployment, environment: environment, ref: branch_name, sha: sha) } let!(:deployment) { create(:deployment, :success, environment: environment, ref: branch_name, sha: sha) }
context 'when visiting the diff of a merge request for the branch' do context 'when visiting the diff of a merge request for the branch' do
let(:merge_request) { create(:merge_request, :simple, source_project: project, source_branch: branch_name) } let(:merge_request) { create(:merge_request, :simple, source_project: project, source_branch: branch_name) }
......
...@@ -12,7 +12,7 @@ describe EnvironmentsFinder do ...@@ -12,7 +12,7 @@ describe EnvironmentsFinder do
context 'tagged deployment' do context 'tagged deployment' do
before do before do
create(:deployment, environment: environment, ref: 'v1.1.0', tag: true, sha: project.commit.id) create(:deployment, :success, environment: environment, ref: 'v1.1.0', tag: true, sha: project.commit.id)
end end
it 'returns environment when with_tags is set' do it 'returns environment when with_tags is set' do
...@@ -33,7 +33,7 @@ describe EnvironmentsFinder do ...@@ -33,7 +33,7 @@ describe EnvironmentsFinder do
context 'branch deployment' do context 'branch deployment' do
before do before do
create(:deployment, environment: environment, ref: 'master', sha: project.commit.id) create(:deployment, :success, environment: environment, ref: 'master', sha: project.commit.id)
end end
it 'returns environment when ref is set' do it 'returns environment when ref is set' do
...@@ -59,7 +59,7 @@ describe EnvironmentsFinder do ...@@ -59,7 +59,7 @@ describe EnvironmentsFinder do
context 'commit deployment' do context 'commit deployment' do
before do before do
create(:deployment, environment: environment, ref: 'master', sha: project.commit.id) create(:deployment, :success, environment: environment, ref: 'master', sha: project.commit.id)
end end
it 'returns environment' do it 'returns environment' do
...@@ -71,7 +71,7 @@ describe EnvironmentsFinder do ...@@ -71,7 +71,7 @@ describe EnvironmentsFinder do
context 'recently updated' do context 'recently updated' do
context 'when last deployment to environment is the most recent one' do context 'when last deployment to environment is the most recent one' do
before do before do
create(:deployment, environment: environment, ref: 'feature') create(:deployment, :success, environment: environment, ref: 'feature')
end end
it 'finds recently updated environment' do it 'finds recently updated environment' do
...@@ -82,8 +82,8 @@ describe EnvironmentsFinder do ...@@ -82,8 +82,8 @@ describe EnvironmentsFinder do
context 'when last deployment to environment is not the most recent' do context 'when last deployment to environment is not the most recent' do
before do before do
create(:deployment, environment: environment, ref: 'feature') create(:deployment, :success, environment: environment, ref: 'feature')
create(:deployment, environment: environment, ref: 'master') create(:deployment, :success, environment: environment, ref: 'master')
end end
it 'does not find environment' do it 'does not find environment' do
...@@ -96,8 +96,8 @@ describe EnvironmentsFinder do ...@@ -96,8 +96,8 @@ describe EnvironmentsFinder do
let(:second_environment) { create(:environment, project: project) } let(:second_environment) { create(:environment, project: project) }
before do before do
create(:deployment, environment: environment, ref: 'feature') create(:deployment, :success, environment: environment, ref: 'feature')
create(:deployment, environment: second_environment, ref: 'feature') create(:deployment, :success, environment: second_environment, ref: 'feature')
end end
it 'finds both environments' do it 'finds both environments' do
......
...@@ -44,15 +44,15 @@ describe Gitlab::CycleAnalytics::StageSummary do ...@@ -44,15 +44,15 @@ describe Gitlab::CycleAnalytics::StageSummary do
describe "#deploys" do describe "#deploys" do
it "finds the number of deploys made created after the 'from date'" do it "finds the number of deploys made created after the 'from date'" do
Timecop.freeze(5.days.ago) { create(:deployment, project: project) } Timecop.freeze(5.days.ago) { create(:deployment, :success, project: project) }
Timecop.freeze(5.days.from_now) { create(:deployment, project: project) } Timecop.freeze(5.days.from_now) { create(:deployment, :success, project: project) }
expect(subject.third[:value]).to eq(1) expect(subject.third[:value]).to eq(1)
end end
it "doesn't find commits from other projects" do it "doesn't find commits from other projects" do
Timecop.freeze(5.days.from_now) do Timecop.freeze(5.days.from_now) do
create(:deployment, project: create(:project, :repository)) create(:deployment, :success, project: create(:project, :repository))
end end
expect(subject.third[:value]).to eq(0) expect(subject.third[:value]).to eq(0)
......
...@@ -44,7 +44,7 @@ describe Gitlab::SlashCommands::Command do ...@@ -44,7 +44,7 @@ describe Gitlab::SlashCommands::Command do
let!(:build) { create(:ci_build, pipeline: pipeline) } let!(:build) { create(:ci_build, pipeline: pipeline) }
let!(:pipeline) { create(:ci_pipeline, project: project) } let!(:pipeline) { create(:ci_pipeline, project: project) }
let!(:staging) { create(:environment, name: 'staging', project: project) } let!(:staging) { create(:environment, name: 'staging', project: project) }
let!(:deployment) { create(:deployment, environment: staging, deployable: build) } let!(:deployment) { create(:deployment, :success, environment: staging, deployable: build) }
let!(:manual) do let!(:manual) do
create(:ci_build, :manual, pipeline: pipeline, create(:ci_build, :manual, pipeline: pipeline,
......
...@@ -31,7 +31,7 @@ describe Gitlab::SlashCommands::Deploy do ...@@ -31,7 +31,7 @@ describe Gitlab::SlashCommands::Deploy do
let!(:staging) { create(:environment, name: 'staging', project: project) } let!(:staging) { create(:environment, name: 'staging', project: project) }
let!(:pipeline) { create(:ci_pipeline, project: project) } let!(:pipeline) { create(:ci_pipeline, project: project) }
let!(:build) { create(:ci_build, pipeline: pipeline) } let!(:build) { create(:ci_build, pipeline: pipeline) }
let!(:deployment) { create(:deployment, environment: staging, deployable: build) } let!(:deployment) { create(:deployment, :success, environment: staging, deployable: build) }
context 'without actions' do context 'without actions' do
it 'does not execute an action' do it 'does not execute an action' do
......
...@@ -65,6 +65,21 @@ describe DeleteInconsistentInternalIdRecords, :migration do ...@@ -65,6 +65,21 @@ describe DeleteInconsistentInternalIdRecords, :migration do
context 'for deployments' do context 'for deployments' do
let(:scope) { :deployment } let(:scope) { :deployment }
let(:deployments) { table(:deployments) }
let(:internal_ids) { table(:internal_ids) }
before do
internal_ids.create!(project_id: project1.id, usage: 2, last_value: 2)
internal_ids.create!(project_id: project2.id, usage: 2, last_value: 2)
internal_ids.create!(project_id: project3.id, usage: 2, last_value: 2)
end
let(:create_models) do
3.times { |i| deployments.create!(project_id: project1.id, iid: i, environment_id: 1, ref: 'master', sha: 'a', tag: false) }
3.times { |i| deployments.create!(project_id: project2.id, iid: i, environment_id: 1, ref: 'master', sha: 'a', tag: false) }
3.times { |i| deployments.create!(project_id: project3.id, iid: i, environment_id: 1, ref: 'master', sha: 'a', tag: false) }
end
it_behaves_like 'deleting inconsistent internal_id records' it_behaves_like 'deleting inconsistent internal_id records'
end end
......
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20181030135124_fill_empty_finished_at_in_deployments')
describe FillEmptyFinishedAtInDeployments, :migration do
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:environments) { table(:environments) }
let(:deployments) { table(:deployments) }
context 'when a deployment row does not have a value on finished_at' do
context 'when a deployment succeeded' do
before do
namespaces.create!(id: 123, name: 'gitlab1', path: 'gitlab1')
projects.create!(id: 1, name: 'gitlab1', path: 'gitlab1', namespace_id: 123)
environments.create!(id: 1, name: 'production', slug: 'production', project_id: 1)
deployments.create!(id: 1, iid: 1, project_id: 1, environment_id: 1, ref: 'master', sha: 'xxx', tag: false)
end
it 'correctly replicates finished_at by created_at' do
expect(deployments.last.created_at).not_to be_nil
expect(deployments.last.finished_at).to be_nil
migrate!
expect(deployments.last.created_at).not_to be_nil
expect(deployments.last.finished_at).to eq(deployments.last.created_at)
end
end
context 'when a deployment is running' do
before do
namespaces.create!(id: 123, name: 'gitlab1', path: 'gitlab1')
projects.create!(id: 1, name: 'gitlab1', path: 'gitlab1', namespace_id: 123)
environments.create!(id: 1, name: 'production', slug: 'production', project_id: 1)
deployments.create!(id: 1, iid: 1, project_id: 1, environment_id: 1, ref: 'master', sha: 'xxx', tag: false, status: 1)
end
it 'does not fill finished_at' do
expect(deployments.last.created_at).not_to be_nil
expect(deployments.last.finished_at).to be_nil
migrate!
expect(deployments.last.created_at).not_to be_nil
expect(deployments.last.finished_at).to be_nil
end
end
end
context 'when a deployment row does has a value on finished_at' do
let(:finished_at) { '2018-10-30 11:12:02 UTC' }
before do
namespaces.create!(id: 123, name: 'gitlab1', path: 'gitlab1')
projects.create!(id: 1, name: 'gitlab1', path: 'gitlab1', namespace_id: 123)
environments.create!(id: 1, name: 'production', slug: 'production', project_id: 1)
deployments.create!(id: 1, iid: 1, project_id: 1, environment_id: 1, ref: 'master', sha: 'xxx', tag: false, finished_at: finished_at)
end
it 'does not affect existing value' do
expect(deployments.last.created_at).not_to be_nil
expect(deployments.last.finished_at).not_to be_nil
migrate!
expect(deployments.last.created_at).not_to be_nil
expect(deployments.last.finished_at).to eq(finished_at)
end
end
end
...@@ -17,8 +17,8 @@ describe Ci::Build do ...@@ -17,8 +17,8 @@ describe Ci::Build do
it { is_expected.to belong_to(:runner) } it { is_expected.to belong_to(:runner) }
it { is_expected.to belong_to(:trigger_request) } it { is_expected.to belong_to(:trigger_request) }
it { is_expected.to belong_to(:erased_by) } it { is_expected.to belong_to(:erased_by) }
it { is_expected.to have_many(:deployments) }
it { is_expected.to have_many(:trace_sections)} it { is_expected.to have_many(:trace_sections)}
it { is_expected.to have_one(:deployment) }
it { is_expected.to have_one(:runner_session)} it { is_expected.to have_one(:runner_session)}
it { is_expected.to validate_presence_of(:ref) } it { is_expected.to validate_presence_of(:ref) }
it { is_expected.to respond_to(:has_trace?) } it { is_expected.to respond_to(:has_trace?) }
...@@ -799,17 +799,100 @@ describe Ci::Build do ...@@ -799,17 +799,100 @@ describe Ci::Build do
end end
end end
describe 'state transition as a deployable' do
let!(:build) { create(:ci_build, :start_review_app) }
let(:deployment) { build.deployment }
let(:environment) { deployment.environment }
it 'has deployments record with created status' do
expect(deployment).to be_created
expect(environment.name).to eq('review/master')
end
context 'when transits to running' do
before do
build.run!
end
it 'transits deployment status to running' do
expect(deployment).to be_running
end
end
context 'when transits to success' do
before do
allow(Deployments::SuccessWorker).to receive(:perform_async)
build.success!
end
it 'transits deployment status to success' do
expect(deployment).to be_success
end
end
context 'when transits to failed' do
before do
build.drop!
end
it 'transits deployment status to failed' do
expect(deployment).to be_failed
end
end
context 'when transits to skipped' do
before do
build.skip!
end
it 'transits deployment status to canceled' do
expect(deployment).to be_canceled
end
end
context 'when transits to canceled' do
before do
build.cancel!
end
it 'transits deployment status to canceled' do
expect(deployment).to be_canceled
end
end
end
describe '#on_stop' do
subject { build.on_stop }
context 'when a job has a specification that it can be stopped from the other job' do
let(:build) { create(:ci_build, :start_review_app) }
it 'returns the other job name' do
is_expected.to eq('stop_review_app')
end
end
context 'when a job does not have environment information' do
let(:build) { create(:ci_build) }
it 'returns nil' do
is_expected.to be_nil
end
end
end
describe 'deployment' do describe 'deployment' do
describe '#last_deployment' do describe '#has_deployment?' do
subject { build.last_deployment } subject { build.has_deployment? }
context 'when multiple deployments are created' do context 'when build has a deployment' do
let!(:deployment1) { create(:deployment, deployable: build) } let!(:deployment) { create(:deployment, deployable: build) }
let!(:deployment2) { create(:deployment, deployable: build) }
it 'returns the latest one' do it { is_expected.to be_truthy }
is_expected.to eq(deployment2)
end end
context 'when build does not have a deployment' do
it { is_expected.to be_falsy }
end end
end end
...@@ -818,14 +901,14 @@ describe Ci::Build do ...@@ -818,14 +901,14 @@ describe Ci::Build do
context 'when build succeeded' do context 'when build succeeded' do
let(:build) { create(:ci_build, :success) } let(:build) { create(:ci_build, :success) }
let!(:deployment) { create(:deployment, deployable: build) } let!(:deployment) { create(:deployment, :success, deployable: build) }
context 'current deployment is latest' do context 'current deployment is latest' do
it { is_expected.to be_falsey } it { is_expected.to be_falsey }
end end
context 'current deployment is not latest on environment' do context 'current deployment is not latest on environment' do
let!(:deployment2) { create(:deployment, environment: deployment.environment) } let!(:deployment2) { create(:deployment, :success, environment: deployment.environment) }
it { is_expected.to be_truthy } it { is_expected.to be_truthy }
end end
...@@ -3209,10 +3292,14 @@ describe Ci::Build do ...@@ -3209,10 +3292,14 @@ describe Ci::Build do
end end
describe '#deployment_status' do describe '#deployment_status' do
before do
allow_any_instance_of(described_class).to receive(:create_deployment)
end
context 'when build is a last deployment' do context 'when build is a last deployment' do
let(:build) { create(:ci_build, :success, environment: 'production') } let(:build) { create(:ci_build, :success, environment: 'production') }
let(:environment) { create(:environment, name: 'production', project: build.project) } let(:environment) { create(:environment, name: 'production', project: build.project) }
let!(:deployment) { create(:deployment, environment: environment, project: environment.project, deployable: build) } let!(:deployment) { create(:deployment, :success, environment: environment, project: environment.project, deployable: build) }
it { expect(build.deployment_status).to eq(:last) } it { expect(build.deployment_status).to eq(:last) }
end end
...@@ -3220,8 +3307,8 @@ describe Ci::Build do ...@@ -3220,8 +3307,8 @@ describe Ci::Build do
context 'when there is a newer build with deployment' do context 'when there is a newer build with deployment' do
let(:build) { create(:ci_build, :success, environment: 'production') } let(:build) { create(:ci_build, :success, environment: 'production') }
let(:environment) { create(:environment, name: 'production', project: build.project) } let(:environment) { create(:environment, name: 'production', project: build.project) }
let!(:deployment) { create(:deployment, environment: environment, project: environment.project, deployable: build) } let!(:deployment) { create(:deployment, :success, environment: environment, project: environment.project, deployable: build) }
let!(:last_deployment) { create(:deployment, environment: environment, project: environment.project) } let!(:last_deployment) { create(:deployment, :success, environment: environment, project: environment.project) }
it { expect(build.deployment_status).to eq(:out_of_date) } it { expect(build.deployment_status).to eq(:out_of_date) }
end end
...@@ -3229,7 +3316,7 @@ describe Ci::Build do ...@@ -3229,7 +3316,7 @@ describe Ci::Build do
context 'when build with deployment has failed' do context 'when build with deployment has failed' do
let(:build) { create(:ci_build, :failed, environment: 'production') } let(:build) { create(:ci_build, :failed, environment: 'production') }
let(:environment) { create(:environment, name: 'production', project: build.project) } let(:environment) { create(:environment, name: 'production', project: build.project) }
let!(:deployment) { create(:deployment, environment: environment, project: environment.project, deployable: build) } let!(:deployment) { create(:deployment, :success, environment: environment, project: environment.project, deployable: build) }
it { expect(build.deployment_status).to eq(:failed) } it { expect(build.deployment_status).to eq(:failed) }
end end
...@@ -3237,14 +3324,7 @@ describe Ci::Build do ...@@ -3237,14 +3324,7 @@ describe Ci::Build do
context 'when build with deployment is running' do context 'when build with deployment is running' do
let(:build) { create(:ci_build, environment: 'production') } let(:build) { create(:ci_build, environment: 'production') }
let(:environment) { create(:environment, name: 'production', project: build.project) } let(:environment) { create(:environment, name: 'production', project: build.project) }
let!(:deployment) { create(:deployment, environment: environment, project: environment.project, deployable: build) } let!(:deployment) { create(:deployment, :success, environment: environment, project: environment.project, deployable: build) }
it { expect(build.deployment_status).to eq(:creating) }
end
context 'when build is successful but deployment is not ready yet' do
let(:build) { create(:ci_build, :success, environment: 'production') }
let(:environment) { create(:environment, name: 'production', project: build.project) }
it { expect(build.deployment_status).to eq(:creating) } it { expect(build.deployment_status).to eq(:creating) }
end end
......
require 'rails_helper'
describe Deployable do
describe '#create_deployment' do
let(:deployment) { job.deployment }
let(:environment) { deployment&.environment }
before do
job.reload
end
context 'when the deployable object will deploy to production' do
let!(:job) { create(:ci_build, :start_review_app) }
it 'creates a deployment and environment record' do
expect(deployment.project).to eq(job.project)
expect(deployment.ref).to eq(job.ref)
expect(deployment.tag).to eq(job.tag)
expect(deployment.sha).to eq(job.sha)
expect(deployment.user).to eq(job.user)
expect(deployment.deployable).to eq(job)
expect(deployment.on_stop).to eq('stop_review_app')
expect(environment.name).to eq('review/master')
end
end
context 'when the deployable object has already had a deployment' do
let!(:job) { create(:ci_build, :start_review_app, deployment: race_deployment) }
let!(:race_deployment) { create(:deployment, :success) }
it 'does not create a new deployment' do
expect(deployment).to eq(race_deployment)
end
end
context 'when the deployable object will not deploy' do
let!(:job) { create(:ci_build) }
it 'does not create a deployment and environment record' do
expect(deployment).to be_nil
expect(environment).to be_nil
end
end
end
end
...@@ -42,16 +42,174 @@ describe Deployment do ...@@ -42,16 +42,174 @@ describe Deployment do
end end
end end
describe 'after_create callbacks' do describe '.success' do
let(:environment) { create(:environment) } subject { described_class.success }
let(:store) { Gitlab::EtagCaching::Store.new }
it 'invalidates the environment etag cache' do context 'when deployment status is success' do
old_value = store.get(environment.etag_cache_key) let(:deployment) { create(:deployment, :success) }
create(:deployment, environment: environment) it { is_expected.to eq([deployment]) }
end
context 'when deployment status is created' do
let(:deployment) { create(:deployment, :created) }
it { is_expected.to be_empty }
end
context 'when deployment status is running' do
let(:deployment) { create(:deployment, :running) }
it { is_expected.to be_empty }
end
end
describe 'state machine' do
context 'when deployment runs' do
let(:deployment) { create(:deployment) }
before do
deployment.run!
end
it 'starts running' do
Timecop.freeze do
expect(deployment).to be_running
expect(deployment.finished_at).to be_nil
end
end
end
context 'when deployment succeeded' do
let(:deployment) { create(:deployment, :running) }
it 'has correct status' do
Timecop.freeze do
deployment.succeed!
expect(deployment).to be_success
expect(deployment.finished_at).to eq(Time.now)
end
end
it 'executes Deployments::SuccessWorker asynchronously' do
expect(Deployments::SuccessWorker)
.to receive(:perform_async).with(deployment.id)
deployment.succeed!
end
end
context 'when deployment failed' do
let(:deployment) { create(:deployment, :running) }
it 'has correct status' do
Timecop.freeze do
deployment.drop!
expect(deployment).to be_failed
expect(deployment.finished_at).to eq(Time.now)
end
end
end
context 'when deployment was canceled' do
let(:deployment) { create(:deployment, :running) }
it 'has correct status' do
Timecop.freeze do
deployment.cancel!
expect(deployment).to be_canceled
expect(deployment.finished_at).to eq(Time.now)
end
end
end
end
describe '#success?' do
subject { deployment.success? }
context 'when deployment status is success' do
let(:deployment) { create(:deployment, :success) }
it { is_expected.to be_truthy }
end
context 'when deployment status is failed' do
let(:deployment) { create(:deployment, :failed) }
expect(store.get(environment.etag_cache_key)).not_to eq(old_value) it { is_expected.to be_falsy }
end
end
describe '#status_name' do
subject { deployment.status_name }
context 'when deployment status is success' do
let(:deployment) { create(:deployment, :success) }
it { is_expected.to eq(:success) }
end
context 'when deployment status is failed' do
let(:deployment) { create(:deployment, :failed) }
it { is_expected.to eq(:failed) }
end
end
describe '#finished_at' do
subject { deployment.finished_at }
context 'when deployment status is created' do
let(:deployment) { create(:deployment) }
it { is_expected.to be_nil }
end
context 'when deployment status is success' do
let(:deployment) { create(:deployment, :success) }
it { is_expected.to eq(deployment.read_attribute(:finished_at)) }
end
context 'when deployment status is success' do
let(:deployment) { create(:deployment, :success, finished_at: nil) }
before do
deployment.update_column(:finished_at, nil)
end
it { is_expected.to eq(deployment.read_attribute(:created_at)) }
end
context 'when deployment status is running' do
let(:deployment) { create(:deployment, :running) }
it { is_expected.to be_nil }
end
end
describe '#deployed_at' do
subject { deployment.deployed_at }
context 'when deployment status is created' do
let(:deployment) { create(:deployment) }
it { is_expected.to be_nil }
end
context 'when deployment status is success' do
let(:deployment) { create(:deployment, :success) }
it { is_expected.to eq(deployment.read_attribute(:finished_at)) }
end
context 'when deployment status is running' do
let(:deployment) { create(:deployment, :running) }
it { is_expected.to be_nil }
end end
end end
...@@ -112,7 +270,7 @@ describe Deployment do ...@@ -112,7 +270,7 @@ describe Deployment do
end end
describe '#metrics' do describe '#metrics' do
let(:deployment) { create(:deployment) } let(:deployment) { create(:deployment, :success) }
let(:prometheus_adapter) { double('prometheus_adapter', can_query?: true) } let(:prometheus_adapter) { double('prometheus_adapter', can_query?: true) }
subject { deployment.metrics } subject { deployment.metrics }
...@@ -141,7 +299,7 @@ describe Deployment do ...@@ -141,7 +299,7 @@ describe Deployment do
describe '#additional_metrics' do describe '#additional_metrics' do
let(:project) { create(:project, :repository) } let(:project) { create(:project, :repository) }
let(:deployment) { create(:deployment, project: project) } let(:deployment) { create(:deployment, :succeed, project: project) }
subject { deployment.additional_metrics } subject { deployment.additional_metrics }
......
...@@ -95,7 +95,7 @@ describe Environment do ...@@ -95,7 +95,7 @@ describe Environment do
context 'with a last deployment' do context 'with a last deployment' do
let!(:deployment) do let!(:deployment) do
create(:deployment, environment: environment, sha: project.commit('master').id) create(:deployment, :success, environment: environment, sha: project.commit('master').id)
end end
context 'in the same branch' do context 'in the same branch' do
...@@ -136,8 +136,8 @@ describe Environment do ...@@ -136,8 +136,8 @@ describe Environment do
describe '#first_deployment_for' do describe '#first_deployment_for' do
let(:project) { create(:project, :repository) } let(:project) { create(:project, :repository) }
let!(:deployment) { create(:deployment, environment: environment, ref: commit.parent.id) } let!(:deployment) { create(:deployment, :succeed, environment: environment, ref: commit.parent.id) }
let!(:deployment1) { create(:deployment, environment: environment, ref: commit.id) } let!(:deployment1) { create(:deployment, :succeed, environment: environment, ref: commit.id) }
let(:head_commit) { project.commit } let(:head_commit) { project.commit }
let(:commit) { project.commit.parent } let(:commit) { project.commit.parent }
...@@ -181,7 +181,8 @@ describe Environment do ...@@ -181,7 +181,8 @@ describe Environment do
let(:build) { create(:ci_build) } let(:build) { create(:ci_build) }
let!(:deployment) do let!(:deployment) do
create(:deployment, environment: environment, create(:deployment, :success,
environment: environment,
deployable: build, deployable: build,
on_stop: 'close_app') on_stop: 'close_app')
end end
...@@ -249,7 +250,8 @@ describe Environment do ...@@ -249,7 +250,8 @@ describe Environment do
let(:build) { create(:ci_build, pipeline: pipeline) } let(:build) { create(:ci_build, pipeline: pipeline) }
let!(:deployment) do let!(:deployment) do
create(:deployment, environment: environment, create(:deployment, :success,
environment: environment,
deployable: build, deployable: build,
on_stop: 'close_app') on_stop: 'close_app')
end end
...@@ -304,7 +306,7 @@ describe Environment do ...@@ -304,7 +306,7 @@ describe Environment do
context 'when last deployment to environment is the most recent one' do context 'when last deployment to environment is the most recent one' do
before do before do
create(:deployment, environment: environment, ref: 'feature') create(:deployment, :success, environment: environment, ref: 'feature')
end end
it { is_expected.to be true } it { is_expected.to be true }
...@@ -312,8 +314,8 @@ describe Environment do ...@@ -312,8 +314,8 @@ describe Environment do
context 'when last deployment to environment is not the most recent' do context 'when last deployment to environment is not the most recent' do
before do before do
create(:deployment, environment: environment, ref: 'feature') create(:deployment, :success, environment: environment, ref: 'feature')
create(:deployment, environment: environment, ref: 'master') create(:deployment, :success, environment: environment, ref: 'master')
end end
it { is_expected.to be false } it { is_expected.to be false }
...@@ -321,7 +323,7 @@ describe Environment do ...@@ -321,7 +323,7 @@ describe Environment do
end end
describe '#actions_for' do describe '#actions_for' do
let(:deployment) { create(:deployment, environment: environment) } let(:deployment) { create(:deployment, :success, environment: environment) }
let(:pipeline) { deployment.deployable.pipeline } let(:pipeline) { deployment.deployable.pipeline }
let!(:review_action) { create(:ci_build, :manual, name: 'review-apps', pipeline: pipeline, environment: 'review/$CI_COMMIT_REF_NAME' )} let!(:review_action) { create(:ci_build, :manual, name: 'review-apps', pipeline: pipeline, environment: 'review/$CI_COMMIT_REF_NAME' )}
let!(:production_action) { create(:ci_build, :manual, name: 'production', pipeline: pipeline, environment: 'production' )} let!(:production_action) { create(:ci_build, :manual, name: 'production', pipeline: pipeline, environment: 'production' )}
...@@ -331,6 +333,70 @@ describe Environment do ...@@ -331,6 +333,70 @@ describe Environment do
end end
end end
describe '.deployments' do
subject { environment.deployments }
context 'when there is a deployment record with created status' do
let(:deployment) { create(:deployment, :created, environment: environment) }
it 'does not return the record' do
is_expected.to be_empty
end
end
context 'when there is a deployment record with running status' do
let(:deployment) { create(:deployment, :running, environment: environment) }
it 'does not return the record' do
is_expected.to be_empty
end
end
context 'when there is a deployment record with success status' do
let(:deployment) { create(:deployment, :success, environment: environment) }
it 'returns the record' do
is_expected.to eq([deployment])
end
end
end
describe '.last_deployment' do
subject { environment.last_deployment }
before do
allow_any_instance_of(Deployment).to receive(:create_ref)
end
context 'when there is an old deployment record' do
let!(:previous_deployment) { create(:deployment, :success, environment: environment) }
context 'when there is a deployment record with created status' do
let!(:deployment) { create(:deployment, environment: environment) }
it 'returns the previous deployment' do
is_expected.to eq(previous_deployment)
end
end
context 'when there is a deployment record with running status' do
let!(:deployment) { create(:deployment, :running, environment: environment) }
it 'returns the previous deployment' do
is_expected.to eq(previous_deployment)
end
end
context 'when there is a deployment record with success status' do
let!(:deployment) { create(:deployment, :success, environment: environment) }
it 'returns the latest successful deployment' do
is_expected.to eq(deployment)
end
end
end
end
describe '#has_terminals?' do describe '#has_terminals?' do
subject { environment.has_terminals? } subject { environment.has_terminals? }
...@@ -338,7 +404,7 @@ describe Environment do ...@@ -338,7 +404,7 @@ describe Environment do
context 'with a deployment service' do context 'with a deployment service' do
shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do
context 'and a deployment' do context 'and a deployment' do
let!(:deployment) { create(:deployment, environment: environment) } let!(:deployment) { create(:deployment, :success, environment: environment) }
it { is_expected.to be_truthy } it { is_expected.to be_truthy }
end end
......
require 'spec_helper' require 'spec_helper'
describe EnvironmentStatus do describe EnvironmentStatus do
let(:deployment) { create(:deployment, :review_app) } let(:deployment) { create(:deployment, :succeed, :review_app) }
let(:environment) { deployment.environment} let(:environment) { deployment.environment}
let(:project) { deployment.project } let(:project) { deployment.project }
let(:merge_request) { create(:merge_request, :deployed_review_app, deployment: deployment) } let(:merge_request) { create(:merge_request, :deployed_review_app, deployment: deployment) }
...@@ -12,7 +12,7 @@ describe EnvironmentStatus do ...@@ -12,7 +12,7 @@ describe EnvironmentStatus do
it { is_expected.to delegate_method(:id).to(:environment) } it { is_expected.to delegate_method(:id).to(:environment) }
it { is_expected.to delegate_method(:name).to(:environment) } it { is_expected.to delegate_method(:name).to(:environment) }
it { is_expected.to delegate_method(:project).to(:environment) } it { is_expected.to delegate_method(:project).to(:environment) }
it { is_expected.to delegate_method(:deployed_at).to(:deployment).as(:created_at) } it { is_expected.to delegate_method(:deployed_at).to(:deployment) }
it { is_expected.to delegate_method(:status).to(:deployment) } it { is_expected.to delegate_method(:status).to(:deployment) }
describe '#project' do describe '#project' do
......
...@@ -1836,8 +1836,8 @@ describe MergeRequest do ...@@ -1836,8 +1836,8 @@ describe MergeRequest do
let(:environments) { create_list(:environment, 3, project: project) } let(:environments) { create_list(:environment, 3, project: project) }
before do before do
create(:deployment, environment: environments.first, ref: 'master', sha: project.commit('master').id) create(:deployment, :success, environment: environments.first, ref: 'master', sha: project.commit('master').id)
create(:deployment, environment: environments.second, ref: 'feature', sha: project.commit('feature').id) create(:deployment, :success, environment: environments.second, ref: 'feature', sha: project.commit('feature').id)
end end
it 'selects deployed environments' do it 'selects deployed environments' do
...@@ -1857,7 +1857,7 @@ describe MergeRequest do ...@@ -1857,7 +1857,7 @@ describe MergeRequest do
let(:source_environment) { create(:environment, project: source_project) } let(:source_environment) { create(:environment, project: source_project) }
before do before do
create(:deployment, environment: source_environment, ref: 'feature', sha: merge_request.diff_head_sha) create(:deployment, :success, environment: source_environment, ref: 'feature', sha: merge_request.diff_head_sha)
end end
it 'selects deployed environments' do it 'selects deployed environments' do
...@@ -1868,7 +1868,7 @@ describe MergeRequest do ...@@ -1868,7 +1868,7 @@ describe MergeRequest do
let(:target_environment) { create(:environment, project: project) } let(:target_environment) { create(:environment, project: project) }
before do before do
create(:deployment, environment: target_environment, tag: true, sha: merge_request.diff_head_sha) create(:deployment, :success, environment: target_environment, tag: true, sha: merge_request.diff_head_sha)
end end
it 'selects deployed environments' do it 'selects deployed environments' do
......
...@@ -3976,6 +3976,40 @@ describe Project do ...@@ -3976,6 +3976,40 @@ describe Project do
end end
end end
describe '.deployments' do
subject { project.deployments }
let(:project) { create(:project) }
before do
allow_any_instance_of(Deployment).to receive(:create_ref)
end
context 'when there is a deployment record with created status' do
let(:deployment) { create(:deployment, :created, project: project) }
it 'does not return the record' do
is_expected.to be_empty
end
end
context 'when there is a deployment record with running status' do
let(:deployment) { create(:deployment, :running, project: project) }
it 'does not return the record' do
is_expected.to be_empty
end
end
context 'when there is a deployment record with success status' do
let(:deployment) { create(:deployment, :success, project: project) }
it 'returns the record' do
is_expected.to eq([deployment])
end
end
end
def rugged_config def rugged_config
rugged_repo(project.repository).config rugged_repo(project.repository).config
end end
......
...@@ -10,9 +10,9 @@ describe API::Deployments do ...@@ -10,9 +10,9 @@ describe API::Deployments do
describe 'GET /projects/:id/deployments' do describe 'GET /projects/:id/deployments' do
let(:project) { create(:project) } let(:project) { create(:project) }
let!(:deployment_1) { create(:deployment, project: project, iid: 11, ref: 'master', created_at: Time.now) } let!(:deployment_1) { create(:deployment, :success, project: project, iid: 11, ref: 'master', created_at: Time.now) }
let!(:deployment_2) { create(:deployment, project: project, iid: 12, ref: 'feature', created_at: 1.day.ago) } let!(:deployment_2) { create(:deployment, :success, project: project, iid: 12, ref: 'feature', created_at: 1.day.ago) }
let!(:deployment_3) { create(:deployment, project: project, iid: 8, ref: 'feature', created_at: 2.days.ago) } let!(:deployment_3) { create(:deployment, :success, project: project, iid: 8, ref: 'patch', created_at: 2.days.ago) }
context 'as member of the project' do context 'as member of the project' do
it 'returns projects deployments sorted by id asc' do it 'returns projects deployments sorted by id asc' do
...@@ -53,8 +53,8 @@ describe API::Deployments do ...@@ -53,8 +53,8 @@ describe API::Deployments do
'id' | 'desc' | [:deployment_3, :deployment_2, :deployment_1] 'id' | 'desc' | [:deployment_3, :deployment_2, :deployment_1]
'iid' | 'asc' | [:deployment_3, :deployment_1, :deployment_2] 'iid' | 'asc' | [:deployment_3, :deployment_1, :deployment_2]
'iid' | 'desc' | [:deployment_2, :deployment_1, :deployment_3] 'iid' | 'desc' | [:deployment_2, :deployment_1, :deployment_3]
'ref' | 'asc' | [:deployment_2, :deployment_3, :deployment_1] 'ref' | 'asc' | [:deployment_2, :deployment_1, :deployment_3]
'ref' | 'desc' | [:deployment_1, :deployment_2, :deployment_3] 'ref' | 'desc' | [:deployment_3, :deployment_1, :deployment_2]
end end
with_them do with_them do
...@@ -76,7 +76,7 @@ describe API::Deployments do ...@@ -76,7 +76,7 @@ describe API::Deployments do
describe 'GET /projects/:id/deployments/:deployment_id' do describe 'GET /projects/:id/deployments/:deployment_id' do
let(:project) { deployment.environment.project } let(:project) { deployment.environment.project }
let!(:deployment) { create(:deployment) } let!(:deployment) { create(:deployment, :success) }
context 'as a member of the project' do context 'as a member of the project' do
it 'returns the projects deployment' do it 'returns the projects deployment' do
......
...@@ -14,7 +14,8 @@ describe EnvironmentSerializer do ...@@ -14,7 +14,8 @@ describe EnvironmentSerializer do
let(:project) { create(:project, :repository) } let(:project) { create(:project, :repository) }
let(:deployable) { create(:ci_build) } let(:deployable) { create(:ci_build) }
let(:deployment) do let(:deployment) do
create(:deployment, deployable: deployable, create(:deployment, :success,
deployable: deployable,
user: user, user: user,
project: project, project: project,
sha: project.commit.id) sha: project.commit.id)
......
...@@ -4,8 +4,8 @@ describe EnvironmentStatusEntity do ...@@ -4,8 +4,8 @@ describe EnvironmentStatusEntity do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:request) { double('request') } let(:request) { double('request') }
let(:deployment) { create(:deployment, :review_app) } let(:deployment) { create(:deployment, :succeed, :review_app) }
let(:environment) { deployment.environment} let(:environment) { deployment.environment }
let(:project) { deployment.project } let(:project) { deployment.project }
let(:merge_request) { create(:merge_request, :deployed_review_app, deployment: deployment) } let(:merge_request) { create(:merge_request, :deployed_review_app, deployment: deployment) }
......
...@@ -32,7 +32,7 @@ describe Ci::RetryBuildService do ...@@ -32,7 +32,7 @@ describe Ci::RetryBuildService do
IGNORE_ACCESSORS = IGNORE_ACCESSORS =
%i[type lock_version target_url base_tags trace_sections %i[type lock_version target_url base_tags trace_sections
commit_id deployments erased_by_id last_deployment project_id commit_id deployment erased_by_id project_id
runner_id tag_taggings taggings tags trigger_request_id runner_id tag_taggings taggings tags trigger_request_id
user_id auto_canceled_by_id retried failure_reason user_id auto_canceled_by_id retried failure_reason
artifacts_file_store artifacts_metadata_store artifacts_file_store artifacts_metadata_store
......
require 'spec_helper' require 'spec_helper'
describe CreateDeploymentService do describe UpdateDeploymentService do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:options) { nil } let(:options) { { name: 'production' } }
let(:job) do let(:job) do
create(:ci_build, create(:ci_build,
ref: 'master', ref: 'master',
tag: false, tag: false,
environment: 'production', environment: 'production',
options: { environment: options }) options: { environment: options },
project: project)
end end
let(:project) { job.project } let(:project) { create(:project, :repository) }
let(:environment) { deployment.environment }
let!(:environment) do let(:deployment) { job.deployment }
create(:environment, project: project, name: 'production') let(:service) { described_class.new(deployment) }
end
let(:service) { described_class.new(job) }
before do before do
allow_any_instance_of(Deployment).to receive(:create_ref) job.success! # Create/Succeed deployment
end end
describe '#execute' do describe '#execute' do
subject { service.execute } subject { service.execute }
context 'when environment exists' do let(:store) { Gitlab::EtagCaching::Store.new }
it 'creates a deployment' do
expect(subject).to be_persisted it 'invalidates the environment etag cache' do
end old_value = store.get(environment.etag_cache_key)
subject
expect(store.get(environment.etag_cache_key)).not_to eq(old_value)
end end
context 'when environment does not exist' do it 'creates ref' do
let(:environment) {} expect_any_instance_of(Repository)
.to receive(:create_ref)
.with(deployment.ref, deployment.send(:ref_path))
it 'does not create a deployment' do subject
expect do
expect(subject).to be_nil
end.not_to change { Deployment.count }
end end
it 'updates merge request metrics' do
expect_any_instance_of(Deployment)
.to receive(:update_merge_request_metrics!)
subject
end end
context 'when start action is defined' do context 'when start action is defined' do
let(:options) { { action: 'start' } } let(:options) { { name: 'production', action: 'start' } }
context 'and environment is stopped' do context 'and environment is stopped' do
before do before do
...@@ -56,15 +63,11 @@ describe CreateDeploymentService do ...@@ -56,15 +63,11 @@ describe CreateDeploymentService do
expect(environment.reload).to be_available expect(environment.reload).to be_available
end end
it 'creates a deployment' do
expect(subject).to be_persisted
end
end end
end end
context 'when stop action is defined' do context 'when stop action is defined' do
let(:options) { { action: 'stop' } } let(:options) { { name: 'production', action: 'stop' } }
context 'and environment is available' do context 'and environment is available' do
before do before do
...@@ -76,10 +79,6 @@ describe CreateDeploymentService do ...@@ -76,10 +79,6 @@ describe CreateDeploymentService do
expect(environment.reload).to be_stopped expect(environment.reload).to be_stopped
end end
it 'does not create a deployment' do
expect(subject).to be_nil
end
end end
end end
...@@ -94,10 +93,6 @@ describe CreateDeploymentService do ...@@ -94,10 +93,6 @@ describe CreateDeploymentService do
job.update(environment: 'review-apps/$CI_COMMIT_REF_NAME') job.update(environment: 'review-apps/$CI_COMMIT_REF_NAME')
end end
it 'creates a new deployment' do
expect(subject).to be_persisted
end
it 'does not create a new environment' do it 'does not create a new environment' do
expect { subject }.not_to change { Environment.count } expect { subject }.not_to change { Environment.count }
end end
...@@ -109,21 +104,6 @@ describe CreateDeploymentService do ...@@ -109,21 +104,6 @@ describe CreateDeploymentService do
expect(subject.environment.external_url).to eq('http://master.review-apps.gitlab.com') expect(subject.environment.external_url).to eq('http://master.review-apps.gitlab.com')
end end
end end
context 'when project was removed' do
let(:environment) {}
before do
job.update(project: nil)
end
it 'does not create deployment or environment' do
expect { subject }.not_to raise_error
expect(Environment.count).to be_zero
expect(Deployment.count).to be_zero
end
end
end end
describe '#expanded_environment_url' do describe '#expanded_environment_url' do
...@@ -133,7 +113,9 @@ describe CreateDeploymentService do ...@@ -133,7 +113,9 @@ describe CreateDeploymentService do
let(:job) do let(:job) do
create(:ci_build, create(:ci_build,
ref: 'master', ref: 'master',
options: { environment: { url: 'http://review/$CI_COMMIT_REF_NAME' } }) environment: 'production',
project: project,
options: { environment: { name: 'production', url: 'http://review/$CI_COMMIT_REF_NAME' } })
end end
it { is_expected.to eq('http://review/master') } it { is_expected.to eq('http://review/master') }
...@@ -143,16 +125,9 @@ describe CreateDeploymentService do ...@@ -143,16 +125,9 @@ describe CreateDeploymentService do
let(:job) do let(:job) do
create(:ci_build, create(:ci_build,
ref: 'master', ref: 'master',
environment: 'production', environment: 'prod-slug',
options: { environment: { url: 'http://review/$CI_ENVIRONMENT_SLUG' } }) project: project,
end options: { environment: { name: 'prod-slug', url: 'http://review/$CI_ENVIRONMENT_SLUG' } })
let!(:environment) do
create(:environment,
project: job.project,
name: 'production',
slug: 'prod-slug',
external_url: 'http://review/old')
end end
it { is_expected.to eq('http://review/prod-slug') } it { is_expected.to eq('http://review/prod-slug') }
...@@ -162,18 +137,16 @@ describe CreateDeploymentService do ...@@ -162,18 +137,16 @@ describe CreateDeploymentService do
let(:job) do let(:job) do
create(:ci_build, create(:ci_build,
yaml_variables: [{ key: :APP_HOST, value: 'host' }], yaml_variables: [{ key: :APP_HOST, value: 'host' }],
options: { environment: { url: 'http://review/$APP_HOST' } }) environment: 'production',
project: project,
options: { environment: { name: 'production', url: 'http://review/$APP_HOST' } })
end end
it { is_expected.to eq('http://review/host') } it { is_expected.to eq('http://review/host') }
end end
context 'when yaml environment does not have url' do context 'when yaml environment does not have url' do
let(:job) { create(:ci_build, environment: 'staging') } let(:job) { create(:ci_build, environment: 'staging', project: project) }
let!(:environment) do
create(:environment, project: job.project, name: job.environment)
end
it 'returns the external_url from persisted environment' do it 'returns the external_url from persisted environment' do
is_expected.to be_nil is_expected.to be_nil
...@@ -181,109 +154,37 @@ describe CreateDeploymentService do ...@@ -181,109 +154,37 @@ describe CreateDeploymentService do
end end
end end
describe 'processing of builds' do
shared_examples 'does not create deployment' do
it 'does not create a new deployment' do
expect { subject }.not_to change { Deployment.count }
end
it 'does not call a service' do
expect_any_instance_of(described_class).not_to receive(:execute)
subject
end
end
shared_examples 'creates deployment' do
it 'creates a new deployment' do
expect { subject }.to change { Deployment.count }.by(1)
end
it 'calls a service' do
expect_any_instance_of(described_class).to receive(:execute)
subject
end
it 'is set as deployable' do
subject
expect(Deployment.last.deployable).to eq(deployable)
end
it 'updates environment URL' do
subject
expect(Deployment.last.environment.external_url).not_to be_nil
end
end
context 'without environment specified' do
let(:job) { create(:ci_build) }
it_behaves_like 'does not create deployment' do
subject { job.success }
end
end
context 'when environment is specified' do
let(:deployable) { job }
let(:options) do
{ environment: { name: 'production', url: 'http://gitlab.com' } }
end
context 'when job succeeds' do
it_behaves_like 'creates deployment' do
subject { job.success }
end
end
context 'when job fails' do
it_behaves_like 'does not create deployment' do
subject { job.drop }
end
end
context 'when job is retried' do
it_behaves_like 'creates deployment' do
before do
stub_not_protect_default_branch
project.add_developer(user)
end
let(:deployable) { Ci::Build.retry(job, user) }
subject { deployable.success }
end
end
end
end
describe "merge request metrics" do describe "merge request metrics" do
let(:merge_request) { create(:merge_request, target_branch: 'master', source_branch: 'feature', source_project: project) } let(:merge_request) { create(:merge_request, target_branch: 'master', source_branch: 'feature', source_project: project) }
context "while updating the 'first_deployed_to_production_at' time" do context "while updating the 'first_deployed_to_production_at' time" do
before do before do
merge_request.metrics.update!(merged_at: Time.now) merge_request.metrics.update!(merged_at: 1.hour.ago)
end end
context "for merge requests merged before the current deploy" do context "for merge requests merged before the current deploy" do
it "sets the time if the deploy's environment is 'production'" do it "sets the time if the deploy's environment is 'production'" do
time = Time.now service.execute
Timecop.freeze(time) { service.execute }
expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_like_time(time) expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_like_time(deployment.finished_at)
end
context 'when job deploys to staging' do
let(:job) do
create(:ci_build,
ref: 'master',
tag: false,
environment: 'staging',
options: { environment: { name: 'staging' } },
project: project)
end end
it "doesn't set the time if the deploy's environment is not 'production'" do it "doesn't set the time if the deploy's environment is not 'production'" do
job.update(environment: 'staging')
service = described_class.new(job)
service.execute service.execute
expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_nil expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_nil
end end
end
it 'does not raise errors if the merge request does not have a metrics record' do it 'does not raise errors if the merge request does not have a metrics record' do
merge_request.metrics.destroy merge_request.metrics.destroy
...@@ -303,7 +204,6 @@ describe CreateDeploymentService do ...@@ -303,7 +204,6 @@ describe CreateDeploymentService do
expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_like_time(time) expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_like_time(time)
# Current deploy # Current deploy
service = described_class.new(job)
Timecop.freeze(time + 12.hours) { service.execute } Timecop.freeze(time + 12.hours) { service.execute }
expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_like_time(time) expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_like_time(time)
...@@ -318,15 +218,12 @@ describe CreateDeploymentService do ...@@ -318,15 +218,12 @@ describe CreateDeploymentService do
expect(merge_request.reload.metrics.merged_at).to be < merge_request.reload.metrics.first_deployed_to_production_at expect(merge_request.reload.metrics.merged_at).to be < merge_request.reload.metrics.first_deployed_to_production_at
merge_request.reload.metrics.update(first_deployed_to_production_at: nil) previous_time = merge_request.reload.metrics.first_deployed_to_production_at
expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_nil
# Current deploy # Current deploy
service = described_class.new(job)
Timecop.freeze(time + 12.hours) { service.execute } Timecop.freeze(time + 12.hours) { service.execute }
expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_nil expect(merge_request.reload.metrics.first_deployed_to_production_at).to eq(previous_time)
end end
end end
end end
......
...@@ -85,7 +85,7 @@ module CycleAnalyticsHelpers ...@@ -85,7 +85,7 @@ module CycleAnalyticsHelpers
raise ArgumentError raise ArgumentError
end end
CreateDeploymentService.new(dummy_job).execute dummy_job.success! # State machine automatically update associated deployment/environment record
end end
def dummy_production_job(user, project) def dummy_production_job(user, project)
...@@ -97,7 +97,7 @@ module CycleAnalyticsHelpers ...@@ -97,7 +97,7 @@ module CycleAnalyticsHelpers
end end
def dummy_pipeline(project) def dummy_pipeline(project)
Ci::Pipeline.new( create(:ci_pipeline,
sha: project.repository.commit('master').sha, sha: project.repository.commit('master').sha,
ref: 'master', ref: 'master',
source: :push, source: :push,
...@@ -106,9 +106,7 @@ module CycleAnalyticsHelpers ...@@ -106,9 +106,7 @@ module CycleAnalyticsHelpers
end end
def new_dummy_job(user, project, environment) def new_dummy_job(user, project, environment)
project.environments.find_or_create_by(name: environment) create(:ci_build,
Ci::Build.new(
project: project, project: project,
user: user, user: user,
environment: environment, environment: environment,
......
...@@ -2,15 +2,39 @@ require 'spec_helper' ...@@ -2,15 +2,39 @@ require 'spec_helper'
describe BuildSuccessWorker do describe BuildSuccessWorker do
describe '#perform' do describe '#perform' do
subject { described_class.new.perform(build.id) }
before do
allow_any_instance_of(Deployment).to receive(:create_ref)
end
context 'when build exists' do context 'when build exists' do
context 'when build belogs to the environment' do context 'when deployment was not created with the build creation' do # An edge case during the transition period
let!(:build) { create(:ci_build, environment: 'production') } let!(:build) { create(:ci_build, :deploy_to_production) }
before do
Deployment.delete_all
build.reload
end
it 'creates a successful deployment' do
expect(build).not_to be_has_deployment
subject
build.reload
expect(build).to be_has_deployment
expect(build.deployment).to be_success
end
end
context 'when deployment was created with the build creation' do # Counter part of the above edge case
let!(:build) { create(:ci_build, :deploy_to_production) }
it 'executes deployment service' do it 'does not create a new deployment' do
expect_any_instance_of(CreateDeploymentService) expect(build).to be_has_deployment
.to receive(:execute)
described_class.new.perform(build.id) expect { subject }.not_to change { Deployment.count }
end end
end end
...@@ -18,10 +42,9 @@ describe BuildSuccessWorker do ...@@ -18,10 +42,9 @@ describe BuildSuccessWorker do
let!(:build) { create(:ci_build, project: nil) } let!(:build) { create(:ci_build, project: nil) }
it 'does not create deployment' do it 'does not create deployment' do
expect_any_instance_of(CreateDeploymentService) subject
.not_to receive(:execute)
described_class.new.perform(build.id) expect(build.reload).not_to be_has_deployment
end end
end end
end end
......
require 'spec_helper'
describe Deployments::SuccessWorker do
subject { described_class.new.perform(deployment&.id) }
context 'when successful deployment' do
let(:deployment) { create(:deployment, :success) }
it 'executes UpdateDeploymentService' do
expect(UpdateDeploymentService)
.to receive(:new).with(deployment).and_call_original
subject
end
end
context 'when canceled deployment' do
let(:deployment) { create(:deployment, :canceled) }
it 'does not execute UpdateDeploymentService' do
expect(UpdateDeploymentService).not_to receive(:new)
subject
end
end
context 'when deploy record does not exist' do
let(:deployment) { nil }
it 'does not execute UpdateDeploymentService' do
expect(UpdateDeploymentService).not_to receive(:new)
subject
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment