summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-09-29 06:09:45 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-09-29 06:09:45 +0000
commitcd54f7e81bbedff94ea78092f44fb67bd8c2ac57 (patch)
tree588056e7ded7fbefe4f1158a550dcc2d581aa178
parentf574f9a14bb6448935fd27a67fc9f3ca61ffcc86 (diff)
downloadgitlab-ce-cd54f7e81bbedff94ea78092f44fb67bd8c2ac57.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/boards/index.js11
-rw-r--r--app/assets/javascripts/pages/projects/pipeline_schedules/shared/icons/intro_illustration.svg1
-rw-r--r--app/assets/stylesheets/_page_specific_files.scss1
-rw-r--r--app/assets/stylesheets/page_bundles/cycle_analytics.scss (renamed from app/assets/stylesheets/pages/cycle_analytics.scss)44
-rw-r--r--app/assets/stylesheets/pages/pipelines.scss166
-rw-r--r--app/assets/stylesheets/themes/_dark.scss2
-rw-r--r--app/controllers/projects/static_site_editor_controller.rb7
-rw-r--r--app/helpers/clusters_helper.rb8
-rw-r--r--app/services/static_site_editor/config_service.rb64
-rw-r--r--app/views/clusters/clusters/_buttons.html.haml6
-rw-r--r--app/views/clusters/clusters/_cluster.html.haml19
-rw-r--r--app/views/clusters/clusters/index.html.haml26
-rw-r--r--app/views/projects/cycle_analytics/show.html.haml2
-rw-r--r--app/views/projects/pipeline_schedules/index.html.haml2
-rw-r--r--app/views/shared/labels/_form.html.haml6
-rw-r--r--app/views/shared/labels/_nav.html.haml6
-rw-r--r--changelogs/unreleased/231209-labels-buttons.yml5
-rw-r--r--changelogs/unreleased/add-sse-config-file-3.yml6
-rw-r--r--config/application.rb22
-rw-r--r--config/feature_flags/development/allow_unsafe_ruby_regexp.yml4
-rw-r--r--config/feature_flags/development/ci_disable_validates_dependencies.yml6
-rw-r--r--config/feature_flags/development/clusters_list_redesign.yml7
-rw-r--r--doc/integration/elasticsearch.md191
-rw-r--r--doc/user/application_security/dependency_scanning/index.md79
-rw-r--r--doc/user/clusters/agent/index.md4
-rw-r--r--lib/gitlab/static_site_editor/config/file_config.rb35
-rw-r--r--lib/gitlab/static_site_editor/config/file_config/entry/global.rb31
-rw-r--r--lib/gitlab/static_site_editor/config/file_config/entry/static_site_generator.rb26
-rw-r--r--locale/gitlab.pot9
-rw-r--r--spec/controllers/projects/static_site_editor_controller_spec.rb7
-rw-r--r--spec/features/projects/clusters_spec.rb30
-rw-r--r--spec/helpers/clusters_helper_spec.rb26
-rw-r--r--spec/lib/gitlab/static_site_editor/config/file_config/entry/global_spec.rb182
-rw-r--r--spec/lib/gitlab/static_site_editor/config/file_config/entry/static_site_generator_spec.rb50
-rw-r--r--spec/lib/gitlab/static_site_editor/config/file_config_spec.rb90
-rw-r--r--spec/services/static_site_editor/config_service_spec.rb86
36 files changed, 848 insertions, 419 deletions
diff --git a/app/assets/javascripts/boards/index.js b/app/assets/javascripts/boards/index.js
index df6792023ed..dd4d075a042 100644
--- a/app/assets/javascripts/boards/index.js
+++ b/app/assets/javascripts/boards/index.js
@@ -155,7 +155,13 @@ export default () => {
}
},
methods: {
- ...mapActions(['setInitialBoardData', 'setFilters', 'fetchEpicsSwimlanes', 'resetIssues']),
+ ...mapActions([
+ 'setInitialBoardData',
+ 'setFilters',
+ 'fetchEpicsSwimlanes',
+ 'resetIssues',
+ 'resetEpics',
+ ]),
initialBoardLoad() {
boardsStore
.all()
@@ -176,7 +182,8 @@ export default () => {
performSearch() {
this.setFilters(convertObjectPropsToCamelCase(urlParamsToObject(window.location.search)));
if (gon.features.boardsWithSwimlanes && this.isShowingEpicsSwimlanes) {
- this.fetchEpicsSwimlanes(false);
+ this.resetEpics();
+ this.fetchEpicsSwimlanes({ withLists: false });
this.resetIssues();
}
},
diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/icons/intro_illustration.svg b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/icons/intro_illustration.svg
deleted file mode 100644
index 26d1ff97b3e..00000000000
--- a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/icons/intro_illustration.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg width="140" height="102" viewBox="0 0 140 102" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><title>illustration</title><defs><rect id="a" width="12.033" height="40.197" rx="3"/><rect id="b" width="12.033" height="40.197" rx="3"/></defs><g fill="none" fill-rule="evenodd"><g transform="translate(-.446)"><path d="M91.747 35.675v-6.039a2.996 2.996 0 0 0-2.999-3.005H54.635a2.997 2.997 0 0 0-2.999 3.005v6.039H40.092a3.007 3.007 0 0 0-2.996 3.005v34.187a2.995 2.995 0 0 0 2.996 3.005h11.544V79.9a2.996 2.996 0 0 0 2.999 3.005h34.113a2.997 2.997 0 0 0 2.999-3.005v-4.03h11.544a3.007 3.007 0 0 0 2.996-3.004V38.68a2.995 2.995 0 0 0-2.996-3.005H91.747z" stroke="#B5A7DD" stroke-width="2"/><rect stroke="#E5E5E5" stroke-width="2" fill="#FFF" x="21.556" y="38.69" width="98.27" height="34.167" rx="3"/><path d="M121.325 38.19c.55 0 .995.444.995 1.002 0 .554-.453 1.003-.995 1.003h-4.039a1.004 1.004 0 0 1 0-2.006h4.039zm9.044 0c.55 0 .996.444.996 1.002 0 .554-.454 1.003-.996 1.003h-4.038a1.004 1.004 0 0 1 0-2.006h4.038zm9.044 0c.55 0 .996.444.996 1.002 0 .554-.453 1.003-.996 1.003h-4.038a1.004 1.004 0 0 1 0-2.006h4.038zM121.325 71.854a1.004 1.004 0 0 1 0 2.006h-4.039a1.004 1.004 0 0 1 0-2.006h4.039zm9.044 0a1.004 1.004 0 0 1 0 2.006h-4.038a1.004 1.004 0 0 1 0-2.006h4.038zm9.044 0a1.004 1.004 0 0 1 0 2.006h-4.038a1.004 1.004 0 0 1 0-2.006h4.038z" fill="#E5E5E5"/><g transform="translate(110.3 35.675)"><use fill="#FFF" xlink:href="#a"/><rect stroke="#FDE5D8" stroke-width="2" x="1" y="1" width="10.033" height="38.197" rx="3"/><ellipse fill="#FC8A51" cx="6.017" cy="9.547" rx="1.504" ry="1.507"/><ellipse fill="#FC8A51" cx="6.017" cy="20.099" rx="1.504" ry="1.507"/><ellipse fill="#FC8A51" cx="6.017" cy="30.65" rx="1.504" ry="1.507"/></g><path d="M6.008 38.19c.55 0 .996.444.996 1.002 0 .554-.454 1.003-.996 1.003H1.97a1.004 1.004 0 0 1 0-2.006h4.038zm9.044 0c.55 0 .996.444.996 1.002 0 .554-.453 1.003-.996 1.003h-4.038a1.004 1.004 0 0 1 0-2.006h4.038zm9.045 0c.55 0 .995.444.995 1.002 0 .554-.453 1.003-.995 1.003h-4.039a1.004 1.004 0 0 1 0-2.006h4.039zM6.008 71.854a1.004 1.004 0 0 1 0 2.006H1.97a1.004 1.004 0 0 1 0-2.006h4.038zm9.044 0a1.004 1.004 0 0 1 0 2.006h-4.038a1.004 1.004 0 0 1 0-2.006h4.038zm9.045 0a1.004 1.004 0 0 1 0 2.006h-4.039a1.004 1.004 0 0 1 0-2.006h4.039z" fill="#E5E5E5"/><g transform="translate(19.05 35.675)"><use fill="#FFF" xlink:href="#b"/><rect stroke="#FDE5D8" stroke-width="2" x="1" y="1" width="10.033" height="38.197" rx="3"/><ellipse fill="#FC8A51" cx="6.017" cy="10.049" rx="1.504" ry="1.507"/><ellipse fill="#FC8A51" cx="6.017" cy="20.601" rx="1.504" ry="1.507"/><ellipse fill="#FC8A51" cx="6.017" cy="31.153" rx="1.504" ry="1.507"/></g><g transform="translate(47.096)"><g transform="translate(7.05)"><ellipse fill="#FC8A51" cx="17.548" cy="5.025" rx="4.512" ry="4.522"/><rect stroke="#B5A7DD" stroke-width="2" fill="#FFF" x="13.036" y="4.02" width="9.025" height="20.099" rx="1.5"/><rect stroke="#FDE5D8" stroke-width="2" fill="#FFF" y="4.02" width="35.096" height="4.02" rx="2.01"/><rect stroke="#6B4FBB" stroke-width="2" fill="#FFF" x="4.512" y="18.089" width="26.072" height="17.084" rx="1.5"/></g><rect stroke="#6B4FBB" stroke-width="2" fill="#FFF" transform="rotate(-45 43.117 35.117)" x="38.168" y="31.416" width="9.899" height="7.403" rx="3.702"/><ellipse stroke="#6B4FBB" stroke-width="2" fill="#FFF" cx="25" cy="55" rx="25" ry="25"/><ellipse stroke="#6B4FBB" stroke-width="2" fill="#FFF" cx="25" cy="55" rx="21" ry="21"/><rect stroke="#6B4FBB" stroke-width="2" fill="#FFF" x="43.05" y="53.281" width="2.95" height="1.538" rx=".769"/><rect stroke="#6B4FBB" stroke-width="2" fill="#FFF" x="4.305" y="53.281" width="2.95" height="1.538" rx=".769"/><rect stroke="#6B4FBB" stroke-width="2" fill="#FFF" transform="rotate(90 25.153 74.422)" x="23.677" y="73.653" width="2.95" height="1.538" rx=".769"/><rect stroke="#6B4FBB" stroke-width="2" fill="#FFF" transform="rotate(90 25.153 35.51)" x="23.844" y="34.742" width="2.616" height="1.538" rx=".769"/><path d="M13.362 42.502c-.124-.543.198-.854.74-.69l2.321.704c.533.161.643.592.235.972l-.22.206 7.06 7.572a1.002 1.002 0 1 1-1.467 1.368l-7.06-7.573-.118.11c-.402.375-.826.248-.952-.304l-.54-2.365zM21.606 67.576c-.408.38-.84.255-.968-.295l-.551-2.363c-.127-.542.191-.852.725-.69l.288.089 3.027-9.901a1.002 1.002 0 1 1 1.918.586l-3.027 9.901.154.047c.525.16.627.592.213.977l-1.779 1.65z" fill="#FC8A51"/><ellipse stroke="#6B4FBB" stroke-width="2" fill="#FFF" cx="25.099" cy="54.768" rx="2.507" ry="2.512"/></g></g><path d="M52.697 96.966a1.004 1.004 0 0 1 2.006 0v4.038a1.004 1.004 0 0 1-2.006 0v-4.038zm0-9.044a1.004 1.004 0 0 1 2.006 0v4.038a1.004 1.004 0 0 1-2.006 0v-4.038zM86.29 96.966c0-.55.444-.996 1.002-.996.554 0 1.003.454 1.003.996v4.038a1.004 1.004 0 0 1-2.006 0v-4.038zm0-9.044c0-.55.444-.996 1.002-.996.554 0 1.003.453 1.003.996v4.038a1.004 1.004 0 0 1-2.006 0v-4.038z" fill="#E5E5E5"/></g></svg> \ No newline at end of file
diff --git a/app/assets/stylesheets/_page_specific_files.scss b/app/assets/stylesheets/_page_specific_files.scss
index 3380d93e3d7..e8899b0a430 100644
--- a/app/assets/stylesheets/_page_specific_files.scss
+++ b/app/assets/stylesheets/_page_specific_files.scss
@@ -6,7 +6,6 @@
@import './pages/ci_projects';
@import './pages/clusters';
@import './pages/commits';
-@import './pages/cycle_analytics';
@import './pages/deploy_keys';
@import './pages/detail_page';
@import './pages/dev_ops_report';
diff --git a/app/assets/stylesheets/pages/cycle_analytics.scss b/app/assets/stylesheets/page_bundles/cycle_analytics.scss
index c509bf121bc..3a5e2e4159d 100644
--- a/app/assets/stylesheets/pages/cycle_analytics.scss
+++ b/app/assets/stylesheets/page_bundles/cycle_analytics.scss
@@ -1,3 +1,5 @@
+@import 'mixins_and_variables_and_functions';
+
#cycle-analytics,
.cycle-analytics {
margin: 24px auto 0;
@@ -84,7 +86,7 @@
}
.text {
- color: $layout-link-gray;
+ color: var(--gray-500, $gray-500);
margin: 0;
}
@@ -127,14 +129,14 @@
line-height: 65px;
&.active {
- background: $blue-50;
- border-color: $blue-300;
- box-shadow: inset 4px 0 0 0 $blue-500;
+ background: var(--blue-50, $blue-50);
+ border-color: var(--blue-300, $blue-300);
+ box-shadow: inset 4px 0 0 0 var(--blue-500, $blue-500);
}
&:hover:not(.active) {
- background-color: $gray-lightest;
- box-shadow: inset 2px 0 0 0 $border-color;
+ background-color: var(--gray-10, $gray-10);
+ box-shadow: inset 2px 0 0 0 var(--border-color, $border-color);
cursor: pointer;
}
@@ -148,7 +150,7 @@
.stage-empty,
.not-available {
- color: $gl-text-color-secondary;
+ color: var(--gray-500, $gray-500);
}
}
}
@@ -172,7 +174,7 @@
}
.events-info {
- color: $gl-text-color-secondary;
+ color: var(--gray-500, $gray-500);
}
}
@@ -191,7 +193,7 @@
list-style-type: none;
padding: 0 0 $gl-padding;
margin: 0 $gl-padding $gl-padding;
- border-bottom: 1px solid $gray-darker;
+ border-bottom: 1px solid var(--gray-50, $gray-50);
&:last-child {
border-bottom: 0;
@@ -220,7 +222,7 @@
display: block;
a {
- color: $gl-text-color;
+ color: var(--gl-text-color, $gl-text-color);
}
}
}
@@ -232,24 +234,24 @@
.total-time {
font-size: $cycle-analytics-big-font;
- color: $gl-text-color;
+ color: var(--gl-text-color, $gl-text-color);
span {
- color: $gl-text-color;
+ color: var(--gl-text-color, $gl-text-color);
font-size: $gl-font-size;
}
}
.issue-date,
.build-date {
- color: $gl-text-color;
+ color: var(--gl-text-color, $gl-text-color);
}
.mr-link,
.issue-link,
.commit-author-link,
.issue-author-link {
- color: $gl-text-color;
+ color: var(--gl-text-color, $gl-text-color);
}
// Custom CSS for components
@@ -287,16 +289,16 @@
}
.item-build-name {
- color: $gl-text-color;
+ color: var(--gl-text-color, $gl-text-color);
}
.pipeline-id {
- color: $gl-text-color;
+ color: var(--gl-text-color, $gl-text-color);
padding: 0 3px 0 0;
}
.ref-name {
- color: $black;
+ color: var(--gray-900, $gray-900);
display: inline-block;
max-width: 180px;
text-overflow: ellipsis;
@@ -307,14 +309,14 @@
}
.commit-sha {
- color: $blue-600;
+ color: var(--blue-600, $blue-600);
line-height: 1.3;
vertical-align: top;
font-weight: $gl-font-weight-normal;
}
.fa {
- color: $gl-text-color-secondary;
+ color: var(--gray-500, $gray-500);
font-size: $code-font-size;
}
}
@@ -326,10 +328,10 @@
width: 75%;
margin: 0 auto;
padding-top: 130px;
- color: $gl-text-color-secondary;
+ color: var(--gray-500, $gray-500);
h4 {
- color: $gl-text-color;
+ color: var(--gl-text-color, $gl-text-color);
}
}
diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss
index 10ab32d1e9a..4e2ac94f5b2 100644
--- a/app/assets/stylesheets/pages/pipelines.scss
+++ b/app/assets/stylesheets/pages/pipelines.scss
@@ -322,9 +322,11 @@
}
}
-.admin-builds-table {
- .ci-table td:last-child {
- min-width: 120px;
+[data-page='admin:jobs:index'] {
+ .admin-builds-table {
+ td:last-child {
+ min-width: 120px;
+ }
}
}
@@ -333,110 +335,108 @@
border-bottom: 0;
}
-.tab-pane {
- &.builds .ci-table tr {
- height: 71px;
- }
-
- .ci-table {
- thead th {
- border-top: 0;
+[data-page='projects:pipelines:show'] {
+ .tab-pane {
+ .ci-table {
+ thead th {
+ border-top: 0;
+ }
}
}
-}
-.build-failures {
- .build-state {
- padding: 20px 2px;
+ .build-failures {
+ .build-state {
+ padding: 20px 2px;
- .build-name {
- font-weight: $gl-font-weight-normal;
- }
+ .build-name {
+ font-weight: $gl-font-weight-normal;
+ }
- .stage {
- color: $gl-text-color-secondary;
- font-weight: $gl-font-weight-normal;
- vertical-align: middle;
+ .stage {
+ color: $gl-text-color-secondary;
+ font-weight: $gl-font-weight-normal;
+ vertical-align: middle;
+ }
}
- }
- .build-log {
- border: 0;
- line-height: initial;
- }
+ .build-log {
+ border: 0;
+ line-height: initial;
+ }
- .build-trace-row td {
- border-top: 0;
- border-bottom-width: 1px;
- border-bottom-style: solid;
- padding-top: 0;
- }
+ .build-trace-row td {
+ border-top: 0;
+ border-bottom-width: 1px;
+ border-bottom-style: solid;
+ padding-top: 0;
+ }
- .build-trace {
- width: 100%;
- text-align: left;
- margin-top: $gl-padding;
- }
+ .build-trace {
+ width: 100%;
+ text-align: left;
+ margin-top: $gl-padding;
+ }
- .build-name {
- width: 196px;
+ .build-name {
+ width: 196px;
- a {
- font-weight: $gl-font-weight-bold;
- color: $gl-text-color;
- text-decoration: none;
+ a {
+ font-weight: $gl-font-weight-bold;
+ color: $gl-text-color;
+ text-decoration: none;
- &:focus,
- &:hover {
- text-decoration: underline;
+ &:focus,
+ &:hover {
+ text-decoration: underline;
+ }
}
}
- }
-
- .build-actions {
- width: 70px;
- text-align: right;
- }
- .build-stage {
- width: 140px;
- }
-
- .ci-status-icon-failed {
- padding: 10px 0 10px 12px;
- width: 12px + 24px; // padding-left + svg width
- }
-
- .build-icon svg {
- width: 24px;
- height: 24px;
- vertical-align: middle;
- }
+ .build-actions {
+ width: 70px;
+ text-align: right;
+ }
- .build-state,
- .build-trace-row {
- > td:last-child {
- padding-right: 0;
+ .build-stage {
+ width: 140px;
}
- }
- @include media-breakpoint-down(sm) {
- td:empty {
- display: none;
+ .ci-status-icon-failed {
+ padding: 10px 0 10px 12px;
+ width: 12px + 24px; // padding-left + svg width
}
- .ci-table {
- margin-top: 2 * $gl-padding;
+ .build-icon svg {
+ width: 24px;
+ height: 24px;
+ vertical-align: middle;
}
- .build-trace-container {
- padding-top: $gl-padding;
- padding-bottom: $gl-padding;
+ .build-state,
+ .build-trace-row {
+ > td:last-child {
+ padding-right: 0;
+ }
}
- .build-trace {
- margin-bottom: 0;
- margin-top: 0;
+ @include media-breakpoint-down(sm) {
+ td:empty {
+ display: none;
+ }
+
+ .ci-table {
+ margin-top: 2 * $gl-padding;
+ }
+
+ .build-trace-container {
+ padding-top: $gl-padding;
+ padding-bottom: $gl-padding;
+ }
+
+ .build-trace {
+ margin-bottom: 0;
+ margin-top: 0;
+ }
}
}
}
diff --git a/app/assets/stylesheets/themes/_dark.scss b/app/assets/stylesheets/themes/_dark.scss
index bfbcb8c13c6..cd607e9b247 100644
--- a/app/assets/stylesheets/themes/_dark.scss
+++ b/app/assets/stylesheets/themes/_dark.scss
@@ -163,6 +163,8 @@ body.gl-dark {
--gl-text-color: #{$gray-900};
--border-color: #{$border-color};
+
+ --white: #{$white};
}
$border-white-light: $gray-900;
diff --git a/app/controllers/projects/static_site_editor_controller.rb b/app/controllers/projects/static_site_editor_controller.rb
index e97a8db0b79..a6ed044f92e 100644
--- a/app/controllers/projects/static_site_editor_controller.rb
+++ b/app/controllers/projects/static_site_editor_controller.rb
@@ -27,7 +27,12 @@ class Projects::StaticSiteEditorController < Projects::ApplicationController
if service_response.success?
@data = service_response.payload
else
- respond_422
+ # TODO: For now, if the service returns any error, the user is redirected
+ # to the root project page with the error message displayed as an alert.
+ # See https://gitlab.com/gitlab-org/gitlab/-/issues/213285#note_414808004
+ # for discussion of plans to handle this via a page owned by the Static Site Editor.
+ flash[:alert] = service_response.message
+ redirect_to project_path(project)
end
end
diff --git a/app/helpers/clusters_helper.rb b/app/helpers/clusters_helper.rb
index caad215e996..884452fe32f 100644
--- a/app/helpers/clusters_helper.rb
+++ b/app/helpers/clusters_helper.rb
@@ -42,14 +42,6 @@ module ClustersHelper
}
end
- # This method is depreciated and will be removed when associated HAML files are moved to JavaScript
- def provider_icon(provider = nil)
- img_data = js_clusters_list_data.dig(:img_tags, provider&.to_sym) ||
- js_clusters_list_data.dig(:img_tags, :default)
-
- image_tag img_data[:path], alt: img_data[:text], class: 'gl-h-full'
- end
-
def render_gcp_signup_offer
return if Gitlab::CurrentSettings.current_application_settings.hide_third_party_offers?
return unless show_gcp_signup_offer?
diff --git a/app/services/static_site_editor/config_service.rb b/app/services/static_site_editor/config_service.rb
index 987ee071976..3be56790f7b 100644
--- a/app/services/static_site_editor/config_service.rb
+++ b/app/services/static_site_editor/config_service.rb
@@ -4,18 +4,38 @@ module StaticSiteEditor
class ConfigService < ::BaseContainerService
ValidationError = Class.new(StandardError)
- def execute
+ def initialize(container:, current_user: nil, params: {})
+ super
+
@project = container
+ @repository = project.repository
+ @ref = params.fetch(:ref)
+ end
+
+ def execute
check_access!
+ file_config = load_file_config!
+ file_data = file_config.to_hash_with_defaults
+ generated_data = load_generated_config.data
+
+ check_for_duplicate_keys!(generated_data, file_data)
+ data = merged_data(generated_data, file_data)
+
ServiceResponse.success(payload: data)
rescue ValidationError => e
ServiceResponse.error(message: e.message)
+ rescue => e
+ Gitlab::ErrorTracking.track_and_raise_exception(e)
end
private
- attr_reader :project
+ attr_reader :project, :repository, :ref
+
+ def static_site_editor_config_file
+ '.gitlab/static-site-editor.yml'
+ end
def check_access!
unless can?(current_user, :download_code, project)
@@ -23,27 +43,43 @@ module StaticSiteEditor
end
end
- def data
- check_for_duplicate_keys!
- generated_data.merge(file_data)
+ def load_file_config!
+ yaml = yaml_from_repo.presence || '{}'
+ file_config = Gitlab::StaticSiteEditor::Config::FileConfig.new(yaml)
+
+ unless file_config.valid?
+ raise ValidationError, file_config.errors.first
+ end
+
+ file_config
+ rescue Gitlab::StaticSiteEditor::Config::FileConfig::ConfigError => e
+ raise ValidationError, e.message
end
- def generated_data
- @generated_data ||= Gitlab::StaticSiteEditor::Config::GeneratedConfig.new(
+ def load_generated_config
+ Gitlab::StaticSiteEditor::Config::GeneratedConfig.new(
project.repository,
- params.fetch(:ref),
+ ref,
params.fetch(:path),
params[:return_url]
- ).data
- end
-
- def file_data
- @file_data ||= Gitlab::StaticSiteEditor::Config::FileConfig.new.data
+ )
end
- def check_for_duplicate_keys!
+ def check_for_duplicate_keys!(generated_data, file_data)
duplicate_keys = generated_data.keys & file_data.keys
raise ValidationError.new("Duplicate key(s) '#{duplicate_keys}' found.") if duplicate_keys.present?
end
+
+ def merged_data(generated_data, file_data)
+ generated_data.merge(file_data)
+ end
+
+ def yaml_from_repo
+ project.repository.blob_data_at(ref, static_site_editor_config_file)
+ rescue GRPC::NotFound
+ # Return nil in the case of a GRPC::NotFound exception, so the default config will be used.
+ # Allow any other unexpected exception will be tracked and re-raised.
+ nil
+ end
end
end
diff --git a/app/views/clusters/clusters/_buttons.html.haml b/app/views/clusters/clusters/_buttons.html.haml
deleted file mode 100644
index c81d1d5b05a..00000000000
--- a/app/views/clusters/clusters/_buttons.html.haml
+++ /dev/null
@@ -1,6 +0,0 @@
-.nav-controls
- - if clusterable.can_add_cluster?
- = link_to s_('ClusterIntegration|Add Kubernetes cluster'), clusterable.new_path, class: 'btn btn-success js-add-cluster'
- - else
- %span.btn.btn-add-cluster.disabled.js-add-cluster
- = s_("ClusterIntegration|Add Kubernetes cluster")
diff --git a/app/views/clusters/clusters/_cluster.html.haml b/app/views/clusters/clusters/_cluster.html.haml
deleted file mode 100644
index f11117ea5c4..00000000000
--- a/app/views/clusters/clusters/_cluster.html.haml
+++ /dev/null
@@ -1,19 +0,0 @@
-.card
- .card-body.gl-responsive-table-row
- .table-section.section-60
- .table-mobile-header{ role: "rowheader" }= s_("ClusterIntegration|Kubernetes cluster")
- .table-mobile-content.gl-display-flex.gl-align-items-center.gl-justify-content-end.gl-justify-content-md-start
- .gl-w-6.gl-h-6.gl-mr-3.gl-display-flex.gl-align-items-center= provider_icon(cluster.provider_type)
- = cluster.item_link(clusterable, html_options: { data: { qa_selector: 'cluster', qa_cluster_name: cluster.name } })
- - if cluster.status_name == :creating
- .spinner.ml-2.align-middle.has-tooltip{ title: s_("ClusterIntegration|Cluster being created") }
- - unless cluster.enabled?
- %span.badge.badge-danger Connection disabled
- .table-section.section-25
- .table-mobile-header{ role: "rowheader" }= s_("ClusterIntegration|Environment scope")
- .table-mobile-content= cluster.environment_scope
- .table-section.section-15.text-right
- .table-mobile-header{ role: "rowheader" }
- .table-mobile-content
- %span.badge.badge-light
- = cluster.cluster_type_description
diff --git a/app/views/clusters/clusters/index.html.haml b/app/views/clusters/clusters/index.html.haml
index 01e94e124f9..803b3d1c156 100644
--- a/app/views/clusters/clusters/index.html.haml
+++ b/app/views/clusters/clusters/index.html.haml
@@ -10,23 +10,11 @@
.top-area.adjust
.nav-text
= s_('ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project')
- = render 'clusters/clusters/buttons'
+ .nav-controls
+ - if clusterable.can_add_cluster?
+ = link_to s_('ClusterIntegration|Add Kubernetes cluster'), clusterable.new_path, class: 'btn gl-button btn-success js-add-cluster'
+ - else
+ %span.btn.gl-button.btn-success.js-add-cluster.disabled
+ = s_("ClusterIntegration|Add Kubernetes cluster")
- - if Feature.enabled?(:clusters_list_redesign, default_enabled: true)
- #js-clusters-list-app{ data: js_clusters_list_data(clusterable.index_path(format: :json)) }
- - else
- - if @has_ancestor_clusters
- .bs-callout.bs-callout-info
- = s_('ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters.')
- %strong
- = link_to _('More information'), help_page_path('user/group/clusters/index', anchor: 'cluster-precedence')
- .clusters-table.js-clusters-list{ data: { testid: 'cluster_list_table' } }
- .gl-responsive-table-row.table-row-header{ role: "row" }
- .table-section.section-60{ role: "rowheader" }
- = s_("ClusterIntegration|Kubernetes cluster")
- .table-section.section-30{ role: "rowheader" }
- = s_("ClusterIntegration|Environment scope")
- .table-section.section-10{ role: "rowheader" }
- - @clusters.each do |cluster|
- = render "cluster", cluster: cluster.present(current_user: current_user)
- = paginate @clusters, theme: "gitlab"
+ #js-clusters-list-app{ data: js_clusters_list_data(clusterable.index_path(format: :json)) }
diff --git a/app/views/projects/cycle_analytics/show.html.haml b/app/views/projects/cycle_analytics/show.html.haml
index d7e10efc3b1..ca689b0bad7 100644
--- a/app/views/projects/cycle_analytics/show.html.haml
+++ b/app/views/projects/cycle_analytics/show.html.haml
@@ -1,4 +1,6 @@
- page_title _("Value Stream Analytics")
+- content_for :page_specific_javascripts do
+ = stylesheet_link_tag 'page_bundles/cycle_analytics'
#cycle-analytics{ "v-cloak" => "true", data: { request_path: project_cycle_analytics_path(@project) } }
- if @cycle_analytics_no_data
diff --git a/app/views/projects/pipeline_schedules/index.html.haml b/app/views/projects/pipeline_schedules/index.html.haml
index 0bcf8ae605a..91083cc0768 100644
--- a/app/views/projects/pipeline_schedules/index.html.haml
+++ b/app/views/projects/pipeline_schedules/index.html.haml
@@ -2,7 +2,7 @@
- page_title _("Pipeline Schedules")
-#pipeline-schedules-callout{ data: { docs_url: help_page_path('ci/pipelines/schedules'), image_url: image_path('pages/projects/pipeline_schedules/shared/icons/intro_illustration.svg') } }
+#pipeline-schedules-callout{ data: { docs_url: help_page_path('ci/pipelines/schedules'), image_url: image_path('illustrations/pipeline_schedule_callout.svg') } }
.top-area
- schedule_path_proc = ->(scope) { pipeline_schedules_path(@project, scope: scope) }
= render "tabs", schedule_path_proc: schedule_path_proc, all_schedules: @all_schedules, scope: @scope
diff --git a/app/views/shared/labels/_form.html.haml b/app/views/shared/labels/_form.html.haml
index 78ff225daad..2df6c3a6afd 100644
--- a/app/views/shared/labels/_form.html.haml
+++ b/app/views/shared/labels/_form.html.haml
@@ -28,7 +28,7 @@
= render_suggested_colors
.form-actions
- if @label.persisted?
- = f.submit 'Save changes', class: 'btn btn-success js-save-button'
+ = f.submit 'Save changes', class: 'btn gl-button btn-success js-save-button'
- else
- = f.submit 'Create label', class: 'btn btn-success js-save-button qa-label-create-button'
- = link_to 'Cancel', back_path, class: 'btn btn-cancel'
+ = f.submit 'Create label', class: 'btn gl-button btn-success js-save-button qa-label-create-button'
+ = link_to 'Cancel', back_path, class: 'btn gl-button btn-cancel'
diff --git a/app/views/shared/labels/_nav.html.haml b/app/views/shared/labels/_nav.html.haml
index d613ea466fa..cc43174dc19 100644
--- a/app/views/shared/labels/_nav.html.haml
+++ b/app/views/shared/labels/_nav.html.haml
@@ -15,10 +15,10 @@
.input-group
= search_field_tag :search, params[:search], { placeholder: _('Filter'), id: 'label-search', class: 'form-control search-text-input input-short', spellcheck: false, autofocus: true }
%span.input-group-append
- %button.btn.btn-default{ type: "submit", "aria-label" => _('Submit search') }
+ %button.btn.gl-button.btn-default{ type: "submit", "aria-label" => _('Submit search') }
= icon("search")
= render 'shared/labels/sort_dropdown'
- if labels_or_filters && can_admin_label && @project
- = link_to _('New label'), new_project_label_path(@project), class: "btn btn-success qa-label-create-new"
+ = link_to _('New label'), new_project_label_path(@project), class: "btn gl-button btn-success qa-label-create-new"
- if labels_or_filters && can_admin_label && @group
- = link_to _('New label'), new_group_label_path(@group), class: "btn btn-success qa-label-create-new"
+ = link_to _('New label'), new_group_label_path(@group), class: "btn gl-button btn-success qa-label-create-new"
diff --git a/changelogs/unreleased/231209-labels-buttons.yml b/changelogs/unreleased/231209-labels-buttons.yml
new file mode 100644
index 00000000000..51de12ff2e8
--- /dev/null
+++ b/changelogs/unreleased/231209-labels-buttons.yml
@@ -0,0 +1,5 @@
+---
+title: Apply GitLab UI styles to buttons in app/views/shared/labels directory
+merge_request: 43346
+author: Gary Bell @garybell
+type: other
diff --git a/changelogs/unreleased/add-sse-config-file-3.yml b/changelogs/unreleased/add-sse-config-file-3.yml
new file mode 100644
index 00000000000..b942b1224f2
--- /dev/null
+++ b/changelogs/unreleased/add-sse-config-file-3.yml
@@ -0,0 +1,6 @@
+---
+title: Introduce '.gitlab/static-site-editor.yml' config file, with support for 'static_site_generator'
+ entry.
+merge_request: 41957
+author:
+type: added
diff --git a/config/application.rb b/config/application.rb
index 2293ab4cb68..4971d2853b9 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -185,6 +185,7 @@ module Gitlab
config.assets.precompile << "mailers/*.css"
config.assets.precompile << "page_bundles/_mixins_and_variables_and_functions.css"
config.assets.precompile << "page_bundles/boards.css"
+ config.assets.precompile << "page_bundles/cycle_analytics.css"
config.assets.precompile << "page_bundles/ide.css"
config.assets.precompile << "page_bundles/issues.css"
config.assets.precompile << "page_bundles/jira_connect.css"
@@ -219,13 +220,6 @@ module Gitlab
config.assets.paths << "#{config.root}/node_modules/xterm/src/"
config.assets.precompile << "xterm.css"
- # Add EE assets
- if Gitlab.ee?
- %w[images javascripts stylesheets].each do |path|
- config.assets.paths << "#{config.root}/ee/app/assets/#{path}"
- end
- end
-
# Import path for EE specific SCSS entry point
# In CE it will import a noop file, in EE a functioning file
# Order is important, so that the ee file takes precedence:
@@ -345,6 +339,20 @@ module Gitlab
end
end
+ # Add EE assets. They should take precedence over CE. This means if two files exist, e.g.:
+ #
+ # ee/app/assets/stylesheets/example.scss
+ # app/assets/stylesheets/example.scss
+ #
+ # The ee/ version will be preferred.
+ initializer :prefer_ee_assets, after: :append_assets_path do |app|
+ if Gitlab.ee?
+ %w[images javascripts stylesheets].each do |path|
+ app.config.assets.paths.unshift("#{config.root}/ee/app/assets/#{path}")
+ end
+ end
+ end
+
config.after_initialize do
# Devise (see initializers/8_devise.rb) already reloads routes if
# eager loading is enabled, so don't do this twice since it's
diff --git a/config/feature_flags/development/allow_unsafe_ruby_regexp.yml b/config/feature_flags/development/allow_unsafe_ruby_regexp.yml
index 4d3b13deda2..272e9f5ffa2 100644
--- a/config/feature_flags/development/allow_unsafe_ruby_regexp.yml
+++ b/config/feature_flags/development/allow_unsafe_ruby_regexp.yml
@@ -1,7 +1,7 @@
---
name: allow_unsafe_ruby_regexp
introduced_by_url:
-rollout_issue_url:
-group:
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/257849
type: development
+group: group::continuous integration
default_enabled: false
diff --git a/config/feature_flags/development/ci_disable_validates_dependencies.yml b/config/feature_flags/development/ci_disable_validates_dependencies.yml
index 65358a04340..ccd529d0a09 100644
--- a/config/feature_flags/development/ci_disable_validates_dependencies.yml
+++ b/config/feature_flags/development/ci_disable_validates_dependencies.yml
@@ -1,7 +1,7 @@
---
name: ci_disable_validates_dependencies
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/14009
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/257847
+group: group::continuous integration
type: development
default_enabled: false
diff --git a/config/feature_flags/development/clusters_list_redesign.yml b/config/feature_flags/development/clusters_list_redesign.yml
deleted file mode 100644
index 22c1f0aa96d..00000000000
--- a/config/feature_flags/development/clusters_list_redesign.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: clusters_list_redesign
-introduced_by_url:
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/220182
-group: Configure
-type: development
-default_enabled: true
diff --git a/doc/integration/elasticsearch.md b/doc/integration/elasticsearch.md
index 0c511e3703a..6681295f8cd 100644
--- a/doc/integration/elasticsearch.md
+++ b/doc/integration/elasticsearch.md
@@ -159,7 +159,7 @@ After installation, be sure to [enable Elasticsearch](#enabling-elasticsearch).
NOTE: **Note:**
If you see an error such as `Permission denied - /home/git/gitlab-elasticsearch-indexer/` while indexing, you
-may need to set the `production -> elasticsearch -> indexer_path` setting in your `gitlab.yml` file to
+may need to set the `production -> elasticsearch -> indexer_path` setting in your `gitlab.yml` file to
`/usr/local/bin/gitlab-elasticsearch-indexer`, which is where the binary is installed.
## Enabling Elasticsearch
@@ -703,104 +703,114 @@ However, some larger installations may wish to tune the merge policy settings:
## Troubleshooting
-### Common issues
+Here are some common pitfalls and how to overcome them.
-Here are some common pitfalls and how to overcome them:
+### How can I verify that my GitLab instance is using Elasticsearch?
-- **How can I verify my GitLab instance is using Elasticsearch?**
+There are a couple of ways to achieve that:
- The easiest method is via the rails console (`sudo gitlab-rails console`) by running the following:
+- Whenever you perform a search there will be a link on the search results page
+ in the top right hand corner saying "Advanced search functionality is enabled".
+ This is always correctly identifying whether the current project/namespace
+ being searched is using Elasticsearch.
- ```ruby
- u = User.find_by_username('your-username')
- s = SearchService.new(u, {:search => 'search_term'})
- pp s.search_objects.class.name
- ```
+- From the admin area under **Settings > General > Elasticsearch** check that the
+ Advanced Search settings are checked.
- If you see `"ActiveRecord::Relation"`, you are **not** using Elasticsearch.
-
- If you see `"Kaminari::PaginatableArray"` you are using Elasticsearch.
+ Those same settings there can be obtained from the Rails console if necessary:
- NOTE: **Note:**
- The above instructions are used to verify that GitLab is using Elasticsearch only when indexing all namespaces. This is not to be used for scenarios that only index a [subset of namespaces](#limiting-namespaces-and-projects).
+ ```ruby
+ ::Gitlab::CurrentSettings.elasticsearch_search? # Whether or not searches will use Elasticsearch
+ ::Gitlab::CurrentSettings.elasticsearch_indexing? # Whether or not content will be indexed in Elasticsearch
+ ::Gitlab::CurrentSettings.elasticsearch_limit_indexing? # Whether or not Elasticsearch is limited only to certain projects/namespaces
+ ```
-- **I updated GitLab and now I can't find anything**
+- If Elasticsearch is limited to specific namespaces and you need to know if
+ Elasticsearch is being used for a specific project or namespace, you can use
+ the Rails console:
- We continuously make updates to our indexing strategies and aim to support
- newer versions of Elasticsearch. When indexing changes are made, it may
- be necessary for you to [reindex](#zero-downtime-reindexing) after updating GitLab.
+ ```ruby
+ ::Gitlab::CurrentSettings.search_using_elasticsearch?(scope: Namespace.find_by_full_path("/my-namespace"))
+ ::Gitlab::CurrentSettings.search_using_elasticsearch?(scope: Project.find_by_full_path("/my-namespace/my-project"))
+ ```
-- **I indexed all the repositories but I can't get any hits for my search term in the UI**
+### I updated GitLab and now I can't find anything
- Make sure you indexed all the database data [as stated above](#enabling-elasticsearch).
+We continuously make updates to our indexing strategies and aim to support
+newer versions of Elasticsearch. When indexing changes are made, it may
+be necessary for you to [reindex](#zero-downtime-reindexing) after updating GitLab.
- If there aren't any results (hits) in the UI search, check if you are seeing the same results via the rails console (`sudo gitlab-rails console`):
+### I indexed all the repositories but I can't get any hits for my search term in the UI
- ```ruby
- u = User.find_by_username('your-username')
- s = SearchService.new(u, {:search => 'search_term', :scope => 'blobs'})
- pp s.search_objects.to_a
- ```
+Make sure you indexed all the database data [as stated above](#enabling-elasticsearch).
- Beyond that, check via the [Elasticsearch Search API](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html) to see if the data shows up on the Elasticsearch side:
+If there aren't any results (hits) in the UI search, check if you are seeing the same results via the rails console (`sudo gitlab-rails console`):
- ```shell
- curl --request GET <elasticsearch_server_ip>:9200/gitlab-production/_search?q=<search_term>
- ```
+```ruby
+u = User.find_by_username('your-username')
+s = SearchService.new(u, {:search => 'search_term', :scope => 'blobs'})
+pp s.search_objects.to_a
+```
- More [complex Elasticsearch API calls](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-filter-context.html) are also possible.
+Beyond that, check via the [Elasticsearch Search API](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html) to see if the data shows up on the Elasticsearch side:
- It is important to understand at which level the problem is manifesting (UI, Rails code, Elasticsearch side) to be able to [troubleshoot further](../administration/troubleshooting/elasticsearch.md#search-results-workflow).
+```shell
+curl --request GET <elasticsearch_server_ip>:9200/gitlab-production/_search?q=<search_term>
+```
- NOTE: **Note:**
- The above instructions are not to be used for scenarios that only index a [subset of namespaces](#limiting-namespaces-and-projects).
+More [complex Elasticsearch API calls](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-filter-context.html) are also possible.
- See [Elasticsearch Index Scopes](#elasticsearch-index-scopes) for more information on searching for specific types of data.
+It is important to understand at which level the problem is manifesting (UI, Rails code, Elasticsearch side) to be able to [troubleshoot further](../administration/troubleshooting/elasticsearch.md#search-results-workflow).
-- **I indexed all the repositories but then switched Elasticsearch servers and now I can't find anything**
+NOTE: **Note:**
+The above instructions are not to be used for scenarios that only index a [subset of namespaces](#limiting-namespaces-and-projects).
- You will need to re-run all the Rake tasks to reindex the database, repositories, and wikis.
+See [Elasticsearch Index Scopes](#elasticsearch-index-scopes) for more information on searching for specific types of data.
-- **The indexing process is taking a very long time**
+### I indexed all the repositories but then switched Elasticsearch servers and now I can't find anything
- The more data present in your GitLab instance, the longer the indexing process takes.
+You will need to re-run all the Rake tasks to reindex the database, repositories, and wikis.
-- **There are some projects that weren't indexed, but we don't know which ones**
+### The indexing process is taking a very long time
- You can run `sudo gitlab-rake gitlab:elastic:projects_not_indexed` to display projects that aren't indexed.
+The more data present in your GitLab instance, the longer the indexing process takes.
-- **No new data is added to the Elasticsearch index when I push code**
+### There are some projects that weren't indexed, but I don't know which ones
- NOTE: **Note:**
- This was [fixed in GitLab 13.2](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35936) and the Rake task is not available for versions greater than that.
+You can run `sudo gitlab-rake gitlab:elastic:projects_not_indexed` to display projects that aren't indexed.
- When performing the initial indexing of blobs, we lock all projects until the project finishes indexing. It could happen that an error during the process causes one or multiple projects to remain locked. In order to unlock them, run:
+### No new data is added to the Elasticsearch index when I push code
- ```shell
- sudo gitlab-rake gitlab:elastic:clear_locked_projects
- ```
+NOTE: **Note:**
+This was [fixed in GitLab 13.2](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35936) and the Rake task is not available for versions greater than that.
-- **"Can't specify parent if no parent field has been configured"**
+When performing the initial indexing of blobs, we lock all projects until the project finishes indexing. It could happen that an error during the process causes one or multiple projects to remain locked. In order to unlock them, run:
- If you enabled Elasticsearch before GitLab 8.12 and have not rebuilt indexes you will get
- exception in lots of different cases:
+```shell
+sudo gitlab-rake gitlab:elastic:clear_locked_projects
+```
- ```plaintext
- Elasticsearch::Transport::Transport::Errors::BadRequest([400] {
- "error": {
- "root_cause": [{
- "type": "illegal_argument_exception",
- "reason": "Can't specify parent if no parent field has been configured"
- }],
- "type": "illegal_argument_exception",
- "reason": "Can't specify parent if no parent field has been configured"
- },
- "status": 400
- }):
- ```
+### `Can't specify parent if no parent field has been configured` error
+
+If you enabled Elasticsearch before GitLab 8.12 and have not rebuilt indexes you will get
+exception in lots of different cases:
+
+```plaintext
+Elasticsearch::Transport::Transport::Errors::BadRequest([400] {
+ "error": {
+ "root_cause": [{
+ "type": "illegal_argument_exception",
+ "reason": "Can't specify parent if no parent field has been configured"
+ }],
+ "type": "illegal_argument_exception",
+ "reason": "Can't specify parent if no parent field has been configured"
+ },
+ "status": 400
+}):
+```
- This is because we changed the index mapping in GitLab 8.12 and the old indexes should be removed and built from scratch again,
- see details in the [update guide](../update/upgrading_from_source.md).
+This is because we changed the index mapping in GitLab 8.12 and the old indexes should be removed and built from scratch again,
+see details in the [update guide](../update/upgrading_from_source.md).
- Exception `Elasticsearch::Transport::Transport::Errors::BadRequest`
@@ -822,44 +832,45 @@ Here are some common pitfalls and how to overcome them:
for this setting ("Maximum Size of HTTP Request Payloads"), based on the size of
the underlying instance.
-- **My single node Elasticsearch cluster status never goes from `yellow` to `green` even though everything seems to be running properly**
+### My single node Elasticsearch cluster status never goes from `yellow` to `green` even though everything seems to be running properly
- **For a single node Elasticsearch cluster the functional cluster health status will be yellow** (will never be green) because the primary shard is allocated but replicas can not be as there is no other node to which Elasticsearch can assign a replica. This also applies if you are using the
-[Amazon Elasticsearch](https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/aes-handling-errors.html#aes-handling-errors-yellow-cluster-status) service.
+**For a single node Elasticsearch cluster the functional cluster health status will be yellow** (never green) because the primary shard is allocated but replicas cannot be as there is no other node to which Elasticsearch can assign a replica. This also applies if you are using the [Amazon Elasticsearch](https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/aes-handling-errors.html#aes-handling-errors-yellow-cluster-status) service.
- CAUTION: **Warning:**
- Setting the number of replicas to `0` is not something that we recommend (this is not allowed in the GitLab Elasticsearch Integration menu). If you are planning to add more Elasticsearch nodes (for a total of more than 1 Elasticsearch) the number of replicas will need to be set to an integer value larger than `0`. Failure to do so will result in lack of redundancy (losing one node will corrupt the index).
+CAUTION: **Warning:**
+Setting the number of replicas to `0` is discouraged (this is not allowed in the GitLab Elasticsearch Integration menu). If you are planning to add more Elasticsearch nodes (for a total of more than 1 Elasticsearch) the number of replicas will need to be set to an integer value larger than `0`. Failure to do so will result in lack of redundancy (losing one node will corrupt the index).
- If you have a **hard requirement to have a green status for your single node Elasticsearch cluster**, please make sure you understand the risks outlined in the previous paragraph and then simply run the following query to set the number of replicas to `0`(the cluster will no longer try to create any shard replicas):
+If you have a **hard requirement to have a green status for your single node Elasticsearch cluster**, please make sure you understand the risks outlined in the previous paragraph and then run the following query to set the number of replicas to `0`(the cluster will no longer try to create any shard replicas):
- ```shell
- curl --request PUT localhost:9200/gitlab-production/_settings --header 'Content-Type: application/json' --data '{
- "index" : {
- "number_of_replicas" : 0
- }
- }'
- ```
+```shell
+curl --request PUT localhost:9200/gitlab-production/_settings --header 'Content-Type: application/json' --data '{
+"index" : {
+ "number_of_replicas" : 0
+ }
+}'
+```
-- **I'm getting a `health check timeout: no Elasticsearch node available` error in Sidekiq during the indexing process**
+### `health check timeout: no Elasticsearch node available` error in Sidekiq
- ```plaintext
- Gitlab::Elastic::Indexer::Error: time="2020-01-23T09:13:00Z" level=fatal msg="health check timeout: no Elasticsearch node available"
- ```
+If you're getting a `health check timeout: no Elasticsearch node available` error in Sidekiq during the indexing process:
+
+```plaintext
+Gitlab::Elastic::Indexer::Error: time="2020-01-23T09:13:00Z" level=fatal msg="health check timeout: no Elasticsearch node available"
+```
- You probably have not used either `http://` or `https://` as part of your value in the **"URL"** field of the Elasticsearch Integration Menu. Please make sure you are using either `http://` or `https://` in this field as the [Elasticsearch client for Go](https://github.com/olivere/elastic) that we are using [needs the prefix for the URL to be accepted as valid](https://github.com/olivere/elastic/commit/a80af35aa41856dc2c986204e2b64eab81ccac3a).
- Once you have corrected the formatting of the URL, delete the index (via the [dedicated Rake task](#gitlab-elasticsearch-rake-tasks)) and [reindex the content of your instance](#enabling-elasticsearch).
+You probably have not used either `http://` or `https://` as part of your value in the **"URL"** field of the Elasticsearch Integration Menu. Please make sure you are using either `http://` or `https://` in this field as the [Elasticsearch client for Go](https://github.com/olivere/elastic) that we are using [needs the prefix for the URL to be accepted as valid](https://github.com/olivere/elastic/commit/a80af35aa41856dc2c986204e2b64eab81ccac3a).
+Once you have corrected the formatting of the URL, delete the index (via the [dedicated Rake task](#gitlab-elasticsearch-rake-tasks)) and [reindex the content of your instance](#enabling-elasticsearch).
### Low-level troubleshooting
There is a [more structured, lower-level troubleshooting document](../administration/troubleshooting/elasticsearch.md) for when you experience other issues, including poor performance.
-### Known Issues
+### Known issues
-- **[Elasticsearch `code_analyzer` doesn't account for all code cases](https://gitlab.com/groups/gitlab-org/-/epics/3621)**
+[Elasticsearch `code_analyzer` doesn't account for all code cases](https://gitlab.com/groups/gitlab-org/-/epics/3621).
- The `code_analyzer` pattern and filter configuration is being evaluated for improvement. We have fixed [most edge cases](https://gitlab.com/groups/gitlab-org/-/epics/3621#note_363429094) that were not returning expected search results due to our pattern and filter configuration.
+The `code_analyzer` pattern and filter configuration is being evaluated for improvement. We have fixed [most edge cases](https://gitlab.com/groups/gitlab-org/-/epics/3621#note_363429094) that were not returning expected search results due to our pattern and filter configuration.
- Improvements to the `code_analyzer` pattern and filters is being discussed in [epic 3621](https://gitlab.com/groups/gitlab-org/-/epics/3621).
+Improvements to the `code_analyzer` pattern and filters are being discussed in [epic 3621](https://gitlab.com/groups/gitlab-org/-/epics/3621).
### Reverting to Basic Search
diff --git a/doc/user/application_security/dependency_scanning/index.md b/doc/user/application_security/dependency_scanning/index.md
index 1051849185a..88a498641f6 100644
--- a/doc/user/application_security/dependency_scanning/index.md
+++ b/doc/user/application_security/dependency_scanning/index.md
@@ -9,25 +9,26 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/5105) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 10.7.
-Dependency Scanning helps to find security vulnerabilities in your dependencies automatically
-while you're developing and testing your applications, such as when your
-application is using an external (open source) library that is known to be vulnerable.
+GitLab's Dependency Scanning feature can automatically find security vulnerabilities in your
+dependencies while you're developing and testing your applications. For example, dependency scanning
+lets you know if your application uses an external (open source) library that is known to be
+vulnerable. You can then take action to protect your application.
## Overview
-If you're using [GitLab CI/CD](../../../ci/README.md), you can analyze your dependencies for known
-vulnerabilities using Dependency Scanning.
-All dependencies are scanned, including the transitive dependencies (also known as nested dependencies).
-You can take advantage of Dependency Scanning by either [including the Dependency Scanning template](#configuration)
-in your existing `.gitlab-ci.yml` file or by implicitly using
-the [Auto Dependency Scanning](../../../topics/autodevops/stages.md#auto-dependency-scanning)
+If you're using [GitLab CI/CD](../../../ci/README.md), you can use dependency scanning to analyze
+your dependencies for known vulnerabilities. GitLab scans all dependencies, including transitive
+dependencies (also known as nested dependencies). You can take advantage of dependency scanning by
+either [including the dependency scanning template](#configuration)
+in your existing `.gitlab-ci.yml` file, or by implicitly using
+the [auto dependency scanning](../../../topics/autodevops/stages.md#auto-dependency-scanning)
provided by [Auto DevOps](../../../topics/autodevops/index.md).
-GitLab checks the Dependency Scanning report, compares the found vulnerabilities
+GitLab checks the dependency scanning report, compares the found vulnerabilities
between the source and target branches, and shows the information on the
merge request.
-![Dependency Scanning Widget](img/dependency_scanning_v13_2.png)
+![Dependency scanning Widget](img/dependency_scanning_v13_2.png)
The results are sorted by the severity of the vulnerability:
@@ -40,7 +41,7 @@ The results are sorted by the severity of the vulnerability:
## Requirements
-To run Dependency Scanning jobs, by default, you need GitLab Runner with the
+To run dependency scanning jobs, by default, you need GitLab Runner with the
[`docker`](https://docs.gitlab.com/runner/executors/docker.html) or
[`kubernetes`](https://docs.gitlab.com/runner/install/kubernetes.html) executor.
If you're using the shared runners on GitLab.com, this is enabled by default.
@@ -81,7 +82,7 @@ The [Security Scanner Integration](../../../development/integrations/secure.md)
## Configuration
-To enable Dependency Scanning for GitLab 11.9 and later, you must
+To enable dependency scanning for GitLab 11.9 and later, you must
[include](../../../ci/yaml/README.md#includetemplate) the
[`Dependency-Scanning.gitlab-ci.yml` template](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml)
that is provided as a part of your GitLab installation.
@@ -95,16 +96,16 @@ include:
- template: Dependency-Scanning.gitlab-ci.yml
```
-The included template creates Dependency Scanning jobs in your CI/CD
+The included template creates dependency scanning jobs in your CI/CD
pipeline and scans your project's source code for possible vulnerabilities.
The results are saved as a
-[Dependency Scanning report artifact](../../../ci/pipelines/job_artifacts.md#artifactsreportsdependency_scanning)
+[dependency scanning report artifact](../../../ci/pipelines/job_artifacts.md#artifactsreportsdependency_scanning)
that you can later download and analyze. Due to implementation limitations, we
-always take the latest Dependency Scanning artifact available.
+always take the latest dependency scanning artifact available.
-### Customizing the Dependency Scanning settings
+### Customizing the dependency scanning settings
-The Dependency Scanning settings can be changed through [environment variables](#available-variables) by using the
+The dependency scanning settings can be changed through [environment variables](#available-variables) by using the
[`variables`](../../../ci/yaml/README.md#variables) parameter in `.gitlab-ci.yml`.
For example:
@@ -119,7 +120,7 @@ variables:
Because template is [evaluated before](../../../ci/yaml/README.md#include) the pipeline
configuration, the last mention of the variable takes precedence.
-### Overriding Dependency Scanning jobs
+### Overriding dependency scanning jobs
CAUTION: **Deprecation:**
Beginning in GitLab 13.0, the use of [`only` and `except`](../../../ci/yaml/README.md#onlyexcept-basic)
@@ -141,10 +142,10 @@ gemnasium-dependency_scanning:
### Available variables
-Dependency Scanning can be [configured](#customizing-the-dependency-scanning-settings)
+Dependency scanning can be [configured](#customizing-the-dependency-scanning-settings)
using environment variables.
-#### Configuring Dependency Scanning
+#### Configuring dependency scanning
The following variables allow configuration of global dependency scanning settings.
@@ -156,7 +157,7 @@ The following variables allow configuration of global dependency scanning settin
| `DS_EXCLUDED_PATHS` | Exclude vulnerabilities from output based on the paths. A comma-separated list of patterns. Patterns can be globs, or file or folder paths (for example, `doc,spec`). Parent directories also match patterns. Default: `"spec, test, tests, tmp"` |
| `SECURE_LOG_LEVEL` | Set the minimum logging level. Messages of this logging level or higher are output. From highest to lowest severity, the logging levels are: `fatal`, `error`, `warn`, `info`, `debug`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/10880) in GitLab 13.1. Default: `info` |
-#### Configuring specific analyzers used by Dependency Scanning
+#### Configuring specific analyzers used by dependency scanning
The following variables are used for configuring specific analyzers (used for a specific language/framework).
@@ -176,7 +177,7 @@ The following variables are used for configuring specific analyzers (used for a
| `MAVEN_CLI_OPTS` | `gemnasium-maven` | `"-DskipTests --batch-mode"` | List of command line arguments that are passed to `maven` by the analyzer. See an example for [using private repositories](../index.md#using-private-maven-repos). |
| `GRADLE_CLI_OPTS` | `gemnasium-maven` | | List of command line arguments that are passed to `gradle` by the analyzer. |
| `SBT_CLI_OPTS` | `gemnasium-maven` | | List of command-line arguments that the analyzer passes to `sbt`. |
-| `BUNDLER_AUDIT_UPDATE_DISABLED` | `bundler-audit` | `"false"` | Disable automatic updates for the `bundler-audit` analyzer. Useful if you're running Dependency Scanning in an offline, air-gapped environment.|
+| `BUNDLER_AUDIT_UPDATE_DISABLED` | `bundler-audit` | `"false"` | Disable automatic updates for the `bundler-audit` analyzer. Useful if you're running dependency scanning in an offline, air-gapped environment.|
| `BUNDLER_AUDIT_ADVISORY_DB_URL` | `bundler-audit` | `https://github.com/rubysec/ruby-advisory-db` | URL of the advisory database used by bundler-audit. |
| `BUNDLER_AUDIT_ADVISORY_DB_REF_NAME` | `bundler-audit` | `master` | Git ref for the advisory database specified by `BUNDLER_AUDIT_ADVISORY_DB_URL`. |
| `RETIREJS_JS_ADVISORY_DB` | `retire.js` | `https://raw.githubusercontent.com/RetireJS/retire.js/master/repository/jsrepository.json` | Path or URL to `retire.js` JS vulnerability data file. Note that if the URL hosting the data file uses a custom SSL certificate, for example in an offline installation, you can pass the certificate in the `ADDITIONAL_CA_CERT_BUNDLE` environment variable. |
@@ -214,16 +215,16 @@ For more information about the vulnerabilities database update, check the
## Dependency List
-An additional benefit of Dependency Scanning is the ability to view your
+An additional benefit of dependency scanning is the ability to view your
project's dependencies and their known vulnerabilities. Read more about
the [Dependency List](../dependency_list/index.md).
## Reports JSON format
-The Dependency Scanning tool emits a JSON report file. For more information, see the
+The dependency scanning tool emits a JSON report file. For more information, see the
[schema for this report](https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/blob/master/dist/dependency-scanning-report-format.json).
-Here's an example Dependency Scanning report:
+Here's an example dependency scanning report:
```json-doc
{
@@ -342,18 +343,18 @@ You can search the [gemnasium-db](https://gitlab.com/gitlab-org/security-product
to find a vulnerability in the Gemnasium database.
You can also [submit new vulnerabilities](https://gitlab.com/gitlab-org/security-products/gemnasium-db/blob/master/CONTRIBUTING.md).
-## Running Dependency Scanning in an offline environment
+## Running dependency scanning in an offline environment
For self-managed GitLab instances in an environment with limited, restricted, or intermittent access
-to external resources through the internet, some adjustments are required for Dependency Scanning
+to external resources through the internet, some adjustments are required for dependency scanning
jobs to run successfully. For more information, see [Offline environments](../offline_deployments/index.md).
-### Requirements for offline Dependency Scanning
+### Requirements for offline dependency scanning
-Here are the requirements for using Dependency Scanning in an offline environment:
+Here are the requirements for using dependency scanning in an offline environment:
- GitLab Runner with the [`docker` or `kubernetes` executor](#requirements).
-- Docker Container Registry with locally available copies of Dependency Scanning [analyzer](https://gitlab.com/gitlab-org/security-products/analyzers) images.
+- Docker Container Registry with locally available copies of dependency scanning [analyzer](https://gitlab.com/gitlab-org/security-products/analyzers) images.
- Host an offline Git copy of the [gemnasium-db advisory database](https://gitlab.com/gitlab-org/security-products/gemnasium-db/).
This is required because, in an offline environment, the Gemnasium analyzer can't fetch the latest
advisories from the online repository.
@@ -368,10 +369,10 @@ in an offline environment if you prefer using only locally available Docker imag
recommend keeping the pull policy setting to `always` if not in an offline environment, as this
enables the use of updated scanners in your CI/CD pipelines.
-### Make GitLab Dependency Scanning analyzer images available inside your Docker registry
+### Make GitLab dependency scanning analyzer images available inside your Docker registry
-For Dependency Scanning with all [supported languages and frameworks](#supported-languages-and-package-managers),
-import the following default Dependency Scanning analyzer images from `registry.gitlab.com` into
+For dependency scanning with all [supported languages and frameworks](#supported-languages-and-package-managers),
+import the following default dependency scanning analyzer images from `registry.gitlab.com` into
your [local Docker container registry](../../packages/container_registry/index.md):
```plaintext
@@ -392,7 +393,7 @@ For details on saving and transporting Docker images as a file, see Docker's doc
[`docker save`](https://docs.docker.com/engine/reference/commandline/save/), [`docker load`](https://docs.docker.com/engine/reference/commandline/load/),
[`docker export`](https://docs.docker.com/engine/reference/commandline/export/), and [`docker import`](https://docs.docker.com/engine/reference/commandline/import/).
-### Set Dependency Scanning CI job variables to use local Dependency Scanning analyzers
+### Set dependency scanning CI job variables to use local dependency scanning analyzers
Add the following configuration to your `.gitlab-ci.yml` file. You must change the value of
`SECURE_ANALYZERS_PREFIX` to refer to your local Docker container registry. You must also change the
@@ -479,15 +480,15 @@ As a workaround, remove the [`retire.js`](analyzers.md#selecting-specific-analyz
### `Error response from daemon: error processing tar file: docker-tar: relocation error`
-This error occurs when the Docker version that runs the Dependency Scanning job is `19.03.00`.
+This error occurs when the Docker version that runs the dependency scanning job is `19.03.00`.
Consider updating to Docker `19.03.1` or greater. Older versions are not
affected. Read more in
[this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/13830#note_211354992 "Current SAST container fails").
### Limitation when using rules:exists
-The [Dependency Scanning CI template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml)
+The [dependency scanning CI template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml)
uses the [`rules:exists`](../../../ci/yaml/README.md#rulesexists)
syntax. This directive is limited to 10000 checks and always returns `true` after reaching this
-number. Because of this, and depending on the number of files in your repository, a Dependency
-Scanning job might be triggered even if the scanner doesn't support your project.
+number. Because of this, and depending on the number of files in your repository, a dependency
+scanning job might be triggered even if the scanner doesn't support your project.
diff --git a/doc/user/clusters/agent/index.md b/doc/user/clusters/agent/index.md
index f63306db5bb..e6f78a80d45 100644
--- a/doc/user/clusters/agent/index.md
+++ b/doc/user/clusters/agent/index.md
@@ -81,7 +81,8 @@ When installing or upgrading the GitLab Helm chart, consider the following Helm
for the Agent to be properly installed and configured:
```shell
-helm upgrade --force --install gitlab . \
+helm repo update
+helm upgrade --force --install gitlab gitlab/gitlab \
--timeout 600 \
--set global.hosts.domain=<YOUR_DOMAIN> \
--set global.hosts.externalIP=<YOUR_IP> \
@@ -336,6 +337,7 @@ apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
+ namespace: gitlab-agent # Can be any namespace managed by you that the agent has access to.
spec:
selector:
matchLabels:
diff --git a/lib/gitlab/static_site_editor/config/file_config.rb b/lib/gitlab/static_site_editor/config/file_config.rb
index f647c85e1c8..315c603c1dd 100644
--- a/lib/gitlab/static_site_editor/config/file_config.rb
+++ b/lib/gitlab/static_site_editor/config/file_config.rb
@@ -3,11 +3,38 @@
module Gitlab
module StaticSiteEditor
module Config
+ #
+ # Base GitLab Static Site Editor Configuration facade
+ #
class FileConfig
- def data
- {
- static_site_generator: 'middleman'
- }
+ ConfigError = Class.new(StandardError)
+
+ def initialize(yaml)
+ content_hash = content_hash(yaml)
+ @global = Entry::Global.new(content_hash)
+ @global.compose!
+ rescue Gitlab::Config::Loader::FormatError => e
+ raise FileConfig::ConfigError, e.message
+ end
+
+ def valid?
+ @global.valid?
+ end
+
+ def errors
+ @global.errors
+ end
+
+ def to_hash_with_defaults
+ # NOTE: The current approach of simply mapping all the descendents' keys and values ('config')
+ # into a flat hash may need to be enhanced as we add more complex, non-scalar entries.
+ @global.descendants.map { |descendant| [descendant.key, descendant.config] }.to_h
+ end
+
+ private
+
+ def content_hash(yaml)
+ Gitlab::Config::Loader::Yaml.new(yaml).load!
end
end
end
diff --git a/lib/gitlab/static_site_editor/config/file_config/entry/global.rb b/lib/gitlab/static_site_editor/config/file_config/entry/global.rb
new file mode 100644
index 00000000000..5249de088c0
--- /dev/null
+++ b/lib/gitlab/static_site_editor/config/file_config/entry/global.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module StaticSiteEditor
+ module Config
+ class FileConfig
+ module Entry
+ ##
+ # This class represents a global entry - root Entry for entire
+ # GitLab StaticSiteEditor Configuration file.
+ #
+ class Global < ::Gitlab::Config::Entry::Node
+ include ::Gitlab::Config::Entry::Configurable
+ include ::Gitlab::Config::Entry::Attributable
+
+ ALLOWED_KEYS = %i[static_site_generator].freeze
+
+ attributes ALLOWED_KEYS
+
+ validations do
+ validates :config, allowed_keys: ALLOWED_KEYS
+ end
+
+ entry :static_site_generator, Entry::StaticSiteGenerator,
+ description: 'Configuration of the Static Site Editor static site generator.'
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/static_site_editor/config/file_config/entry/static_site_generator.rb b/lib/gitlab/static_site_editor/config/file_config/entry/static_site_generator.rb
new file mode 100644
index 00000000000..593c0951f93
--- /dev/null
+++ b/lib/gitlab/static_site_editor/config/file_config/entry/static_site_generator.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module StaticSiteEditor
+ module Config
+ class FileConfig
+ module Entry
+ ##
+ # Entry that represents the static site generator tool/framework.
+ #
+ class StaticSiteGenerator < ::Gitlab::Config::Entry::Node
+ include ::Gitlab::Config::Entry::Validatable
+
+ validations do
+ validates :config, type: String, inclusion: { in: %w[middleman], message: "should be 'middleman'" }
+ end
+
+ def self.default
+ 'middleman'
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index b9626a49341..08675783ead 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -5472,9 +5472,6 @@ msgstr ""
msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
msgstr ""
-msgid "ClusterIntegration|Cluster being created"
-msgstr ""
-
msgid "ClusterIntegration|Cluster management project (alpha)"
msgstr ""
@@ -5484,9 +5481,6 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
-msgstr ""
-
msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters. %{linkStart}More information%{linkEnd}"
msgstr ""
@@ -5751,9 +5745,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
diff --git a/spec/controllers/projects/static_site_editor_controller_spec.rb b/spec/controllers/projects/static_site_editor_controller_spec.rb
index 7883c7e6f81..7170a3466c5 100644
--- a/spec/controllers/projects/static_site_editor_controller_spec.rb
+++ b/spec/controllers/projects/static_site_editor_controller_spec.rb
@@ -8,6 +8,8 @@ RSpec.describe Projects::StaticSiteEditorController do
let(:data) { instance_double(Hash) }
describe 'GET show' do
+ render_views
+
let(:default_params) do
{
namespace_id: project.namespace,
@@ -82,8 +84,9 @@ RSpec.describe Projects::StaticSiteEditorController do
context 'when invalid config file' do
let(:service_response) { ServiceResponse.error(message: 'invalid') }
- it 'returns 422' do
- expect(response).to have_gitlab_http_status(:unprocessable_entity)
+ it 'redirects to project page and flashes error message' do
+ expect(response).to redirect_to(project_path(project))
+ expect(response).to set_flash[:alert].to('invalid')
end
end
end
diff --git a/spec/features/projects/clusters_spec.rb b/spec/features/projects/clusters_spec.rb
index a27c9d54e8a..058a5c3e607 100644
--- a/spec/features/projects/clusters_spec.rb
+++ b/spec/features/projects/clusters_spec.rb
@@ -13,36 +13,6 @@ RSpec.describe 'Clusters', :js do
gitlab_sign_in(user)
end
- context 'when clusters_list_redesign feature flag is disabled' do
- before do
- stub_feature_flags(clusters_list_redesign: false)
- end
-
- context 'when user does not have a cluster and visits cluster index page' do
- before do
- visit project_clusters_path(project)
- end
-
- it 'sees empty state' do
- expect(page).to have_link('Add Kubernetes cluster')
- expect(page).to have_selector('.empty-state')
- end
- end
-
- context 'when user has a cluster and visits cluster index page' do
- let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
- let(:project) { cluster.project }
-
- before do
- visit project_clusters_path(project)
- end
-
- it 'user sees a table with one cluster' do
- expect(page).to have_selector('[data-testid="cluster_list_table"] .card-body', count: 1)
- end
- end
- end
-
context 'when user does not have a cluster and visits cluster index page' do
before do
visit project_clusters_path(project)
diff --git a/spec/helpers/clusters_helper_spec.rb b/spec/helpers/clusters_helper_spec.rb
index 6164f3b5e8d..f0945106ce3 100644
--- a/spec/helpers/clusters_helper_spec.rb
+++ b/spec/helpers/clusters_helper_spec.rb
@@ -89,32 +89,6 @@ RSpec.describe ClustersHelper do
end
end
- describe '#provider_icon' do
- it 'will return GCP logo with gcp argument' do
- logo = helper.provider_icon('gcp')
-
- expect(logo).to match(%r(img alt="Google GKE" data-src="|/illustrations/logos/google_gke|svg))
- end
-
- it 'will return AWS logo with aws argument' do
- logo = helper.provider_icon('aws')
-
- expect(logo).to match(%r(img alt="Amazon EKS" data-src="|/illustrations/logos/amazon_eks|svg))
- end
-
- it 'will return default logo with unknown provider' do
- logo = helper.provider_icon('unknown')
-
- expect(logo).to match(%r(img alt="Kubernetes Cluster" data-src="|/illustrations/logos/kubernetes|svg))
- end
-
- it 'will return default logo when provider is empty' do
- logo = helper.provider_icon
-
- expect(logo).to match(%r(img alt="Kubernetes Cluster" data-src="|/illustrations/logos/kubernetes|svg))
- end
- end
-
describe '#cluster_type_label' do
subject { helper.cluster_type_label(cluster_type) }
diff --git a/spec/lib/gitlab/static_site_editor/config/file_config/entry/global_spec.rb b/spec/lib/gitlab/static_site_editor/config/file_config/entry/global_spec.rb
new file mode 100644
index 00000000000..57edcd8a07b
--- /dev/null
+++ b/spec/lib/gitlab/static_site_editor/config/file_config/entry/global_spec.rb
@@ -0,0 +1,182 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::StaticSiteEditor::Config::FileConfig::Entry::Global do
+ let(:global) { described_class.new(hash) }
+ let(:default_static_site_generator_value) { 'middleman' }
+
+ shared_examples_for 'valid default configuration' do
+ describe '#compose!' do
+ before do
+ global.compose!
+ end
+
+ it 'creates nodes hash' do
+ expect(global.descendants).to be_an Array
+ end
+
+ it 'creates node object for each entry' do
+ expect(global.descendants.count).to eq 1
+ end
+
+ it 'creates node object using valid class' do
+ expect(global.descendants.first)
+ .to be_an_instance_of expected_node_object_class
+ end
+
+ it 'sets correct description for nodes' do
+ expect(global.descendants.first.description)
+ .to eq 'Configuration of the Static Site Editor static site generator.'
+ end
+
+ describe '#leaf?' do
+ it 'is not leaf' do
+ expect(global).not_to be_leaf
+ end
+ end
+ end
+
+ context 'when not composed' do
+ describe '#static_site_generator_value' do
+ it 'returns nil' do
+ expect(global.static_site_generator_value).to be nil
+ end
+ end
+
+ describe '#leaf?' do
+ it 'is leaf' do
+ expect(global).to be_leaf
+ end
+ end
+ end
+
+ context 'when composed' do
+ before do
+ global.compose!
+ end
+
+ describe '#errors' do
+ it 'has no errors' do
+ expect(global.errors).to be_empty
+ end
+ end
+
+ describe '#static_site_generator_value' do
+ it 'returns correct values' do
+ expect(global.static_site_generator_value).to eq(default_static_site_generator_value)
+ end
+ end
+ end
+ end
+
+ describe '.nodes' do
+ it 'returns a hash' do
+ expect(described_class.nodes).to be_a(Hash)
+ end
+
+ context 'when filtering all the entry/node names' do
+ it 'contains the expected node names' do
+ expect(described_class.nodes.keys)
+ .to match_array(%i[static_site_generator])
+ end
+ end
+ end
+
+ context 'when configuration is valid' do
+ context 'when some entries defined' do
+ let(:expected_node_object_class) { Gitlab::StaticSiteEditor::Config::FileConfig::Entry::StaticSiteGenerator }
+ let(:hash) do
+ { static_site_generator: default_static_site_generator_value }
+ end
+
+ it_behaves_like 'valid default configuration'
+ end
+ end
+
+ context 'when value is an empty hash' do
+ let(:expected_node_object_class) { Gitlab::Config::Entry::Unspecified }
+ let(:hash) { {} }
+
+ it_behaves_like 'valid default configuration'
+ end
+
+ context 'when configuration is not valid' do
+ before do
+ global.compose!
+ end
+
+ context 'when static_site_generator is invalid' do
+ let(:hash) do
+ { static_site_generator: { not_a_string: true } }
+ end
+
+ describe '#errors' do
+ it 'reports errors' do
+ expect(global.errors)
+ .to include 'static_site_generator config should be a string'
+ end
+ end
+ end
+
+ context 'when there is an invalid key' do
+ let(:hash) do
+ { invalid_key: true }
+ end
+
+ describe '#errors' do
+ it 'reports errors' do
+ expect(global.errors)
+ .to include 'global config contains unknown keys: invalid_key'
+ end
+ end
+ end
+ end
+
+ context 'when value is not a hash' do
+ let(:hash) { [] }
+
+ describe '#valid?' do
+ it 'is not valid' do
+ expect(global).not_to be_valid
+ end
+ end
+
+ describe '#errors' do
+ it 'returns error about invalid type' do
+ expect(global.errors.first).to match /should be a hash/
+ end
+ end
+ end
+
+ describe '#specified?' do
+ it 'is concrete entry that is defined' do
+ expect(global.specified?).to be true
+ end
+ end
+
+ describe '#[]' do
+ before do
+ global.compose!
+ end
+
+ let(:hash) do
+ { static_site_generator: default_static_site_generator_value }
+ end
+
+ context 'when entry exists' do
+ it 'returns correct entry' do
+ expect(global[:static_site_generator])
+ .to be_an_instance_of Gitlab::StaticSiteEditor::Config::FileConfig::Entry::StaticSiteGenerator
+ expect(global[:static_site_generator].value).to eq default_static_site_generator_value
+ end
+ end
+
+ context 'when entry does not exist' do
+ it 'always return unspecified node' do
+ expect(global[:some][:unknown][:node])
+ .not_to be_specified
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/static_site_editor/config/file_config/entry/static_site_generator_spec.rb b/spec/lib/gitlab/static_site_editor/config/file_config/entry/static_site_generator_spec.rb
new file mode 100644
index 00000000000..a9c730218cf
--- /dev/null
+++ b/spec/lib/gitlab/static_site_editor/config/file_config/entry/static_site_generator_spec.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::StaticSiteEditor::Config::FileConfig::Entry::StaticSiteGenerator do
+ let(:static_site_generator) { described_class.new(config) }
+
+ describe 'validations' do
+ context 'when value is valid' do
+ let(:config) { 'middleman' }
+
+ describe '#value' do
+ it 'returns a static_site_generator key' do
+ expect(static_site_generator.value).to eq config
+ end
+ end
+
+ describe '#valid?' do
+ it 'is valid' do
+ expect(static_site_generator).to be_valid
+ end
+ end
+ end
+
+ context 'when value is invalid' do
+ let(:config) { 'not-a-valid-generator' }
+
+ describe '#valid?' do
+ it 'is not valid' do
+ expect(static_site_generator).not_to be_valid
+ end
+ end
+ end
+
+ context 'when value has a wrong type' do
+ let(:config) { { not_a_string: true } }
+
+ it 'reports errors about wrong type' do
+ expect(static_site_generator.errors)
+ .to include 'static site generator config should be a string'
+ end
+ end
+ end
+
+ describe '.default' do
+ it 'returns default static_site_generator' do
+ expect(described_class.default).to eq 'middleman'
+ end
+ end
+end
diff --git a/spec/lib/gitlab/static_site_editor/config/file_config_spec.rb b/spec/lib/gitlab/static_site_editor/config/file_config_spec.rb
index 594425c2dab..198ba611cf6 100644
--- a/spec/lib/gitlab/static_site_editor/config/file_config_spec.rb
+++ b/spec/lib/gitlab/static_site_editor/config/file_config_spec.rb
@@ -3,13 +3,93 @@
require 'spec_helper'
RSpec.describe Gitlab::StaticSiteEditor::Config::FileConfig do
- subject(:config) { described_class.new }
+ let(:config) do
+ described_class.new(yml)
+ end
+
+ context 'when config is valid' do
+ context 'when config has valid values' do
+ let(:yml) do
+ <<-EOS
+ static_site_generator: middleman
+ EOS
+ end
+
+ describe '#to_hash_with_defaults' do
+ it 'returns hash created from string' do
+ hash = {
+ static_site_generator: 'middleman'
+ }
+
+ expect(config.to_hash_with_defaults).to eq hash
+ end
+ end
+
+ describe '#valid?' do
+ it 'is valid' do
+ expect(config).to be_valid
+ end
+
+ it 'has no errors' do
+ expect(config.errors).to be_empty
+ end
+ end
+ end
+ end
+
+ context 'when a config entry has an empty value' do
+ let(:yml) { 'static_site_generator: ' }
+
+ describe '#to_hash_with_defaults' do
+ it 'returns default values' do
+ hash = {
+ static_site_generator: 'middleman'
+ }
+
+ expect(config.to_hash_with_defaults).to eq hash
+ end
+ end
+
+ describe '#valid?' do
+ it 'is valid' do
+ expect(config).to be_valid
+ end
+
+ it 'has no errors' do
+ expect(config.errors).to be_empty
+ end
+ end
+ end
+
+ context 'when config is invalid' do
+ context 'when yml is incorrect' do
+ let(:yml) { '// invalid' }
+
+ describe '.new' do
+ it 'raises error' do
+ expect { config }.to raise_error(described_class::ConfigError, /Invalid configuration format/)
+ end
+ end
+ end
+
+ context 'when config value exists but is not a valid value' do
+ let(:yml) { 'static_site_generator: "unsupported-generator"' }
+
+ describe '#valid?' do
+ it 'is not valid' do
+ expect(config).not_to be_valid
+ end
- describe '#data' do
- subject { config.data }
+ it 'has errors' do
+ expect(config.errors).not_to be_empty
+ end
+ end
- it 'returns hardcoded data for now' do
- is_expected.to match(static_site_generator: 'middleman')
+ describe '#errors' do
+ it 'returns an array of strings' do
+ expect(config.errors).to all(be_an_instance_of(String))
+ end
+ end
end
end
end
diff --git a/spec/services/static_site_editor/config_service_spec.rb b/spec/services/static_site_editor/config_service_spec.rb
index 5fff4e0af53..fed373828a1 100644
--- a/spec/services/static_site_editor/config_service_spec.rb
+++ b/spec/services/static_site_editor/config_service_spec.rb
@@ -7,8 +7,8 @@ RSpec.describe StaticSiteEditor::ConfigService do
let_it_be(:user) { create(:user) }
# params
- let(:ref) { double(:ref) }
- let(:path) { double(:path) }
+ let(:ref) { 'master' }
+ let(:path) { 'README.md' }
let(:return_url) { double(:return_url) }
# stub data
@@ -42,22 +42,84 @@ RSpec.describe StaticSiteEditor::ConfigService do
allow_next_instance_of(Gitlab::StaticSiteEditor::Config::GeneratedConfig) do |config|
allow(config).to receive(:data) { generated_data }
end
+ end
+
+ context 'when reading file from repo fails with an unexpected error' do
+ let(:unexpected_error) { RuntimeError.new('some unexpected error') }
- allow_next_instance_of(Gitlab::StaticSiteEditor::Config::FileConfig) do |config|
- allow(config).to receive(:data) { file_data }
+ before do
+ allow(project.repository).to receive(:blob_data_at).and_raise(unexpected_error)
+ end
+
+ it 'returns an error response' do
+ expect(Gitlab::ErrorTracking).to receive(:track_and_raise_exception).with(unexpected_error).and_call_original
+ expect { execute }.to raise_error(unexpected_error)
end
end
- it 'returns merged generated data and config file data' do
- expect(execute).to be_success
- expect(execute.payload).to eq(generated: true, file: true)
+ context 'when file is missing' do
+ before do
+ allow(project.repository).to receive(:blob_data_at).and_raise(GRPC::NotFound)
+ expect_next_instance_of(Gitlab::StaticSiteEditor::Config::FileConfig, '{}') do |config|
+ allow(config).to receive(:valid?) { true }
+ allow(config).to receive(:to_hash_with_defaults) { file_data }
+ end
+ end
+
+ it 'returns default config' do
+ expect(execute).to be_success
+ expect(execute.payload).to eq(generated: true, file: true)
+ end
end
- it 'returns an error if any keys would be overwritten by the merge' do
- generated_data[:duplicate_key] = true
- file_data[:duplicate_key] = true
- expect(execute).to be_error
- expect(execute.message).to match(/duplicate key.*duplicate_key.*found/i)
+ context 'when file is present' do
+ before do
+ allow(project.repository).to receive(:blob_data_at).with(ref, anything) do
+ config_content
+ end
+ end
+
+ context 'and configuration is not valid' do
+ let(:config_content) { 'invalid content' }
+
+ before do
+ expect_next_instance_of(Gitlab::StaticSiteEditor::Config::FileConfig, config_content) do |config|
+ error = 'error'
+ allow(config).to receive_message_chain('errors.first') { error }
+ allow(config).to receive(:valid?) { false }
+ end
+ end
+
+ it 'returns an error' do
+ expect(execute).to be_error
+ expect(execute.message).to eq('Invalid configuration format')
+ end
+ end
+
+ context 'and configuration is valid' do
+ # NOTE: This has to be a valid config, even though it is mocked, because
+ # `expect_next_instance_of` executes the constructor logic.
+ let(:config_content) { 'static_site_generator: middleman' }
+
+ before do
+ expect_next_instance_of(Gitlab::StaticSiteEditor::Config::FileConfig, config_content) do |config|
+ allow(config).to receive(:valid?) { true }
+ allow(config).to receive(:to_hash_with_defaults) { file_data }
+ end
+ end
+
+ it 'returns merged generated data and config file data' do
+ expect(execute).to be_success
+ expect(execute.payload).to eq(generated: true, file: true)
+ end
+
+ it 'returns an error if any keys would be overwritten by the merge' do
+ generated_data[:duplicate_key] = true
+ file_data[:duplicate_key] = true
+ expect(execute).to be_error
+ expect(execute.message).to match(/duplicate key.*duplicate_key.*found/i)
+ end
+ end
end
end
end