Skip to content
Snippets Groups Projects
Commit 8f210aeb authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 996f7009
No related branches found
No related tags found
No related merge requests found
Showing
with 250 additions and 487 deletions
Loading
Loading
@@ -239,6 +239,7 @@ static-analysis:
dependencies: ["setup-test-env", "compile-assets pull-cache"]
variables:
SETUP_DB: "false"
parallel: 2
script:
- scripts/static-analysis
cache:
Loading
Loading
Loading
Loading
@@ -343,6 +343,8 @@ linters:
- 'app/views/projects/triggers/_index.html.haml'
- 'app/views/projects/triggers/_trigger.html.haml'
- 'app/views/projects/triggers/edit.html.haml'
- 'app/views/projects/wikis/_new.html.haml'
- 'app/views/projects/wikis/_pages_wiki_page.html.haml'
- 'app/views/projects/wikis/edit.html.haml'
- 'app/views/projects/wikis/history.html.haml'
- 'app/views/repository_check_mailer/notify.html.haml'
Loading
Loading
Loading
Loading
@@ -16,10 +16,25 @@
# Uncomment the following lines to make the configuration take effect.
 
PreCommit:
AuthorName:
enabled: false
EsLint:
enabled: true
# https://github.com/sds/overcommit/issues/338
command: './node_modules/eslint/bin/eslint.js'
HamlLint:
enabled: true
MergeConflicts:
enabled: true
exclude:
- '**/conflict/file_spec.rb'
- '**/git/conflict/parser_spec.rb'
# prettier? https://github.com/sds/overcommit/issues/614 https://github.com/sds/overcommit/issues/390#issuecomment-495703284
RuboCop:
enabled: true
# on_warn: fail # Treat all warnings as failures
#
ScssLint:
enabled: true
#PostCheckout:
# ALL: # Special hook name that customizes all hooks of this type
# quiet: true # Change all post-checkout hooks to only display output on failure
Loading
Loading
// currently, this controller inherits all behaviors from wikis
import '../wikis/index';
import $ from 'jquery';
import Vue from 'vue';
import Translate from '~/vue_shared/translate';
import csrf from '~/lib/utils/csrf';
import ShortcutsWiki from '~/behaviors/shortcuts/shortcuts_wiki';
import ZenMode from '~/zen_mode';
import GLForm from '~/gl_form';
import deleteWikiModal from '../wikis/components/delete_wiki_modal.vue';
import Wikis from '../wikis/wikis';
document.addEventListener('DOMContentLoaded', () => {
new Wikis(); // eslint-disable-line no-new
new ShortcutsWiki(); // eslint-disable-line no-new
new ZenMode(); // eslint-disable-line no-new
new GLForm($('.wiki-form')); // eslint-disable-line no-new
const deleteWikiModalWrapperEl = document.getElementById('delete-wiki-modal-wrapper');
if (deleteWikiModalWrapperEl) {
Vue.use(Translate);
const { deleteWikiUrl, pageTitle } = deleteWikiModalWrapperEl.dataset;
// eslint-disable-next-line no-new
new Vue({
el: deleteWikiModalWrapperEl,
data: {
deleteWikiUrl: '',
},
render(createElement) {
return createElement(deleteWikiModal, {
props: {
pageTitle,
deleteWikiUrl,
csrfToken: csrf.token,
},
});
},
});
}
});
import $ from 'jquery';
import Vue from 'vue';
import Translate from '~/vue_shared/translate';
import csrf from '~/lib/utils/csrf';
import ShortcutsWiki from '~/behaviors/shortcuts/shortcuts_wiki';
import GLForm from '~/gl_form';
import Wikis from './wikis';
import ZenMode from '../../../zen_mode';
import GLForm from '../../../gl_form';
import deleteWikiModal from './components/delete_wiki_modal.vue';
 
document.addEventListener('DOMContentLoaded', () => {
new Wikis(); // eslint-disable-line no-new
new ShortcutsWiki(); // eslint-disable-line no-new
new ZenMode(); // eslint-disable-line no-new
new GLForm($('.wiki-form')); // eslint-disable-line no-new
const deleteWikiModalWrapperEl = document.getElementById('delete-wiki-modal-wrapper');
if (deleteWikiModalWrapperEl) {
Vue.use(Translate);
const { deleteWikiUrl, pageTitle } = deleteWikiModalWrapperEl.dataset;
// eslint-disable-next-line no-new
new Vue({
el: deleteWikiModalWrapperEl,
data: {
deleteWikiUrl: '',
},
render(createElement) {
return createElement(deleteWikiModal, {
props: {
pageTitle,
deleteWikiUrl,
csrfToken: csrf.token,
},
});
},
});
}
});
Loading
Loading
@@ -12,8 +12,8 @@ export default class Wikis {
}
 
