Class: DesignManagement::Version

Inherits:
ApplicationRecord show all
Extended by:
Gitlab::ExclusiveLeaseHelpers
Includes:
AfterCommitQueue, Gitlab::Utils::StrongMemoize, Importable, ShaAttribute
Defined in:
app/models/design_management/version.rb

Defined Under Namespace

Classes: CouldNotCreateVersion

Constant Summary collapse

NotSameIssue =
Class.new(StandardError)
CREATION_TTL =
5.seconds
RETRY_DELAY =
->(num) { 0.2.seconds * num**2 }

Constants included from Gitlab::ExclusiveLeaseHelpers

Gitlab::ExclusiveLeaseHelpers::FailedToObtainLockError

Instance Attribute Summary

Attributes included from Importable

#imported, #importing

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Gitlab::ExclusiveLeaseHelpers

in_lock

Methods included from Gitlab::Utils::StrongMemoize

#clear_memoization, #strong_memoize, #strong_memoized?

Methods included from AfterCommitQueue

#run_after_commit, #run_after_commit_or_now

Methods inherited from ApplicationRecord

at_most, id_in, id_not_in, iid_in, pluck_primary_key, primary_key_in, safe_ensure_unique, safe_find_or_create_by, safe_find_or_create_by!, underscore, where_exists, with_fast_statement_timeout, without_order

Class Method Details

.create_for_designs(design_actions, sha, author) ⇒ Object

This is the one true way to create a Version.

This method means you can avoid the paradox of versions being invalid without designs, and not being able to add designs without a saved version. Also this method inserts designs in bulk, rather than one by one.

Before calling this method, callers must guard against concurrent modification by obtaining the lock on the design repository. See: `DesignManagement::Version.with_lock`.

Parameters:

  • design_actions [DesignManagement::DesignAction]:

    the actions that have been performed in the repository.
    
  • sha [String]:

    the SHA of the commit that performed them
    
  • author [User]:

    the user who performed the commit
    

returns [DesignManagement::Version]


78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'app/models/design_management/version.rb', line 78

def self.create_for_designs(design_actions, sha, author)
  issue_id, not_uniq = design_actions.map(&:issue_id).compact.uniq
  raise NotSameIssue, 'All designs must belong to the same issue!' if not_uniq

  transaction do
    version = new(sha: sha, issue_id: issue_id, author: author)
    version.save(validate: false) # We need it to have an ID. Validate later when designs are present

    rows = design_actions.map { |action| action.row_attrs(version) }

    Gitlab::Database.bulk_insert(::DesignManagement::Action.table_name, rows) # rubocop:disable Gitlab/BulkInsert
    version.designs.reset
    version.validate!
    design_actions.each(&:performed)

    version
  end
rescue
  raise CouldNotCreateVersion.new(sha, issue_id, design_actions)
end

.with_lock(project_id, repository, &block) ⇒ Object


102
103
104
105
106
107
108
109
# File 'app/models/design_management/version.rb', line 102

def self.with_lock(project_id, repository, &block)
  key = "with_lock:#{name}:{#{project_id}}"

  in_lock(key, ttl: CREATION_TTL, retries: 5, sleep_sec: RETRY_DELAY) do |_retried|
    repository.create_if_not_exists
    yield
  end
end

Instance Method Details

#authorObject


118
119
120
# File 'app/models/design_management/version.rb', line 118

def author
  super || (commit_author if persisted?)
end

#designs_by_eventObject


111
112
113
114
115
116
# File 'app/models/design_management/version.rb', line 111

def designs_by_event
  actions
    .includes(:design)
    .group_by(&:event)
    .transform_values { |group| group.map(&:design) }
end

#diff_refsObject


122
123
124
# File 'app/models/design_management/version.rb', line 122

def diff_refs
  strong_memoize(:diff_refs) { commit&.diff_refs }
end

#resetObject


126
127
128
129
# File 'app/models/design_management/version.rb', line 126

def reset
  %i[diff_refs commit].each { |k| clear_memoization(k) }
  super
end