Class: Release

Inherits:
ApplicationRecord show all
Includes:
CacheMarkdownField, EachBatch, FromUnion, Gitlab::Utils::StrongMemoize, Importable, Presentable, UpdatedAtFilterable
Defined in:
app/models/release.rb

Constant Summary collapse

MAX_NUMBER_TO_DISPLAY =
3
MAX_NUMBER_TO_PUBLISH =
5000

Constants included from CacheMarkdownField

CacheMarkdownField::INVALIDATED_BY

Constants inherited from ApplicationRecord

ApplicationRecord::MAX_PLUCK

Constants included from HasCheckConstraints

HasCheckConstraints::NOT_NULL_CHECK_PATTERN

Constants included from ResetOnColumnErrors

ResetOnColumnErrors::MAX_RESET_PERIOD

Instance Attribute Summary

Attributes included from Importable

#importing, #user_contributions

Attributes included from CacheMarkdownField

#skip_markdown_cache_validation

Class Method Summary collapse

Instance Method Summary collapse

Methods included from CacheMarkdownField

#attribute_invalidated?, #banzai_render_context, #cached_html_for, #cached_html_up_to_date?, #can_cache_field?, #invalidated_markdown_cache?, #latest_cached_markdown_version, #mentionable_attributes_changed?, #mentioned_filtered_user_ids_for, #parent_user, #refresh_markdown_cache, #refresh_markdown_cache!, #rendered_field_content, #skip_project_check?, #store_mentions!, #store_mentions_after_commit?, #updated_cached_html_for

Methods included from Presentable

#present

Methods inherited from ApplicationRecord

===, cached_column_list, #create_or_load_association, declarative_enum, default_select_columns, id_in, id_not_in, iid_in, nullable_column?, pluck_primary_key, primary_key_in, #readable_by?, safe_ensure_unique, safe_find_or_create_by, safe_find_or_create_by!, #to_ability_name, underscore, where_exists, where_not_exists, with_fast_read_statement_timeout, without_order

Methods included from ResetOnColumnErrors

#reset_on_union_error, #reset_on_unknown_attribute_error

Methods included from Gitlab::SensitiveSerializableHash

#serializable_hash

Class Method Details

.latest(order_by: 'released_at') ⇒ Object

In the future, we should support ‘order_by=semver`; see gitlab.com/gitlab-org/gitlab/-/issues/352945



78
79
80
# File 'app/models/release.rb', line 78

def latest(order_by: 'released_at')
  sort_by_attribute("#{order_by}_desc").first
end

.latest_for_projects(projects, order_by: 'released_at') ⇒ Object

This query uses LATERAL JOIN to find the latest release for each project. To avoid joining the ‘projects` table, we build an in-memory table using the project ids. Example: SELECT … FROM (VALUES (PROJECT_ID_1),(PROJECT_ID_2)) projects (id) INNER JOIN LATERAL (…)



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'app/models/release.rb', line 88

def latest_for_projects(projects, order_by: 'released_at')
  return Release.none if projects.empty?

  projects_table = Project.arel_table
  releases_table = Release.arel_table

  join_query = Release
    .where(projects_table[:id].eq(releases_table[:project_id]))
    .sort_by_attribute("#{order_by}_desc")
    .limit(1)

  project_ids_list = projects.map { |project| "(#{project.id})" }.join(',')

  Release
    .from("(VALUES #{project_ids_list}) projects (id)")
    .joins("INNER JOIN LATERAL (#{join_query.to_sql}) #{Release.table_name} ON TRUE")
end

.waiting_for_publish_eventObject



106
107
108
# File 'app/models/release.rb', line 106

def waiting_for_publish_event
  unpublished.released_within_2hrs.joins(:project).merge(Project.with_feature_enabled(:releases)).limit(MAX_NUMBER_TO_PUBLISH)
end

Instance Method Details

#assets_count(except: []) ⇒ Object



129
130
131
132
133
134
# File 'app/models/release.rb', line 129

def assets_count(except: [])
  links_count = links.size
  sources_count = except.include?(:sources) ? 0 : sources.size

  links_count + sources_count
end

#commitObject



119
120
121
122
123
# File 'app/models/release.rb', line 119

def commit
  strong_memoize(:commit) do
    repository.commit(actual_sha)
  end
end

#execute_hooks(action) ⇒ Object



162
163
164
165
# File 'app/models/release.rb', line 162

def execute_hooks(action)
  hook_data = to_hook_data(action)
  project.execute_hooks(hook_data, :release_hooks)
end

#historical_release?Boolean

Returns:

  • (Boolean)


146
147
148
# File 'app/models/release.rb', line 146

def historical_release?
  released_at.present? && released_at.to_i < created_at.to_i
end

#milestone_titlesObject



154
155
156
# File 'app/models/release.rb', line 154

def milestone_titles
  self.milestones.order_by_dates_and_title.map(&:title).join(', ')
end

#nameObject



150
151
152
# File 'app/models/release.rb', line 150

def name
  self.read_attribute(:name) || tag
end


167
168
169
170
171
172
173
# File 'app/models/release.rb', line 167

def related_deployments
  Deployment
    .with(Gitlab::SQL::CTE.new(:available_environments, project.environments.available.select(:id)).to_arel)
    .where('environment_id IN (SELECT * FROM available_environments)')
    .where(ref: tag)
    .with_environment_page_associations
end

#sha_unchangedObject



111
112
113
# File 'app/models/release.rb', line 111

def sha_unchanged
  errors.add(:sha, "cannot be changed") if sha_changed?
end

#sourcesObject



136
137
138
139
140
# File 'app/models/release.rb', line 136

def sources
  strong_memoize(:sources) do
    Releases::Source.all(project, tag)
  end
end

#tag_missing?Boolean

Returns:

  • (Boolean)


125
126
127
# File 'app/models/release.rb', line 125

def tag_missing?
  actual_tag.nil?
end

#to_hook_data(action) ⇒ Object



158
159
160
# File 'app/models/release.rb', line 158

def to_hook_data(action)
  Gitlab::HookData::ReleaseBuilder.new(self).build(action)
end

#to_paramObject



115
116
117
# File 'app/models/release.rb', line 115

def to_param
  tag
end

#upcoming_release?Boolean

Returns:

  • (Boolean)


142
143
144
# File 'app/models/release.rb', line 142

def upcoming_release?
  released_at.present? && released_at.to_i > Time.zone.now.to_i
end