this.isNewWikiPage = Boolean(document.querySelector('.js-new-wiki-page'));
this.editTitleInput = document.querySelector('form.wiki-form #wiki_page_title');
this.commitMessageInput = document.querySelector('form.wiki-form #wiki_page_message');
this.editTitleInput = document.querySelector('form.wiki-form #wiki_title');
this.commitMessageInput = document.querySelector('form.wiki-form #wiki_message');
this.commitMessageI18n = this.isNewWikiPage
? s__('WikiPageCreate|Create %{pageTitle}')
: s__('WikiPageEdit|Update %{pageTitle}');
Loading
Loading
Loading
Loading
@@ -99,18 +99,3 @@
justify-content: center;
color: $gray-700;
}
.svg-icon {
display: inline-flex;
align-self: center;
svg {
height: 1em;
width: 1em;
}
&.svg-baseline svg {
top: 0.125em;
position: relative;
}
}
.new-wiki-page {
.new-wiki-page-slug-tip {
display: inline-block;
max-width: 100%;
margin-top: 5px;
}
}
.wiki-history,
.wiki-page,
.edit-wiki-page {
margin-right: $gutter-width;
}
.edit-wiki-page {
@media only screen and (min-width: map-get($grid-breakpoints, lg) + (2 * $gutter-width)) and (max-width: map-get($grid-breakpoints, lg) + (3 * $gutter-width)) {
margin-right: $gutter-width * 1.5;
}
}
.wiki-form {
.edit-wiki-page-slug-tip {
display: inline-block;
max-width: 100%;
margin-top: 5px;
}
}
.title .edit-wiki-header {
width: 780px;
margin-left: auto;
Loading
Loading
@@ -33,15 +5,6 @@
padding-right: 7px;
}
 
.container-fluid.wiki-page,
.container-fluid.edit-wiki-page {
width: initial;
}
.wiki-history.breadcrumbs {
min-height: (2 * $gl-padding) + 22;
}
.wiki-page-header {
position: relative;
 
Loading
Loading
@@ -116,7 +79,7 @@
}
 
.sidebar-container {
padding-bottom: $gl-padding;
padding: $gl-padding 0;
width: calc(100% + 100px);
padding-right: 100px;
height: 100%;
Loading
Loading
@@ -162,7 +125,7 @@
}
 
.wiki-sidebar-header {
padding: $gl-padding;
padding: 0 $gl-padding $gl-padding;
 
.gutter-toggle {
margin-top: 0;
Loading
Loading
Loading
Loading
@@ -9,10 +9,11 @@ module PreviewMarkdown
 
markdown_params =
case controller_name
when 'wikis' then { pipeline: :wiki, project_wiki: @project_wiki, page_slug: params[:id] }
when 'snippets' then { skip_project_check: true }
when 'groups' then { group: group }
when 'projects' then projects_filter_params
else preview_markdown_params
else {}
end
 
render json: {
Loading
Loading
@@ -24,7 +25,6 @@ module PreviewMarkdown
}
}
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
 
private
 
Loading
Loading
@@ -35,12 +35,8 @@ module PreviewMarkdown
}
end
 
