Welcome to mirror list, hosted at ThFree Co, Russian Federation.

update_pages_service.rb « projects « services « app - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 0fadd75669ebf6733fe41ee22d3413df9b5bdef1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# frozen_string_literal: true

module Projects
  class UpdatePagesService < BaseService
    # old deployment can be cached by pages daemon
    # so we need to give pages daemon some time update cache
    # 10 minutes is enough, but 30 feels safer
    OLD_DEPLOYMENTS_DESTRUCTION_DELAY = 30.minutes.freeze

    attr_reader :build, :deployment_update

    def initialize(project, build)
      @project = project
      @build = build
      @deployment_update = ::Gitlab::Pages::DeploymentUpdate.new(project, build)
    end

    def execute
      register_attempt

      # Create status notifying the deployment of pages
      @commit_status = build_commit_status
      ::Ci::Pipelines::AddJobService.new(@build.pipeline).execute!(@commit_status) do |job|
        job.enqueue!
        job.run!
      end

      return error(deployment_update.errors.first.full_message) unless deployment_update.valid?

      build.artifacts_file.use_file do |artifacts_path|
        deployment = create_pages_deployment(artifacts_path, build)

        break error('The uploaded artifact size does not match the expected value') unless deployment

        if deployment_update.valid?
          update_project_pages_deployment(deployment)
          success
        else
          error(deployment_update.errors.first.full_message)
        end
      end
    rescue StandardError => e
      error(e.message)
      raise e
    end

    private

    def success
      @commit_status.success
      @project.mark_pages_as_deployed
      publish_deployed_event
      super
    end

    def error(message)
      register_failure
      log_error("Projects::UpdatePagesService: #{message}")
      @commit_status.allow_failure = !deployment_update.latest?
      @commit_status.description = message
      @commit_status.drop(:script_failure)
      super
    end

    def build_commit_status
      stage = create_stage

      GenericCommitStatus.new(
        user: build.user,
        ci_stage: stage,
        name: 'pages:deploy',
        stage: 'deploy',
        stage_idx: stage.position
      )
    end

    # rubocop: disable Performance/ActiveRecordSubtransactionMethods
    def create_stage
      build.pipeline.stages.safe_find_or_create_by(name: 'deploy', pipeline_id: build.pipeline.id) do |stage|
        stage.position = GenericCommitStatus::EXTERNAL_STAGE_IDX
        stage.project = build.project
      end
    end
    # rubocop: enable Performance/ActiveRecordSubtransactionMethods

    def create_pages_deployment(artifacts_path, build)
      sha256 = build.job_artifacts_archive.file_sha256
      File.open(artifacts_path) do |file|
        deployment = project.pages_deployments.create!(
          file: file,
          file_count: deployment_update.entries_count,
          file_sha256: sha256,
          ci_build_id: build.id
        )

        break if deployment.size != file.size || deployment.file.size != file.size

        deployment
      end
    end

    def update_project_pages_deployment(deployment)
      project.update_pages_deployment!(deployment)
      DestroyPagesDeploymentsWorker.perform_in(
        OLD_DEPLOYMENTS_DESTRUCTION_DELAY,
        project.id,
        deployment.id
      )
    end

    def ref
      build.ref
    end

    def artifacts
      build.artifacts_file.path
    end

    def register_attempt
      pages_deployments_total_counter.increment
    end

    def register_failure
      pages_deployments_failed_total_counter.increment
    end

    def pages_deployments_total_counter
      @pages_deployments_total_counter ||= Gitlab::Metrics.counter(:pages_deployments_total, "Counter of GitLab Pages deployments triggered")
    end

    def pages_deployments_failed_total_counter
      @pages_deployments_failed_total_counter ||= Gitlab::Metrics.counter(:pages_deployments_failed_total, "Counter of GitLab Pages deployments which failed")
    end

    def publish_deployed_event
      event = ::Pages::PageDeployedEvent.new(data: {
        project_id: project.id,
        namespace_id: project.namespace_id,
        root_namespace_id: project.root_namespace.id
      })

      Gitlab::EventStore.publish(event)
    end
  end
end