# Override this method to customise the markdown for your controller
def preview_markdown_params
{}
end
def markdown_service_params
params
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
end
# frozen_string_literal: true
# Controllers that include this concern must provide:
# * project
# * current_user
module ProjectWikiActions
extend ActiveSupport::Concern
included do
before_action :authorize_read_wiki!
before_action :init_wiki_actions
attr_accessor :project_wiki, :sidebar_page, :sidebar_wiki_entries
end
def init_wiki_actions
load_project_wiki
load_wiki_sidebar
rescue ProjectWiki::CouldNotCreateWikiError
flash[:notice] = _("Could not create Wiki Repository at this time. Please try again later.")
redirect_to project_path(project)
end
def load_project_wiki
self.project_wiki = load_wiki
end
def load_wiki_sidebar
self.sidebar_page = project_wiki.find_sidebar(params[:version_id])
return if sidebar_page.present?
# Fallback to default sidebar
self.sidebar_wiki_entries = WikiDirectory.group_by_directory(project_wiki.list_pages(limit: 15))
end
def load_wiki
# Call #wiki to make sure the Wiki Repo is initialized
ProjectWiki.new(project, current_user).tap(&:wiki)
end
end
# frozen_string_literal: true
class Projects::WikiDirectoriesController < Projects::ApplicationController
include ProjectWikiActions
def self.local_prefixes
[controller_path, 'shared/wiki']
end
def show
@wiki_dir = find_dir || WikiDirectory.new(params[:id])
return render('empty') if @wiki_dir.empty?
@wiki_entries = @wiki_pages = Kaminari
.paginate_array(@wiki_dir.pages)
.page(params[:page])
render 'show'
end
private
def find_dir
dir_params = params.permit(:id, :sort, :direction).dup.tap do |h|
Gitlab::Utils.allow_hash_values(h, sort_params_config[:allowed])
end
project_wiki.find_dir(dir_params[:id], dir_params[:sort], dir_params[:direction])
end
end
# frozen_string_literal: true
class Projects::WikiPagesController < Projects::ApplicationController
include ProjectWikiActions
include SendsBlob
include PreviewMarkdown
include Gitlab::Utils::StrongMemoize
def self.local_prefixes
[controller_path, 'shared/wiki']
end
before_action :authorize_create_wiki!, only: [:edit, :create, :update]
before_action :authorize_admin_wiki!, only: :destroy
before_action :load_page, only: [:show, :edit, :update, :history, :destroy]
before_action :valid_encoding?,
if: -> { %w[show edit update].include?(action_name) && load_page }
before_action only: [:edit, :update], unless: :valid_encoding? do
redirect_to(project_wiki_path(@project, @page))
end
def new
redirect_to project_wiki_path(@project, SecureRandom.uuid, random_title: true)
end
# `#show` handles a number of scenarios:
#
# - If `id` matches a WikiPage, then show the wiki page.
# - If `id` is a file in the wiki repository, then send the file.
# - If we know the user wants to create a new page with the given `id`,
# then display a create form.
# - Otherwise show the empty wiki page and invite the user to create a page.
def show
if @page
show_page
elsif file_blob
show_blob
elsif should_create_missing_page?
create_missing_page
else
render 'missing_page'
end
end
def edit
end
def update
@page = WikiPages::UpdateService
.new(@project, current_user, wiki_params)
.execute(@page)
return saved(:updated) if @page.valid?
render 'edit'
rescue WikiPage::PageChangedError, WikiPage::PageRenameError, Gitlab::Git::Wiki::OperationError => e
@error = e
render 'edit'
end
def create
@page = WikiPages::CreateService
.new(@project, current_user, wiki_params)
.execute
return saved(:created) if @page.persisted?
render action: "edit"
rescue Gitlab::Git::Wiki::OperationError => e
@page = project_wiki.build_page(wiki_params)
@error = e
render 'edit'
end
def history
if @page
@page_versions = Kaminari.paginate_array(@page.versions(page: params[:page].to_i),
total_count: @page.count_versions)
.page(params[:page])
else
redirect_to(
project_wiki_path(@project, :home),
notice: _("Page not found")
)
end
end
def destroy
WikiPages::DestroyService.new(@project, current_user).execute(@page)
redirect_to project_wiki_path(@project, :home),
status: 302,
notice: _("Page was successfully deleted")
rescue Gitlab::Git::Wiki::OperationError => e
@error = e
render 'edit'
end
private
# Callback for PreviewMarkdown
def preview_markdown_params
{ pipeline: :wiki, project_wiki: project_wiki, page_slug: params[:id] }
end
def show_page
set_encoding_error unless valid_encoding?
@page_dir = @project_wiki.find_dir(@page.directory) if @page.directory.present?
@show_children = true
render 'show'
end
def show_blob
send_blob(@project_wiki.repository, file_blob)
end
def should_create_missing_page?
view_param = @project_wiki.exists? ? 'create' : params[:view]
view_param == 'create' && can?(current_user, :create_wiki, @project)
end
def create_missing_page
# Assign a title to the WikiPage unless `id` is a randomly generated slug from #new
title = params[:id] unless params[:random_title].present?
@page = project_wiki.build_page(title: title)
render 'edit'
end
def wiki_params
params.require(:wiki_page).permit(:title, :content, :format, :message, :last_commit_sha)
end
def load_page
@page ||= @project_wiki.find_page(*page_params)
end
def page_params
keys = [:id]
keys << :version_id if params[:action] == 'show'
params.values_at(*keys)
end
def valid_encoding?
strong_memoize(:valid_encoding) do
@page.content.encoding == Encoding::UTF_8
end
end
def set_encoding_error
flash.now[:notice] = _("The content of this page is not encoded in UTF-8. Edits can only be made via the Git repository.")
end
def file_blob
strong_memoize(:file_blob) do
commit = @project_wiki.repository.commit(@project_wiki.default_branch)
next unless commit
@project_wiki.repository.blob_at(commit.id, params[:id])
end
end
def saved(action)
msg = case action
when :updated
_('Wiki was successfully updated')
when :created
_('Wiki was successfully created')
end
redirect_to(project_wiki_path(@project, @page), notice: msg)
end
end
# frozen_string_literal: true
 
class Projects::WikisController < Projects::ApplicationController
include ProjectWikiActions
include WikiHelper
include PreviewMarkdown
include SendsBlob
include Gitlab::Utils::StrongMemoize
 
def self.local_prefixes
[controller_path, 'shared/wiki']
before_action :authorize_read_wiki!
before_action :authorize_create_wiki!, only: [:edit, :create]
before_action :authorize_admin_wiki!, only: :destroy
before_action :load_project_wiki
before_action :load_page, only: [:show, :edit, :update, :history, :destroy]
before_action :valid_encoding?,
if: -> { %w[show edit update].include?(action_name) && load_page }
before_action only: [:edit, :update], unless: :valid_encoding? do
redirect_to(project_wiki_path(@project, @page))
end
def new
redirect_to project_wiki_path(@project, SecureRandom.uuid, random_title: true)
end
 
def pages
@nesting = show_children_param
@show_children = @nesting != ProjectWiki::NESTING_CLOSED
@wiki_pages = Kaminari.paginate_array(
project_wiki.list_pages(**sort_params)
@project_wiki.list_pages(sort: params[:sort], direction: params[:direction])
).page(params[:page])
 
@wiki_entries = case @nesting
when ProjectWiki::NESTING_FLAT
@wiki_pages
else
WikiDirectory.group_by_directory(@wiki_pages)
end
@wiki_entries = WikiPage.group_by_directory(@wiki_pages)
end
# `#show` handles a number of scenarios:
#
# - If `id` matches a WikiPage, then show the wiki page.
# - If `id` is a file in the wiki repository, then send the file.
# - If we know the user wants to create a new page with the given `id`,
# then display a create form.
# - Otherwise show the empty wiki page and invite the user to create a page.
def show
if @page
set_encoding_error unless valid_encoding?
render 'show'
elsif file_blob
send_blob(@project_wiki.repository, file_blob)
elsif show_create_form?
# Assign a title to the WikiPage unless `id` is a randomly generated slug from #new
title = params[:id] unless params[:random_title].present?
@page = build_page(title: title)
render 'edit'
else
render 'empty'
end
end
def edit
end
def update
return render('empty') unless can?(current_user, :create_wiki, @project)
@page = WikiPages::UpdateService.new(@project, current_user, wiki_params).execute(@page)
if @page.valid?
redirect_to(
project_wiki_path(@project, @page),
notice: _('Wiki was successfully updated.')
)
else
render 'edit'
end
rescue WikiPage::PageChangedError, WikiPage::PageRenameError, Gitlab::Git::Wiki::OperationError => e
@error = e
render 'edit'
end
def create
@page = WikiPages::CreateService.new(@project, current_user, wiki_params).execute
if @page.persisted?
redirect_to(
project_wiki_path(@project, @page),
notice: _('Wiki was successfully updated.')
)
else
render action: "edit"
end
rescue Gitlab::Git::Wiki::OperationError => e
@page = build_page(wiki_params)
@error = e
render 'edit'
end
def history
if @page
@page_versions = Kaminari.paginate_array(@page.versions(page: params[:page].to_i),
total_count: @page.count_versions)
.page(params[:page])
else
redirect_to(
project_wiki_path(@project, :home),
notice: _("Page not found")
)
end
end
def destroy
WikiPages::DestroyService.new(@project, current_user).execute(@page)
 
render 'show'
redirect_to project_wiki_path(@project, :home),
status: 302,
notice: _("Page was successfully deleted")
rescue Gitlab::Git::Wiki::OperationError => e
@error = e
render 'edit'
end
 
def git_access
Loading
Loading
@@ -30,13 +122,74 @@ class Projects::WikisController < Projects::ApplicationController
 
private
 
def sort_params
process_params(sort_params_config)
def show_create_form?
can?(current_user, :create_wiki, @project) &&
@page.nil? &&
# Always show the create form when the wiki has had at least one page created.
# Otherwise, we only show the form when the user has navigated from
# the 'empty wiki' page
(@project_wiki.exists? || params[:view] == 'create')
end
 
def show_children_param
config = nesting_params_config(params[:sort])
def load_project_wiki
@project_wiki = load_wiki
# Call #wiki to make sure the Wiki Repo is initialized
@project_wiki.wiki
@sidebar_page = @project_wiki.find_sidebar(params[:version_id])
unless @sidebar_page # Fallback to default sidebar
@sidebar_wiki_entries = WikiPage.group_by_directory(@project_wiki.list_pages(limit: 15))
end
rescue ProjectWiki::CouldNotCreateWikiError
flash[:notice] = _("Could not create Wiki Repository at this time. Please try again later.")
redirect_to project_path(@project)
false
end
def load_wiki
ProjectWiki.new(@project, current_user)
end
def wiki_params
params.require(:wiki).permit(:title, :content, :format, :message, :last_commit_sha)
end
def build_page(args = {})
WikiPage.new(@project_wiki).tap do |page|
page.update_attributes(args) # rubocop:disable Rails/ActiveRecordAliases
end
end
def load_page
@page ||= @project_wiki.find_page(*page_params)
end
def page_params
keys = [:id]
keys << :version_id if params[:action] == 'show'
params.values_at(*keys)
end
def valid_encoding?
strong_memoize(:valid_encoding) do
@page.content.encoding == Encoding::UTF_8
end
end
def set_encoding_error
flash.now[:notice] = _("The content of this page is not encoded in UTF-8. Edits can only be made via the Git repository.")
end
def file_blob
strong_memoize(:file_blob) do
commit = @project_wiki.repository.commit(@project_wiki.default_branch)
next unless commit
 
process_params(config)
@project_wiki.repository.blob_at(commit.id, params[:id])
end
end
end
Loading
Loading
@@ -290,6 +290,7 @@ module ApplicationSettingsHelper
:snowplow_cookie_domain,
:snowplow_enabled,
:snowplow_site_id,
:snowplow_iglu_registry_url,
:push_event_hooks_limit,
:push_event_activities_limit,
:custom_http_clone_url_root,
Loading
Loading
Loading
Loading
@@ -41,12 +41,6 @@ module IconsHelper
ActionController::Base.helpers.image_path('file_icons.svg', host: sprite_base_url)
end
 
def sprite_icon_with_text(icon_name, content, opts = {})
wrapper_class = opts.delete(:wrapper_class)
icon = sprite_icon(icon_name, opts)
content_tag(:span, [icon, content].join('').html_safe, class: wrapper_class)
end
def sprite_icon(icon_name, size: nil, css_class: nil)
if Gitlab::Sentry.should_raise_for_dev?
unless known_sprites.include?(icon_name)
Loading
Loading
Loading
Loading
@@ -48,23 +48,14 @@ module WikiHelper
expose_url(api_v4_projects_wikis_attachments_path(id: @project.id))
end
 
WIKI_SORT_CSS_CLASSES = 'btn btn-default has-tooltip reverse-sort-btn qa-reverse-sort rspec-reverse-sort'
def wiki_sort_controls(sort_params = {}, &block)
current_sort = sort_params[:sort] || ProjectWiki::TITLE_ORDER
current_direction = (sort_params[:direction] || 'asc').inquiry
reversed_direction = current_direction.desc? ? 'asc' : 'desc'
icon_class = current_direction.desc? ? 'highest' : 'lowest'
sorting = sort_params.merge(sort: current_sort, direction: reversed_direction)
opts = {
type: 'button',
class: WIKI_SORT_CSS_CLASSES,
title: _('Sort direction')
}
link_to(yield(sorting), opts) do
def wiki_sort_controls(project, sort, direction)
sort ||= ProjectWiki::TITLE_ORDER
link_class = 'btn btn-default has-tooltip reverse-sort-btn qa-reverse-sort rspec-reverse-sort'
reversed_direction = direction == 'desc' ? 'asc' : 'desc'
icon_class = direction == 'desc' ? 'highest' : 'lowest'
link_to(project_wikis_pages_path(project, sort: sort, direction: reversed_direction),
type: 'button', class: link_class, title: _('Sort direction')) do
sprite_icon("sort-#{icon_class}", size: 16)
end
end
Loading
Loading
@@ -76,86 +67,4 @@ module WikiHelper
s_("Wiki|Title")
end
end
# Render the sprite icon given the current show_children state
def wiki_show_children_icon(nesting)
icon_name, icon_text =
case nesting
when ProjectWiki::NESTING_TREE
['folder-open', s_("Wiki|Show folder contents")]
when ProjectWiki::NESTING_CLOSED
['folder-o', s_("Wiki|Hide folder contents")]
else
['list-bulleted', s_("Wiki|Show files separately")]
end
sprite_icon_with_text(icon_name, icon_text, size: 16)
end
def wiki_page_link(wiki_page, nesting, project)
link = link_to(wiki_page.title,
project_wiki_path(project, wiki_page),
class: 'wiki-page-title')
case nesting
when ProjectWiki::NESTING_FLAT
tags = []
if wiki_page.directory.present?
wiki_dir = WikiDirectory.new(wiki_page.directory)
tags << link_to(wiki_dir.slug, project_wiki_dir_path(project, wiki_dir), class: 'wiki-page-dir-name')
tags << content_tag(:span, '/', class: 'wiki-page-name-separator')
end
tags << link
tags.join.html_safe
else
link
end
end
def sort_params_config
{
keys: [:sort, :direction],
defaults: {
sort: ProjectWiki::TITLE_ORDER, direction: ProjectWiki::DIRECTION_ASC
},
allowed: {
sort: ProjectWiki::SORT_ORDERS, direction: ProjectWiki::SORT_DIRECTIONS
}
}
end
def nesting_params_config(sort_key)
default_val = case sort_key
when ProjectWiki::CREATED_AT_ORDER
ProjectWiki::NESTING_FLAT
else
ProjectWiki::NESTING_CLOSED
end
{
keys: [:show_children],
defaults: { show_children: default_val },
allowed: { show_children: ProjectWiki::NESTINGS }
}
end
def process_params(config)
unprocessed = params.permit(*config[:keys])
processed = unprocessed
.with_defaults(config[:defaults])
.tap { |h| Gitlab::Utils.allow_hash_values(h, config[:allowed]) }
.to_hash
.transform_keys(&:to_sym)
if processed.keys == config[:keys]
processed.size == 1 ? processed.values.first : processed
else
raise ActionController::BadRequest, "illegal parameters: #{unprocessed}"
end
end
def home_page?
params[:id] == 'home'
end
end
Loading
Loading
@@ -104,6 +104,11 @@ class ApplicationSetting < ApplicationRecord
hostname: true,
if: :snowplow_enabled
 
validates :snowplow_iglu_registry_url,
addressable_url: true,
allow_blank: true,
if: :snowplow_enabled
validates :pendo_url,
presence: true,
public_url: true,
Loading
Loading
Loading
Loading
@@ -129,6 +129,7 @@ module ApplicationSettingImplementation
snowplow_cookie_domain: nil,
snowplow_enabled: false,
snowplow_site_id: nil,
snowplow_iglu_registry_url: nil,
custom_http_clone_url_root: nil,
pendo_enabled: false,
pendo_url: nil
Loading
Loading
Loading
Loading
@@ -75,6 +75,11 @@ class Deployment < ApplicationRecord
find(ids)
end
 
def self.distinct_on_environment
order('environment_id, deployments.id DESC')
.select('DISTINCT ON (environment_id) deployments.*')
end
def self.find_successful_deployment!(iid)
success.find_by!(iid: iid)
end
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment