summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/api.js14
-rw-r--r--app/assets/javascripts/ide/components/ide.vue4
-rw-r--r--app/assets/javascripts/ide/components/ide_status_bar.vue37
-rw-r--r--app/assets/javascripts/ide/services/index.js4
-rw-r--r--app/assets/javascripts/ide/stores/actions/project.js96
-rw-r--r--app/assets/javascripts/ide/stores/mutation_types.js1
-rw-r--r--app/assets/javascripts/ide/stores/mutations/branch.js9
-rw-r--r--app/assets/javascripts/pipelines/components/empty_state.vue2
-rw-r--r--app/assets/stylesheets/framework/variables.scss2
-rw-r--r--app/assets/stylesheets/pages/repo.scss12
-rw-r--r--app/controllers/projects/clusters/applications_controller.rb7
-rw-r--r--app/helpers/commits_helper.rb4
-rw-r--r--app/models/ci/build.rb2
-rw-r--r--app/models/project.rb4
-rw-r--r--app/services/clusters/applications/schedule_installation_service.rb17
-rw-r--r--app/services/merge_requests/refresh_service.rb8
-rw-r--r--app/services/projects/destroy_service.rb19
-rw-r--r--app/services/projects/open_issues_count_service.rb38
-rw-r--r--app/views/admin/dashboard/index.html.haml2
-rw-r--r--app/views/help/index.html.haml2
-rw-r--r--app/views/layouts/nav/sidebar/_project.html.haml4
-rw-r--r--app/views/projects/commit/branches.html.haml3
-rw-r--r--changelogs/unreleased/44579-ide-add-pipeline-to-status-bar.yml5
-rw-r--r--changelogs/unreleased/46600-fix-gitlab-revision-when-not-in-git-repo.yml6
-rw-r--r--changelogs/unreleased/commit-branch-tag-icon-update.yml5
-rw-r--r--changelogs/unreleased/issue_38418.yml5
-rw-r--r--changelogs/unreleased/migrate-restore-repo-to-gitaly.yml5
-rw-r--r--config/initializers/7_prometheus_metrics.rb2
-rw-r--r--config/initializers/console_message.rb2
-rw-r--r--config/initializers/sentry.rb2
-rw-r--r--doc/ci/examples/code_climate.md19
-rw-r--r--doc/install/requirements.md4
-rw-r--r--doc/topics/autodevops/index.md4
-rw-r--r--doc/topics/autodevops/quick_start_guide.md4
-rw-r--r--doc/university/README.md1
-rw-r--r--doc/user/snippets.md33
-rw-r--r--lib/api/internal.rb2
-rw-r--r--lib/api/version.rb2
-rw-r--r--lib/backup/repository.rb88
-rw-r--r--lib/gitlab.rb17
-rw-r--r--lib/gitlab/gon_helper.rb2
-rw-r--r--lib/tasks/gitlab/info.rake2
-rw-r--r--package.json2
-rw-r--r--spec/javascripts/api_spec.js21
-rw-r--r--spec/javascripts/ide/mock_data.js34
-rw-r--r--spec/javascripts/ide/stores/actions/project_spec.js159
-rw-r--r--spec/javascripts/ide/stores/mutations/branch_spec.js36
-rw-r--r--spec/javascripts/pipelines/empty_state_spec.js2
-rw-r--r--spec/javascripts/pipelines/mock_data.js2
-rw-r--r--spec/lib/backup/repository_spec.rb29
-rw-r--r--spec/lib/gitlab_spec.rb60
-rw-r--r--spec/models/ci/build_spec.rb2
-rw-r--r--spec/requests/api/version_spec.rb2
-rw-r--r--spec/services/clusters/applications/schedule_installation_service_spec.rb33
-rw-r--r--spec/services/projects/open_issues_count_service_spec.rb51
-rw-r--r--spec/views/admin/dashboard/index.html.haml_spec.rb2
-rw-r--r--spec/views/help/index.html.haml_spec.rb2
-rw-r--r--spec/workers/update_merge_requests_worker_spec.rb9
-rw-r--r--vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml8
-rw-r--r--yarn.lock6
60 files changed, 740 insertions, 221 deletions
diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js
index eb919241318..ce1069276ab 100644
--- a/app/assets/javascripts/api.js
+++ b/app/assets/javascripts/api.js
@@ -21,6 +21,7 @@ const Api = {
issuableTemplatePath: '/:namespace_path/:project_path/templates/:type/:key',
usersPath: '/api/:version/users.json',
commitPath: '/api/:version/projects/:id/repository/commits',
+ commitPipelinesPath: '/:project_id/commit/:sha/pipelines',
branchSinglePath: '/api/:version/projects/:id/repository/branches/:branch',
createBranchPath: '/api/:version/projects/:id/repository/branches',
pipelinesPath: '/api/:version/projects/:id/pipelines',
@@ -166,6 +167,19 @@ const Api = {
});
},
+ commitPipelines(projectId, sha) {
+ const encodedProjectId = projectId
+ .split('/')
+ .map(fragment => encodeURIComponent(fragment))
+ .join('/');
+
+ const url = Api.buildUrl(Api.commitPipelinesPath)
+ .replace(':project_id', encodedProjectId)
+ .replace(':sha', encodeURIComponent(sha));
+
+ return axios.get(url);
+ },
+
branchSingle(id, branch) {
const url = Api.buildUrl(Api.branchSinglePath)
.replace(':id', encodeURIComponent(id))
diff --git a/app/assets/javascripts/ide/components/ide.vue b/app/assets/javascripts/ide/components/ide.vue
index 1ec69adce09..0aaf5a112cb 100644
--- a/app/assets/javascripts/ide/components/ide.vue
+++ b/app/assets/javascripts/ide/components/ide.vue
@@ -123,8 +123,6 @@ export default {
</template>
</div>
</div>
- <ide-status-bar
- :file="activeFile"
- />
+ <ide-status-bar :file="activeFile"/>
</article>
</template>
diff --git a/app/assets/javascripts/ide/components/ide_status_bar.vue b/app/assets/javascripts/ide/components/ide_status_bar.vue
index 70c6d53c3ab..6f60cfbf184 100644
--- a/app/assets/javascripts/ide/components/ide_status_bar.vue
+++ b/app/assets/javascripts/ide/components/ide_status_bar.vue
@@ -1,14 +1,16 @@
<script>
-import { mapGetters } from 'vuex';
+import { mapActions, mapState, mapGetters } from 'vuex';
import icon from '~/vue_shared/components/icon.vue';
import tooltip from '~/vue_shared/directives/tooltip';
import timeAgoMixin from '~/vue_shared/mixins/timeago';
+import CiIcon from '../../vue_shared/components/ci_icon.vue';
import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
export default {
components: {
icon,
userAvatarImage,
+ CiIcon,
},
directives: {
tooltip,
@@ -27,8 +29,16 @@ export default {
};
},
computed: {
+ ...mapState(['currentBranchId', 'currentProjectId']),
...mapGetters(['currentProject', 'lastCommit']),
},
+ watch: {
+ lastCommit() {
+ if (!this.isPollingInitialized) {
+ this.initPipelinePolling();
+ }
+ },
+ },
mounted() {
this.startTimer();
},
@@ -36,13 +46,21 @@ export default {
if (this.intervalId) {
clearInterval(this.intervalId);
}
+ if (this.isPollingInitialized) {
+ this.stopPipelinePolling();
+ }
},
methods: {
+ ...mapActions(['pipelinePoll', 'stopPipelinePolling']),
startTimer() {
this.intervalId = setInterval(() => {
this.commitAgeUpdate();
}, 1000);
},
+ initPipelinePolling() {
+ this.pipelinePoll();
+ this.isPollingInitialized = true;
+ },
commitAgeUpdate() {
if (this.lastCommit) {
this.lastCommitFormatedAge = this.timeFormated(this.lastCommit.committed_date);
@@ -61,6 +79,23 @@ export default {
class="ide-status-branch"
v-if="lastCommit && lastCommitFormatedAge"
>
+ <span
+ class="ide-status-pipeline"
+ v-if="lastCommit.pipeline && lastCommit.pipeline.details"
+ >
+ <ci-icon
+ :status="lastCommit.pipeline.details.status"
+ v-tooltip
+ :title="lastCommit.pipeline.details.status.text"
+ />
+ Pipeline
+ <a
+ class="monospace"
+ :href="lastCommit.pipeline.details.status.details_path">#{{ lastCommit.pipeline.id }}</a>
+ {{ lastCommit.pipeline.details.status.text }}
+ for
+ </span>
+
<icon
name="commit"
/>
diff --git a/app/assets/javascripts/ide/services/index.js b/app/assets/javascripts/ide/services/index.js
index a12e637616a..e8b51f2b516 100644
--- a/app/assets/javascripts/ide/services/index.js
+++ b/app/assets/javascripts/ide/services/index.js
@@ -75,4 +75,8 @@ export default {
},
});
},
+ lastCommitPipelines({ getters }) {
+ const commitSha = getters.lastCommit.id;
+ return Api.commitPipelines(getters.currentProject.path_with_namespace, commitSha);
+ },
};
diff --git a/app/assets/javascripts/ide/stores/actions/project.js b/app/assets/javascripts/ide/stores/actions/project.js
index eff9bc03651..cece9154c82 100644
--- a/app/assets/javascripts/ide/stores/actions/project.js
+++ b/app/assets/javascripts/ide/stores/actions/project.js
@@ -1,6 +1,11 @@
+import Visibility from 'visibilityjs';
import flash from '~/flash';
+import { __ } from '~/locale';
import service from '../../services';
import * as types from '../mutation_types';
+import Poll from '../../../lib/utils/poll';
+
+let eTagPoll;
export const getProjectData = (
{ commit, state, dispatch },
@@ -21,7 +26,7 @@ export const getProjectData = (
})
.catch(() => {
flash(
- 'Error loading project data. Please try again.',
+ __('Error loading project data. Please try again.'),
'alert',
document,
null,
@@ -59,7 +64,7 @@ export const getBranchData = (
})
.catch(() => {
flash(
- 'Error loading branch data. Please try again.',
+ __('Error loading branch data. Please try again.'),
'alert',
document,
null,
@@ -73,25 +78,74 @@ export const getBranchData = (
}
});
-export const refreshLastCommitData = (
- { commit, state, dispatch },
- { projectId, branchId } = {},
-) => service
- .getBranchData(projectId, branchId)
- .then(({ data }) => {
- commit(types.SET_BRANCH_COMMIT, {
- projectId,
- branchId,
- commit: data.commit,
+export const refreshLastCommitData = ({ commit, state, dispatch }, { projectId, branchId } = {}) =>
+ service
+ .getBranchData(projectId, branchId)
+ .then(({ data }) => {
+ commit(types.SET_BRANCH_COMMIT, {
+ projectId,
+ branchId,
+ commit: data.commit,
+ });
+ })
+ .catch(() => {
+ flash(__('Error loading last commit.'), 'alert', document, null, false, true);
});
- })
- .catch(() => {
- flash(
- 'Error loading last commit.',
- 'alert',
- document,
- null,
- false,
- true,
+
+export const pollSuccessCallBack = ({ commit, state, dispatch }, { data }) => {
+ if (data.pipelines && data.pipelines.length) {
+ const lastCommitHash =
+ state.projects[state.currentProjectId].branches[state.currentBranchId].commit.id;
+ const lastCommitPipeline = data.pipelines.find(
+ pipeline => pipeline.commit.id === lastCommitHash,
);
+ commit(types.SET_LAST_COMMIT_PIPELINE, {
+ projectId: state.currentProjectId,
+ branchId: state.currentBranchId,
+ pipeline: lastCommitPipeline || {},
+ });
+ }
+
+ return data;
+};
+
+export const pipelinePoll = ({ getters, dispatch }) => {
+ eTagPoll = new Poll({
+ resource: service,
+ method: 'lastCommitPipelines',
+ data: {
+ getters,
+ },
+ successCallback: ({ data }) => dispatch('pollSuccessCallBack', { data }),
+ errorCallback: () => {
+ flash(
+ __('Something went wrong while fetching the latest pipeline status.'),
+ 'alert',
+ document,
+ null,
+ false,
+ true,
+ );
+ },
});
+
+ if (!Visibility.hidden()) {
+ eTagPoll.makeRequest();
+ }
+
+ Visibility.change(() => {
+ if (!Visibility.hidden()) {
+ eTagPoll.restart();
+ } else {
+ eTagPoll.stop();
+ }
+ });
+};
+
+export const stopPipelinePolling = () => {
+ eTagPoll.stop();
+};
+
+export const restartPipelinePolling = () => {
+ eTagPoll.restart();
+};
diff --git a/app/assets/javascripts/ide/stores/mutation_types.js b/app/assets/javascripts/ide/stores/mutation_types.js
index a3fb3232f1d..0a3f8d031c4 100644
--- a/app/assets/javascripts/ide/stores/mutation_types.js
+++ b/app/assets/javascripts/ide/stores/mutation_types.js
@@ -23,6 +23,7 @@ export const SET_BRANCH = 'SET_BRANCH';
export const SET_BRANCH_COMMIT = 'SET_BRANCH_COMMIT';
export const SET_BRANCH_WORKING_REFERENCE = 'SET_BRANCH_WORKING_REFERENCE';
export const TOGGLE_BRANCH_OPEN = 'TOGGLE_BRANCH_OPEN';
+export const SET_LAST_COMMIT_PIPELINE = 'SET_LAST_COMMIT_PIPELINE';
// Tree mutation types
export const SET_DIRECTORY_DATA = 'SET_DIRECTORY_DATA';
diff --git a/app/assets/javascripts/ide/stores/mutations/branch.js b/app/assets/javascripts/ide/stores/mutations/branch.js
index e09f88878f4..f17ec4da308 100644
--- a/app/assets/javascripts/ide/stores/mutations/branch.js
+++ b/app/assets/javascripts/ide/stores/mutations/branch.js
@@ -14,6 +14,10 @@ export default {
treeId: `${projectPath}/${branchName}`,
active: true,
workingReference: '',
+ commit: {
+ ...branch.commit,
+ pipeline: {},
+ },
},
},
});
@@ -28,4 +32,9 @@ export default {
commit,
});
},
+ [types.SET_LAST_COMMIT_PIPELINE](state, { projectId, branchId, pipeline }) {
+ Object.assign(state.projects[projectId].branches[branchId].commit, {
+ pipeline,
+ });
+ },
};
diff --git a/app/assets/javascripts/pipelines/components/empty_state.vue b/app/assets/javascripts/pipelines/components/empty_state.vue
index 10ac8c08bed..6083421073e 100644
--- a/app/assets/javascripts/pipelines/components/empty_state.vue
+++ b/app/assets/javascripts/pipelines/components/empty_state.vue
@@ -34,7 +34,7 @@
</h4>
<p>
- {{ s__(`Pipelines|Continous Integration can help
+ {{ s__(`Pipelines|Continuous Integration can help
catch bugs by running your tests automatically,
while Continuous Deployment can help you deliver
code to your product environment.`) }}
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index b8ea8ee14c5..86f82ec14ce 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -230,7 +230,7 @@ $row-hover: $blue-50;
$row-hover-border: $blue-200;
$progress-color: #c0392b;
$header-height: 40px;
-$ide-statusbar-height: 27px;
+$ide-statusbar-height: 25px;
$fixed-layout-width: 1280px;
$limited-layout-width: 990px;
$limited-layout-width-sm: 790px;
diff --git a/app/assets/stylesheets/pages/repo.scss b/app/assets/stylesheets/pages/repo.scss
index 175d2779bb7..35985d3c8f3 100644
--- a/app/assets/stylesheets/pages/repo.scss
+++ b/app/assets/stylesheets/pages/repo.scss
@@ -22,7 +22,6 @@
height: calc(100vh - #{$header-height});
margin-top: 0;
border-top: 1px solid $white-dark;
- border-bottom: 1px solid $white-dark;
padding-bottom: $ide-statusbar-height;
&.is-collapsed {
@@ -380,7 +379,7 @@
.ide-status-bar {
border-top: 1px solid $white-dark;
- padding: $gl-bar-padding $gl-padding;
+ padding: 2px $gl-padding-8 0;
background: $white-light;
display: flex;
justify-content: space-between;
@@ -391,12 +390,19 @@
left: 0;
width: 100%;
+ font-size: 12px;
+ line-height: 22px;
+
+ * {
+ font-size: inherit;
+ }
+
> div + div {
padding-left: $gl-padding;
}
svg {
- vertical-align: middle;
+ vertical-align: sub;
}
}
diff --git a/app/controllers/projects/clusters/applications_controller.rb b/app/controllers/projects/clusters/applications_controller.rb
index 90c7fa62216..35885543622 100644
--- a/app/controllers/projects/clusters/applications_controller.rb
+++ b/app/controllers/projects/clusters/applications_controller.rb
@@ -5,9 +5,10 @@ class Projects::Clusters::ApplicationsController < Projects::ApplicationControll
before_action :authorize_create_cluster!, only: [:create]
def create
- Clusters::Applications::ScheduleInstallationService.new(project, current_user,
- application_class: @application_class,
- cluster: @cluster).execute
+ application = @application_class.find_or_create_by!(cluster: @cluster)
+
+ Clusters::Applications::ScheduleInstallationService.new(project, current_user).execute(application)
+
head :no_content
rescue StandardError
head :bad_request
diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb
index e594a1d0ba3..f5a7871a6e0 100644
--- a/app/helpers/commits_helper.rb
+++ b/app/helpers/commits_helper.rb
@@ -63,7 +63,7 @@ module CommitsHelper
# Returns a link formatted as a commit branch link
def commit_branch_link(url, text)
link_to(url, class: 'label label-gray ref-name branch-link') do
- sprite_icon('fork', size: 12, css_class: 'fork-svg') + "#{text}"
+ sprite_icon('branch', size: 12, css_class: 'fork-svg') + "#{text}"
end
end
@@ -77,7 +77,7 @@ module CommitsHelper
# Returns a link formatted as a commit tag link
def commit_tag_link(url, text)
link_to(url, class: 'label label-gray ref-name') do
- icon('tag', class: 'append-right-5') + "#{text}"
+ sprite_icon('tag', size: 12, css_class: 'append-right-5 vertical-align-middle') + "#{text}"
end
end
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 495430931aa..75fd55a8f7b 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -618,7 +618,7 @@ module Ci
variables.append(key: 'GITLAB_FEATURES', value: project.licensed_features.join(','))
variables.append(key: 'CI_SERVER_NAME', value: 'GitLab')
variables.append(key: 'CI_SERVER_VERSION', value: Gitlab::VERSION)
- variables.append(key: 'CI_SERVER_REVISION', value: Gitlab::REVISION)
+ variables.append(key: 'CI_SERVER_REVISION', value: Gitlab.revision)
variables.append(key: 'CI_JOB_NAME', value: name)
variables.append(key: 'CI_JOB_STAGE', value: stage)
variables.append(key: 'CI_COMMIT_SHA', value: sha)
diff --git a/app/models/project.rb b/app/models/project.rb
index 0e727664d39..0fe9f8880b4 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -1431,8 +1431,8 @@ class Project < ActiveRecord::Base
self.runners_token && ActiveSupport::SecurityUtils.variable_size_secure_compare(token, self.runners_token)
end
- def open_issues_count
- Projects::OpenIssuesCountService.new(self).count
+ def open_issues_count(current_user = nil)
+ Projects::OpenIssuesCountService.new(self, current_user).count
end
def open_merge_requests_count
diff --git a/app/services/clusters/applications/schedule_installation_service.rb b/app/services/clusters/applications/schedule_installation_service.rb
index eb8caa68ef7..9c5461e85e1 100644
--- a/app/services/clusters/applications/schedule_installation_service.rb
+++ b/app/services/clusters/applications/schedule_installation_service.rb
@@ -1,21 +1,10 @@
module Clusters
module Applications
class ScheduleInstallationService < ::BaseService
- def execute
- application_class.find_or_create_by!(cluster: cluster).try do |application|
- application.make_scheduled!
- ClusterInstallAppWorker.perform_async(application.name, application.id)
- end
- end
-
- private
-
- def application_class
- params[:application_class]
- end
+ def execute(application)
+ application.make_scheduled!
- def cluster
- params[:cluster]
+ ClusterInstallAppWorker.perform_async(application.name, application.id)
end
end
end
diff --git a/app/services/merge_requests/refresh_service.rb b/app/services/merge_requests/refresh_service.rb
index 1fb1796b56c..0127d781686 100644
--- a/app/services/merge_requests/refresh_service.rb
+++ b/app/services/merge_requests/refresh_service.rb
@@ -3,6 +3,12 @@ module MergeRequests
def execute(oldrev, newrev, ref)
return true unless Gitlab::Git.branch_ref?(ref)
+ do_execute(oldrev, newrev, ref)
+ end
+
+ private
+
+ def do_execute(oldrev, newrev, ref)
@oldrev, @newrev = oldrev, newrev
@branch_name = Gitlab::Git.ref_name(ref)
@@ -28,8 +34,6 @@ module MergeRequests
true
end
- private
-
def close_upon_missing_source_branch_ref
# MergeRequest#reload_diff ignores not opened MRs. This means it won't
# create an `empty` diff for `closed` MRs without a source branch, keeping
diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb
index adbc498d0bf..077d27c5836 100644
--- a/app/services/projects/destroy_service.rb
+++ b/app/services/projects/destroy_service.rb
@@ -51,11 +51,11 @@ module Projects
flush_caches(@project)
- unless mv_repository(removal_path(repo_path), repo_path)
+ unless rollback_repository(removal_path(repo_path), repo_path)
raise_error('Failed to restore project repository. Please contact the administrator.')
end
- unless mv_repository(removal_path(wiki_path), wiki_path)
+ unless rollback_repository(removal_path(wiki_path), wiki_path)
raise_error('Failed to restore wiki repository. Please contact the administrator.')
end
end
@@ -84,6 +84,9 @@ module Projects
# Skip repository removal. We use this flag when remove user or group
return true if params[:skip_repo] == true
+ # There is a possibility project does not have repository or wiki
+ return true unless repo_exists?(path)
+
new_path = removal_path(path)
if mv_repository(path, new_path)
@@ -98,8 +101,18 @@ module Projects
end
end
- def mv_repository(from_path, to_path)
+ def rollback_repository(old_path, new_path)
# There is a possibility project does not have repository or wiki
+ return true unless repo_exists?(old_path)
+
+ mv_repository(old_path, new_path)
+ end
+
+ def repo_exists?(path)
+ gitlab_shell.exists?(project.repository_storage, path + '.git')
+ end
+
+ def mv_repository(from_path, to_path)
return true unless gitlab_shell.exists?(project.repository_storage, from_path + '.git')
gitlab_shell.mv_repository(project.repository_storage, from_path, to_path)
diff --git a/app/services/projects/open_issues_count_service.rb b/app/services/projects/open_issues_count_service.rb
index a975a06a05c..0a004677417 100644
--- a/app/services/projects/open_issues_count_service.rb
+++ b/app/services/projects/open_issues_count_service.rb
@@ -2,14 +2,42 @@ module Projects
# Service class for counting and caching the number of open issues of a
# project.
class OpenIssuesCountService < Projects::CountService
+ include Gitlab::Utils::StrongMemoize
+
+ def initialize(project, user = nil)
+ @user = user
+
+ super(project)
+ end
+
def cache_key_name
- 'open_issues_count'
+ public_only? ? 'public_open_issues_count' : 'total_open_issues_count'
+ end
+
+ def public_only?
+ !user_is_at_least_reporter?
+ end
+
+ def relation_for_count
+ self.class.query(@project, public_only: public_only?)
+ end
+
+ def user_is_at_least_reporter?
+ strong_memoize(:user_is_at_least_reporter) do
+ @user && @project.team.member?(@user, Gitlab::Access::REPORTER)
+ end
end
- def self.query(project_ids)
- # We don't include confidential issues in this number since this would
- # expose the number of confidential issues to non project members.
- Issue.opened.public_only.where(project: project_ids)
+ # We only show total issues count for reporters
+ # which are allowed to view confidential issues
+ # This will still show a discrepancy on issues number but should be less than before.
+ # Check https://gitlab.com/gitlab-org/gitlab-ce/issues/38418 description.
+ def self.query(projects, public_only: true)
+ if public_only
+ Issue.opened.public_only.where(project: projects)
+ else
+ Issue.opened.where(project: projects)
+ end
end
end
end
diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml
index cfa1d9d0f0c..dd1800eff01 100644
--- a/app/views/admin/dashboard/index.html.haml
+++ b/app/views/admin/dashboard/index.html.haml
@@ -132,7 +132,7 @@
GitLab
%span.pull-right
= Gitlab::VERSION
- = "(#{Gitlab::REVISION})"
+ = "(#{Gitlab.revision})"
%p
GitLab Shell
%span.pull-right
diff --git a/app/views/help/index.html.haml b/app/views/help/index.html.haml
index bf2725dc328..c7a64d77a6a 100644
--- a/app/views/help/index.html.haml
+++ b/app/views/help/index.html.haml
@@ -8,7 +8,7 @@
Community Edition
- if user_signed_in?
%span= Gitlab::VERSION
- %small= link_to Gitlab::REVISION, Gitlab::COM_URL + namespace_project_commits_path('gitlab-org', 'gitlab-ce', Gitlab::REVISION)
+ %small= link_to Gitlab.revision, Gitlab::COM_URL + namespace_project_commits_path('gitlab-org', 'gitlab-ce', Gitlab.revision)
= version_status_badge
%hr
diff --git a/app/views/layouts/nav/sidebar/_project.html.haml b/app/views/layouts/nav/sidebar/_project.html.haml
index f3af15d771d..99e4113bd5a 100644
--- a/app/views/layouts/nav/sidebar/_project.html.haml
+++ b/app/views/layouts/nav/sidebar/_project.html.haml
@@ -89,7 +89,7 @@
= _('Issues')
- if @project.issues_enabled?
%span.badge.count.issue_counter
- = number_with_delimiter(@project.open_issues_count)
+ = number_with_delimiter(@project.open_issues_count(current_user))
%ul.sidebar-sub-level-items
= nav_link(controller: :issues, html_options: { class: "fly-out-top-item" } ) do
@@ -98,7 +98,7 @@
= _('Issues')
- if @project.issues_enabled?
%span.badge.count.issue_counter.fly-out-badge
- = number_with_delimiter(@project.open_issues_count)
+ = number_with_delimiter(@project.open_issues_count(current_user))
%li.divider.fly-out-top-item
= nav_link(controller: :issues, action: :index) do
= link_to project_issues_path(@project), title: 'Issues' do
diff --git a/app/views/projects/commit/branches.html.haml b/app/views/projects/commit/branches.html.haml
index 8611129b356..a91e31afc2b 100644
--- a/app/views/projects/commit/branches.html.haml
+++ b/app/views/projects/commit/branches.html.haml
@@ -6,7 +6,8 @@
- if @branches.any? || @tags.any? || @tags_limit_exceeded
%span
- = link_to "…", "#", class: "js-details-expand label label-gray"
+ = link_to "#", class: "js-details-expand label label-gray ref-name" do
+ = sprite_icon('ellipsis_h', size: 12, css_class: 'vertical-align-middle')
%span.js-details-content.hide
= commit_branches_links(@project, @branches)
- if @tags_limit_exceeded
diff --git a/changelogs/unreleased/44579-ide-add-pipeline-to-status-bar.yml b/changelogs/unreleased/44579-ide-add-pipeline-to-status-bar.yml
new file mode 100644
index 00000000000..21e7c795815
--- /dev/null
+++ b/changelogs/unreleased/44579-ide-add-pipeline-to-status-bar.yml
@@ -0,0 +1,5 @@
+---
+title: Add pipeline status to the status bar of the Web IDE
+merge_request:
+author:
+type: added
diff --git a/changelogs/unreleased/46600-fix-gitlab-revision-when-not-in-git-repo.yml b/changelogs/unreleased/46600-fix-gitlab-revision-when-not-in-git-repo.yml
new file mode 100644
index 00000000000..1d0b11cfd2a
--- /dev/null
+++ b/changelogs/unreleased/46600-fix-gitlab-revision-when-not-in-git-repo.yml
@@ -0,0 +1,6 @@
+---
+title: Replace Gitlab::REVISION with Gitlab.revision and handle installations without
+ a .git directory
+merge_request: 19125
+author:
+type: fixed
diff --git a/changelogs/unreleased/commit-branch-tag-icon-update.yml b/changelogs/unreleased/commit-branch-tag-icon-update.yml
new file mode 100644
index 00000000000..136b7cbf0f4
--- /dev/null
+++ b/changelogs/unreleased/commit-branch-tag-icon-update.yml
@@ -0,0 +1,5 @@
+---
+title: Updated icons for branch and tag names in commit details
+merge_request: 18953
+author: Constance Okoghenun
+type: changed
diff --git a/changelogs/unreleased/issue_38418.yml b/changelogs/unreleased/issue_38418.yml
new file mode 100644
index 00000000000..79452b27e4b
--- /dev/null
+++ b/changelogs/unreleased/issue_38418.yml
@@ -0,0 +1,5 @@
+---
+title: Fix issue count on sidebar
+merge_request:
+author:
+type: other
diff --git a/changelogs/unreleased/migrate-restore-repo-to-gitaly.yml b/changelogs/unreleased/migrate-restore-repo-to-gitaly.yml
new file mode 100644
index 00000000000..59f375de20e
--- /dev/null
+++ b/changelogs/unreleased/migrate-restore-repo-to-gitaly.yml
@@ -0,0 +1,5 @@
+---
+title: Support restoring repositories into gitaly
+merge_request:
+author:
+type: changed
diff --git a/config/initializers/7_prometheus_metrics.rb b/config/initializers/7_prometheus_metrics.rb
index eb7959e4da6..146c4b1e024 100644
--- a/config/initializers/7_prometheus_metrics.rb
+++ b/config/initializers/7_prometheus_metrics.rb
@@ -25,7 +25,7 @@ Sidekiq.configure_server do |config|
end
end
-if Gitlab::Metrics.prometheus_metrics_enabled?
+if !Rails.env.test? && Gitlab::Metrics.prometheus_metrics_enabled?
unless Sidekiq.server?
Gitlab::Metrics::Samplers::UnicornSampler.initialize_instance(Settings.monitoring.unicorn_sampler_interval).start
end
diff --git a/config/initializers/console_message.rb b/config/initializers/console_message.rb
index 536ab337d85..2c46a25f365 100644
--- a/config/initializers/console_message.rb
+++ b/config/initializers/console_message.rb
@@ -3,7 +3,7 @@ if defined?(Rails::Console)
# note that this will not print out when using `spring`
justify = 15
puts "-------------------------------------------------------------------------------------"
- puts " Gitlab:".ljust(justify) + "#{Gitlab::VERSION} (#{Gitlab::REVISION})"
+ puts " Gitlab:".ljust(justify) + "#{Gitlab::VERSION} (#{Gitlab.revision})"
puts " Gitlab Shell:".ljust(justify) + Gitlab::Shell.new.version
puts " #{Gitlab::Database.adapter_name}:".ljust(justify) + Gitlab::Database.version
puts "-------------------------------------------------------------------------------------"
diff --git a/config/initializers/sentry.rb b/config/initializers/sentry.rb
index b2da3b3dc19..17d09293205 100644
--- a/config/initializers/sentry.rb
+++ b/config/initializers/sentry.rb
@@ -13,7 +13,7 @@ def configure_sentry
if sentry_enabled
Raven.configure do |config|
config.dsn = Gitlab::CurrentSettings.current_application_settings.sentry_dsn
- config.release = Gitlab::REVISION
+ config.release = Gitlab.revision
# Sanitize fields based on those sanitized from Rails.
config.sanitize_fields = Rails.application.config.filter_parameters.map(&:to_s)
diff --git a/doc/ci/examples/code_climate.md b/doc/ci/examples/code_climate.md
index d1aa783cc9c..cc19e090964 100644
--- a/doc/ci/examples/code_climate.md
+++ b/doc/ci/examples/code_climate.md
@@ -5,10 +5,10 @@ GitLab CI and Docker.
First, you need GitLab Runner with [docker-in-docker executor][dind].
-Once you set up the Runner, add a new job to `.gitlab-ci.yml`, called `codequality`:
+Once you set up the Runner, add a new job to `.gitlab-ci.yml`, called `code_quality`:
```yaml
-codequality:
+code_quality:
image: docker:stable
variables:
DOCKER_DRIVER: overlay2
@@ -23,20 +23,27 @@ codequality:
--volume /var/run/docker.sock:/var/run/docker.sock
"registry.gitlab.com/gitlab-org/security-products/codequality:$SP_VERSION" /code
artifacts:
- paths: [codeclimate.json]
+ paths: [gl-code-quality-report.json]
```
-The above example will create a `codequality` job in your CI/CD pipeline which
+The above example will create a `code_quality` job in your CI/CD pipeline which
will scan your source code for code quality issues. The report will be saved
as an artifact that you can later download and analyze.
TIP: **Tip:**
Starting with [GitLab Starter][ee] 9.3, this information will
be automatically extracted and shown right in the merge request widget. To do
-so, the CI/CD job must be named `codequality` and the artifact path must be
-`codeclimate.json`.
+so, the CI/CD job must be named `code_quality` and the artifact path must be
+`gl-code-quality-report.json`.
[Learn more on code quality diffs in merge requests](https://docs.gitlab.com/ee/user/project/merge_requests/code_quality_diff.html).
+CAUTION: **Caution:**
+Code Quality was previously using `codeclimate` and `codequality` for job name and
+`codeclimate.json` for the artifact name. While these old names
+are still maintained they have been deprecated with GitLab 11.0 and may be removed
+in next major release, GitLab 12.0. You are advised to update your current `.gitlab-ci.yml`
+configuration to reflect that change.
+
[cli]: https://github.com/codeclimate/codeclimate
[dind]: ../docker/using_docker_build.md#use-docker-in-docker-executor
[ee]: https://about.gitlab.com/products/
diff --git a/doc/install/requirements.md b/doc/install/requirements.md
index 1f2b4d9d3d9..1f399a8a3f7 100644
--- a/doc/install/requirements.md
+++ b/doc/install/requirements.md
@@ -27,8 +27,8 @@ Please see the [installation from source guide](installation.md) and the [instal
### Non-Unix operating systems such as Windows
-GitLab is developed for Unix operating systems.
-GitLab does **not** run on Windows and we have no plans of supporting it in the near future.
+GitLab is developed for Unix operating systems.
+It does **not** run on Windows, and we have no plans to support it in the near future. For the latest development status view this [issue](https://gitlab.com/gitlab-org/gitlab-ce/issues/46567).
Please consider using a virtual machine to run GitLab.
## Ruby versions
diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md
index f80c82acfa3..efec365042a 100644
--- a/doc/topics/autodevops/index.md
+++ b/doc/topics/autodevops/index.md
@@ -220,8 +220,8 @@ tests, it's up to you to add them.
### Auto Code Quality
-Auto Code Quality uses the open source
-[`codeclimate` image](https://hub.docker.com/r/codeclimate/codeclimate/) to run
+Auto Code Quality uses the
+[Code Quality image](https://gitlab.com/gitlab-org/security-products/codequality) to run
static analysis and other code checks on the current code. The report is
created, and is uploaded as an artifact which you can later download and check
out.
diff --git a/doc/topics/autodevops/quick_start_guide.md b/doc/topics/autodevops/quick_start_guide.md
index 8989a4c8956..61c04f3d9bb 100644
--- a/doc/topics/autodevops/quick_start_guide.md
+++ b/doc/topics/autodevops/quick_start_guide.md
@@ -126,10 +126,10 @@ Next, a pipeline needs to be triggered. Since the test project doesn't have a
manually visit `https://gitlab.com/<username>/minimal-ruby-app/pipelines/new`,
where `<username>` is your username.
-This will create a new pipeline with several jobs: `build`, `test`, `codequality`,
+This will create a new pipeline with several jobs: `build`, `test`, `code_quality`,
and `production`. The `build` job will create a Docker image with your new
change and push it to the Container Registry. The `test` job will test your
-changes, whereas the `codequality` job will run static analysis on your changes.
+changes, whereas the `code_quality` job will run static analysis on your changes.
Finally, the `production` job will deploy your changes to a production application.
Once the deploy job succeeds you should be able to see your application by
diff --git a/doc/university/README.md b/doc/university/README.md
index 55865ac23e8..aa68c841f92 100644
--- a/doc/university/README.md
+++ b/doc/university/README.md
@@ -28,7 +28,6 @@ The curriculum is composed of GitLab videos, screencasts, presentations, project
#### 1.1. Version Control and Git
1. [Version Control Systems](https://docs.google.com/presentation/d/16sX7hUrCZyOFbpvnrAFrg6tVO5_yT98IgdAqOmXwBho/edit#slide=id.g72f2e4906_2_29)
-1. [Operating Systems and How Git Works](https://drive.google.com/a/gitlab.com/file/d/0B41DBToSSIG_OVYxVFJDOGI3Vzg/view?usp=sharing)
1. [Code School: An Introduction to Git](https://www.codeschool.com/account/courses/try-git)
#### 1.2. GitLab Basics
diff --git a/doc/user/snippets.md b/doc/user/snippets.md
index 2170b079f62..8397c0b00ef 100644
--- a/doc/user/snippets.md
+++ b/doc/user/snippets.md
@@ -27,3 +27,36 @@ Personal snippets are not related to any project and can be created completely i
You can download the raw content of a snippet.
By default snippets will be downloaded with Linux-style line endings (`LF`). If you want to preserve the original line endings you need to add a parameter `line_ending=raw` (eg. `https://gitlab.com/snippets/SNIPPET_ID/raw?line_ending=raw`). In case a snippet was created using the GitLab web interface the original line ending is Windows-like (`CRLF`).
+
+## Embedded Snippets
+
+> Introduced in GitLab 10.8.
+
+Public snippets can not only be shared, but also embedded on any website. This
+allows to reuse a GitLab snippet in multiple places and any change to the source
+is automatically reflected in the embedded snippet.
+
+To embed a snippet, first make sure that:
+
+- The project is public (if it's a project snippet)
+- The snippet is public
+- In **Project > Settings > Permissions**, the snippets permissions are
+ set to **Everyone with access**
+
+Once the above conditions are met, the "Embed" section will appear in your snippet
+where you can simply click on the "Copy to clipboard" button. This copies a one-line
+script that you can add to any website or blog post.
+
+Here's how an example code looks like:
+
+```html
+<script src="https://gitlab.com/namespace/project/snippets/SNIPPET_ID.js"></script>
+```
+
+Here's how an embedded snippet looks like:
+
+<script src="https://gitlab.com/gitlab-org/gitlab-ce/snippets/1717978.js"></script>
+
+Embedded snippets are displayed with a header that shows the file name if defined,
+the snippet size, a link to GitLab, and the actual snippet content. Actions in
+the header allow users to see the snippet in raw format and download it.
diff --git a/lib/api/internal.rb b/lib/api/internal.rb
index 6b72caea8fd..a3dac36b8b6 100644
--- a/lib/api/internal.rb
+++ b/lib/api/internal.rb
@@ -113,7 +113,7 @@ module API
{
api_version: API.version,
gitlab_version: Gitlab::VERSION,
- gitlab_rev: Gitlab::REVISION,
+ gitlab_rev: Gitlab.revision,
redis: redis_ping
}
end
diff --git a/lib/api/version.rb b/lib/api/version.rb
index 9ba576bd828..3b10bfa6a7d 100644
--- a/lib/api/version.rb
+++ b/lib/api/version.rb
@@ -6,7 +6,7 @@ module API
detail 'This feature was introduced in GitLab 8.13.'
end
get '/version' do
- { version: Gitlab::VERSION, revision: Gitlab::REVISION }
+ { version: Gitlab::VERSION, revision: Gitlab.revision }
end
end
end
diff --git a/lib/backup/repository.rb b/lib/backup/repository.rb
index 44ad991c72a..c3360c391af 100644
--- a/lib/backup/repository.rb
+++ b/lib/backup/repository.rb
@@ -73,6 +73,9 @@ module Backup
end
def prepare_directories
+ # TODO: Need to find a way to do this for gitaly
+ # Gitaly discussion issue: https://gitlab.com/gitlab-org/gitaly/issues/1194
+
Gitlab.config.repositories.storages.each do |name, repository_storage|
path = repository_storage.legacy_disk_path
next unless File.exist?(path)
@@ -93,70 +96,65 @@ module Backup
end
end
+ def restore_custom_hooks(project)
+ # TODO: Need to find a way to do this for gitaly
+ # Gitaly migration issue: https://gitlab.com/gitlab-org/gitaly/issues/1195
+ in_path(path_to_tars(project)) do |dir|
+ path_to_project_repo = path_to_repo(project)
+ cmd = %W(tar -xf #{path_to_tars(project, dir)} -C #{path_to_project_repo} #{dir})
+
+ output, status = Gitlab::Popen.popen(cmd)
+ unless status.zero?
+ progress_warn(project, cmd.join(' '), output)
+ end
+ end
+ end
+
def restore
prepare_directories
+ gitlab_shell = Gitlab::Shell.new
Project.find_each(batch_size: 1000) do |project|
- progress.print " * #{display_repo_path(project)} ... "
- path_to_project_repo = path_to_repo(project)
+ progress.print " * #{project.full_path} ... "
path_to_project_bundle = path_to_bundle(project)
-
project.ensure_storage_path_exists
- cmd = if File.exist?(path_to_project_bundle)
- %W(#{Gitlab.config.git.bin_path} clone --bare --mirror #{path_to_project_bundle} #{path_to_project_repo})
- else
- %W(#{Gitlab.config.git.bin_path} init --bare #{path_to_project_repo})
- end
+ restore_repo_success = nil
+ if File.exist?(path_to_project_bundle)
+ begin
+ gitlab_shell.remove_repository(project.repository_storage, project.disk_path) if project.repository_exists?
+ project.repository.create_from_bundle path_to_project_bundle
+ restore_repo_success = true
+ rescue => e
+ restore_repo_success = false
+ progress.puts "Error: #{e}".color(:red)
+ end
+ else
+ restore_repo_success = gitlab_shell.create_repository(project.repository_storage, project.disk_path)
+ end
- output, status = Gitlab::Popen.popen(cmd)
- if status.zero?
+ if restore_repo_success
progress.puts "[DONE]".color(:green)
else
- progress_warn(project, cmd.join(' '), output)
+ progress.puts "[Failed] restoring #{project.full_path} repository".color(:red)
end
- in_path(path_to_tars(project)) do |dir|
- cmd = %W(tar -xf #{path_to_tars(project, dir)} -C #{path_to_project_repo} #{dir})
-
- output, status = Gitlab::Popen.popen(cmd)
- unless status.zero?
- progress_warn(project, cmd.join(' '), output)
- end
- end
+ restore_custom_hooks(project)
wiki = ProjectWiki.new(project)
- path_to_wiki_repo = path_to_repo(wiki)
path_to_wiki_bundle = path_to_bundle(wiki)
if File.exist?(path_to_wiki_bundle)
- progress.print " * #{display_repo_path(wiki)} ... "
-
- # If a wiki bundle exists, first remove the empty repo
- # that was initialized with ProjectWiki.new() and then
- # try to restore with 'git clone --bare'.
- FileUtils.rm_rf(path_to_wiki_repo)
- cmd = %W(#{Gitlab.config.git.bin_path} clone --bare #{path_to_wiki_bundle} #{path_to_wiki_repo})
-
- output, status = Gitlab::Popen.popen(cmd)
- if status.zero?
- progress.puts " [DONE]".color(:green)
- else
- progress_warn(project, cmd.join(' '), output)
+ progress.print " * #{wiki.full_path} ... "
+ begin
+ gitlab_shell.remove_repository(wiki.repository_storage, wiki.disk_path) if wiki.repository_exists?
+ wiki.repository.create_from_bundle(path_to_wiki_bundle)
+ progress.puts "[DONE]".color(:green)
+ rescue => e
+ progress.puts "[Failed] restoring #{wiki.full_path} wiki".color(:red)
+ progress.puts "Error #{e}".color(:red)
end
end
end
-
- progress.print 'Put GitLab hooks in repositories dirs'.color(:yellow)
- cmd = %W(#{Gitlab.config.gitlab_shell.path}/bin/create-hooks) + repository_storage_paths_args
-
- output, status = Gitlab::Popen.popen(cmd)
- if status.zero?
- progress.puts " [DONE]".color(:green)
- else
- puts " [FAILED]".color(:red)
- puts "failed: #{cmd}"
- puts output
- end
end
# rubocop:enable Metrics/AbcSize
diff --git a/lib/gitlab.rb b/lib/gitlab.rb
index 31119471b8e..a129746e2c6 100644
--- a/lib/gitlab.rb
+++ b/lib/gitlab.rb
@@ -13,11 +13,26 @@ module Gitlab
@_migrations_hash ||= Digest::MD5.hexdigest(ActiveRecord::Migrator.get_all_versions.to_s)
end
+ def self.revision
+ @_revision ||= begin
+ if File.exist?(root.join("REVISION"))
+ File.read(root.join("REVISION")).strip.freeze
+ else
+ result = Gitlab::Popen.popen_with_detail(%W[#{config.git.bin_path} log --pretty=format:%h -n 1])
+
+ if result.status.success?
+ result.stdout.chomp.freeze
+ else
+ "Unknown".freeze
+ end
+ end
+ end
+ end
+
COM_URL = 'https://gitlab.com'.freeze
APP_DIRS_PATTERN = %r{^/?(app|config|ee|lib|spec|\(\w*\))}
SUBDOMAIN_REGEX = %r{\Ahttps://[a-z0-9]+\.gitlab\.com\z}
VERSION = File.read(root.join("VERSION")).strip.freeze
- REVISION = Gitlab::Popen.popen(%W(#{config.git.bin_path} log --pretty=format:%h -n 1)).first.chomp.freeze
def self.com?
# Check `gl_subdomain?` as well to keep parity with gitlab.com
diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb
index c741dabe168..0d31934347f 100644
--- a/lib/gitlab/gon_helper.rb
+++ b/lib/gitlab/gon_helper.rb
@@ -15,7 +15,7 @@ module Gitlab
gon.user_color_scheme = Gitlab::ColorSchemes.for_user(current_user).css_class
gon.sentry_dsn = Gitlab::CurrentSettings.clientside_sentry_dsn if Gitlab::CurrentSettings.clientside_sentry_enabled
gon.gitlab_url = Gitlab.config.gitlab.url
- gon.revision = Gitlab::REVISION
+ gon.revision = Gitlab.revision
gon.gitlab_logo = ActionController::Base.helpers.asset_path('gitlab_logo.png')
gon.sprite_icons = IconsHelper.sprite_icon_path
gon.sprite_file_icons = IconsHelper.sprite_file_icons_path
diff --git a/lib/tasks/gitlab/info.rake b/lib/tasks/gitlab/info.rake
index 47ed522aec3..289aa5d9060 100644
--- a/lib/tasks/gitlab/info.rake
+++ b/lib/tasks/gitlab/info.rake
@@ -47,7 +47,7 @@ namespace :gitlab do
puts ""
puts "GitLab information".color(:yellow)
puts "Version:\t#{Gitlab::VERSION}"
- puts "Revision:\t#{Gitlab::REVISION}"
+ puts "Revision:\t#{Gitlab.revision}"
puts "Directory:\t#{Rails.root}"
puts "DB Adapter:\t#{database_adapter}"
puts "URL:\t\t#{Gitlab.config.gitlab.url}"
diff --git a/package.json b/package.json
index 1382afd41d6..68e5e0a9b6a 100644
--- a/package.json
+++ b/package.json
@@ -16,7 +16,7 @@
"webpack-prod": "NODE_ENV=production webpack --config config/webpack.config.js"
},
"dependencies": {
- "@gitlab-org/gitlab-svgs": "^1.22.0",
+ "@gitlab-org/gitlab-svgs": "^1.23.0",
"autosize": "^4.0.0",
"axios": "^0.17.1",
"babel-core": "^6.26.3",
diff --git a/spec/javascripts/api_spec.js b/spec/javascripts/api_spec.js
index 3d7ccf432be..e8435116221 100644
--- a/spec/javascripts/api_spec.js
+++ b/spec/javascripts/api_spec.js
@@ -341,4 +341,25 @@ describe('Api', () => {
.catch(done.fail);
});
});
+
+ describe('commitPipelines', () => {
+ it('fetches pipelines for a given commit', done => {
+ const projectId = 'example/foobar';
+ const commitSha = 'abc123def';
+ const expectedUrl = `${dummyUrlRoot}/${projectId}/commit/${commitSha}/pipelines`;
+ mock.onGet(expectedUrl).reply(200, [
+ {
+ name: 'test',
+ },
+ ]);
+
+ Api.commitPipelines(projectId, commitSha)
+ .then(({ data }) => {
+ expect(data.length).toBe(1);
+ expect(data[0].name).toBe('test');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
});
diff --git a/spec/javascripts/ide/mock_data.js b/spec/javascripts/ide/mock_data.js
index 7e641c7984b..c68ae050641 100644
--- a/spec/javascripts/ide/mock_data.js
+++ b/spec/javascripts/ide/mock_data.js
@@ -59,3 +59,37 @@ export const jobs = [
duration: 1,
},
];
+
+export const fullPipelinesResponse = {
+ data: {
+ count: {
+ all: 2,
+ },
+ pipelines: [
+ {
+ id: '51',
+ commit: {
+ id: 'xxxxxxxxxxxxxxxxxxxx',
+ },
+ details: {
+ status: {
+ icon: 'status_failed',
+ text: 'failed',
+ },
+ },
+ },
+ {
+ id: '50',
+ commit: {
+ id: 'abc123def456ghi789jkl',
+ },
+ details: {
+ status: {
+ icon: 'status_passed',
+ text: 'passed',
+ },
+ },
+ },
+ ],
+ },
+};
diff --git a/spec/javascripts/ide/stores/actions/project_spec.js b/spec/javascripts/ide/stores/actions/project_spec.js
index ebd08d95810..8e078ae7138 100644
--- a/spec/javascripts/ide/stores/actions/project_spec.js
+++ b/spec/javascripts/ide/stores/actions/project_spec.js
@@ -1,14 +1,33 @@
-import {
- refreshLastCommitData,
-} from '~/ide/stores/actions';
+import Visibility from 'visibilityjs';
+import MockAdapter from 'axios-mock-adapter';
+import { refreshLastCommitData, pollSuccessCallBack } from '~/ide/stores/actions';
import store from '~/ide/stores';
import service from '~/ide/services';
+import axios from '~/lib/utils/axios_utils';
+import { fullPipelinesResponse } from '../../mock_data';
import { resetStore } from '../../helpers';
import testAction from '../../../helpers/vuex_action_helper';
describe('IDE store project actions', () => {
+ const setProjectState = () => {
+ store.state.currentProjectId = 'abc/def';
+ store.state.currentBranchId = 'master';
+ store.state.projects['abc/def'] = {
+ id: 4,
+ path_with_namespace: 'abc/def',
+ branches: {
+ master: {
+ commit: {
+ id: 'abc123def456ghi789jkl',
+ title: 'example',
+ },
+ },
+ },
+ };
+ };
+
beforeEach(() => {
- store.state.projects.abcproject = {};
+ store.state.projects['abc/def'] = {};
});
afterEach(() => {
@@ -17,18 +36,16 @@ describe('IDE store project actions', () => {
describe('refreshLastCommitData', () => {
beforeEach(() => {
- store.state.currentProjectId = 'abcproject';
+ store.state.currentProjectId = 'abc/def';
store.state.currentBranchId = 'master';
- store.state.projects.abcproject = {
+ store.state.projects['abc/def'] = {
+ id: 4,
branches: {
master: {
commit: null,
},
},
};
- });
-
- it('calls the service', done => {
spyOn(service, 'getBranchData').and.returnValue(
Promise.resolve({
data: {
@@ -36,14 +53,16 @@ describe('IDE store project actions', () => {
},
}),
);
+ });
+ it('calls the service', done => {
store
.dispatch('refreshLastCommitData', {
projectId: store.state.currentProjectId,
branchId: store.state.currentBranchId,
})
.then(() => {
- expect(service.getBranchData).toHaveBeenCalledWith('abcproject', 'master');
+ expect(service.getBranchData).toHaveBeenCalledWith('abc/def', 'master');
done();
})
@@ -53,16 +72,118 @@ describe('IDE store project actions', () => {
it('commits getBranchData', done => {
testAction(
refreshLastCommitData,
- {},
- {},
- [{
- type: 'SET_BRANCH_COMMIT',
- payload: {
- projectId: 'abcproject',
- branchId: 'master',
- commit: { id: '123' },
+ {
+ projectId: store.state.currentProjectId,
+ branchId: store.state.currentBranchId,
+ },
+ store.state,
+ [
+ {
+ type: 'SET_BRANCH_COMMIT',
+ payload: {
+ projectId: 'abc/def',
+ branchId: 'master',
+ commit: { id: '123' },
+ },
+ },
+ ], // mutations
+ [
+ {
+ type: 'getLastCommitPipeline',
+ payload: {
+ projectId: 'abc/def',
+ projectIdNumber: store.state.projects['abc/def'].id,
+ branchId: 'master',
+ },
+ },
+ ], // action
+ done,
+ );
+ });
+ });
+
+ describe('pipelinePoll', () => {
+ let mock;
+
+ beforeEach(() => {
+ setProjectState();
+ jasmine.clock().install();
+ mock = new MockAdapter(axios);
+ mock
+ .onGet('/abc/def/commit/abc123def456ghi789jkl/pipelines')
+ .reply(200, { data: { foo: 'bar' } }, { 'poll-interval': '10000' });
+ });
+
+ afterEach(() => {
+ jasmine.clock().uninstall();
+ mock.restore();
+ store.dispatch('stopPipelinePolling');
+ });
+
+ it('calls service periodically', done => {
+ spyOn(axios, 'get').and.callThrough();
+ spyOn(Visibility, 'hidden').and.returnValue(false);
+
+ store
+ .dispatch('pipelinePoll')
+ .then(() => {
+ jasmine.clock().tick(1000);
+
+ expect(axios.get).toHaveBeenCalled();
+ expect(axios.get.calls.count()).toBe(1);
+ })
+ .then(() => new Promise(resolve => requestAnimationFrame(resolve)))
+ .then(() => {
+ jasmine.clock().tick(10000);
+ expect(axios.get.calls.count()).toBe(2);
+ })
+ .then(() => new Promise(resolve => requestAnimationFrame(resolve)))
+ .then(() => {
+ jasmine.clock().tick(10000);
+ expect(axios.get.calls.count()).toBe(3);
+ })
+ .then(() => new Promise(resolve => requestAnimationFrame(resolve)))
+ .then(() => {
+ jasmine.clock().tick(10000);
+ expect(axios.get.calls.count()).toBe(4);
+ })
+
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
+ describe('pollSuccessCallBack', () => {
+ beforeEach(() => {
+ setProjectState();
+ });
+
+ it('commits correct pipeline', done => {
+ testAction(
+ pollSuccessCallBack,
+ fullPipelinesResponse,
+ store.state,
+ [
+ {
+ type: 'SET_LAST_COMMIT_PIPELINE',
+ payload: {
+ projectId: 'abc/def',
+ branchId: 'master',
+ pipeline: {
+ id: '50',
+ commit: {
+ id: 'abc123def456ghi789jkl',
+ },
+ details: {
+ status: {
+ icon: 'status_passed',
+ text: 'passed',
+ },
+ },
+ },
+ },
},
- }], // mutations
+ ], // mutations
[], // action
done,
);
diff --git a/spec/javascripts/ide/stores/mutations/branch_spec.js b/spec/javascripts/ide/stores/mutations/branch_spec.js
index 29eb859ddaf..f2f1f2a9a2e 100644
--- a/spec/javascripts/ide/stores/mutations/branch_spec.js
+++ b/spec/javascripts/ide/stores/mutations/branch_spec.js
@@ -37,4 +37,40 @@ describe('Multi-file store branch mutations', () => {
expect(localState.projects.Example.branches.master.commit.title).toBe('Example commit');
});
});
+
+ describe('SET_LAST_COMMIT_PIPELINE', () => {
+ it('sets the pipeline for the last commit on current project', () => {
+ localState.projects = {
+ Example: {
+ branches: {
+ master: {
+ commit: {},
+ },
+ },
+ },
+ };
+
+ mutations.SET_LAST_COMMIT_PIPELINE(localState, {
+ projectId: 'Example',
+ branchId: 'master',
+ pipeline: {
+ id: '50',
+ details: {
+ status: {
+ icon: 'status_passed',
+ text: 'passed',
+ },
+ },
+ },
+ });
+
+ expect(localState.projects.Example.branches.master.commit.pipeline.id).toBe('50');
+ expect(localState.projects.Example.branches.master.commit.pipeline.details.status.text).toBe(
+ 'passed',
+ );
+ expect(localState.projects.Example.branches.master.commit.pipeline.details.status.icon).toBe(
+ 'status_passed',
+ );
+ });
+ });
});
diff --git a/spec/javascripts/pipelines/empty_state_spec.js b/spec/javascripts/pipelines/empty_state_spec.js
index 71f77e5f42e..1e41a7bfe7c 100644
--- a/spec/javascripts/pipelines/empty_state_spec.js
+++ b/spec/javascripts/pipelines/empty_state_spec.js
@@ -29,7 +29,7 @@ describe('Pipelines Empty State', () => {
expect(
component.$el.querySelector('p').innerHTML.trim().replace(/\n+\s+/m, ' ').replace(/\s\s+/g, ' '),
- ).toContain('Continous Integration can help catch bugs by running your tests automatically,');
+ ).toContain('Continuous Integration can help catch bugs by running your tests automatically,');
expect(
component.$el.querySelector('p').innerHTML.trim().replace(/\n+\s+/m, ' ').replace(/\s\s+/g, ' '),
diff --git a/spec/javascripts/pipelines/mock_data.js b/spec/javascripts/pipelines/mock_data.js
index a5a200973d7..03ead6cd8ba 100644
--- a/spec/javascripts/pipelines/mock_data.js
+++ b/spec/javascripts/pipelines/mock_data.js
@@ -217,7 +217,7 @@ export const pipelineWithStages = {
browse_path: '/gitlab-org/gitlab-ee/-/jobs/62411442/artifacts/browse',
},
{
- name: 'codequality',
+ name: 'code_quality',
expired: false,
expire_at: '2018-04-18T14:16:24.484Z',
path: '/gitlab-org/gitlab-ee/-/jobs/62411441/artifacts/download',
diff --git a/spec/lib/backup/repository_spec.rb b/spec/lib/backup/repository_spec.rb
index 20ea981ec47..a44243ac82d 100644
--- a/spec/lib/backup/repository_spec.rb
+++ b/spec/lib/backup/repository_spec.rb
@@ -48,14 +48,14 @@ describe Backup::Repository do
describe 'command failure' do
before do
- allow(Gitlab::Popen).to receive(:popen).and_return(['error', 1])
+ allow_any_instance_of(Gitlab::Shell).to receive(:create_repository).and_return(false)
end
context 'hashed storage' do
it 'shows the appropriate error' do
subject.restore
- expect(progress).to have_received(:puts).with("Ignoring error on #{project.full_path} (#{project.disk_path}) - error")
+ expect(progress).to have_received(:puts).with("[Failed] restoring #{project.full_path} repository")
end
end
@@ -65,33 +65,10 @@ describe Backup::Repository do
it 'shows the appropriate error' do
subject.restore
- expect(progress).to have_received(:puts).with("Ignoring error on #{project.full_path} - error")
+ expect(progress).to have_received(:puts).with("[Failed] restoring #{project.full_path} repository")
end
end
end
-
- describe 'folders without permissions' do
- before do
- allow(FileUtils).to receive(:mv).and_raise(Errno::EACCES)
- end
-
- it 'shows error message' do
- expect(subject).to receive(:access_denied_error)
- subject.restore
- end
- end
-
- describe 'folder that is a mountpoint' do
- before do
- allow(FileUtils).to receive(:mv).and_raise(Errno::EBUSY)
- end
-
- it 'shows error message' do
- expect(subject).to receive(:resource_busy_error).and_call_original
-
- expect { subject.restore }.to raise_error(/is a mountpoint/)
- end
- end
end
describe '#empty_repo?' do
diff --git a/spec/lib/gitlab_spec.rb b/spec/lib/gitlab_spec.rb
index da146e24893..d63f448883b 100644
--- a/spec/lib/gitlab_spec.rb
+++ b/spec/lib/gitlab_spec.rb
@@ -8,6 +8,66 @@ describe Gitlab do
expect(described_class.root).to eq(Pathname.new(File.expand_path('../..', __dir__)))
end
end
+ describe '.revision' do
+ let(:cmd) { %W[#{described_class.config.git.bin_path} log --pretty=format:%h -n 1] }
+
+ around do |example|
+ described_class.instance_variable_set(:@_revision, nil)
+ example.run
+ described_class.instance_variable_set(:@_revision, nil)
+ end
+
+ context 'when a REVISION file exists' do
+ before do
+ expect(File).to receive(:exist?)
+ .with(described_class.root.join('REVISION'))
+ .and_return(true)
+ end
+
+ it 'returns the actual Git revision' do
+ expect(File).to receive(:read)
+ .with(described_class.root.join('REVISION'))
+ .and_return("abc123\n")
+
+ expect(described_class.revision).to eq('abc123')
+ end
+
+ it 'memoizes the revision' do
+ expect(File).to receive(:read)
+ .once
+ .with(described_class.root.join('REVISION'))
+ .and_return("abc123\n")
+
+ 2.times { described_class.revision }
+ end
+ end
+
+ context 'when no REVISION file exist' do
+ context 'when the Git command succeeds' do
+ before do
+ expect(Gitlab::Popen).to receive(:popen_with_detail)
+ .with(cmd)
+ .and_return(Gitlab::Popen::Result.new(cmd, 'abc123', '', double(success?: true)))
+ end
+
+ it 'returns the actual Git revision' do
+ expect(described_class.revision).to eq('abc123')
+ end
+ end
+
+ context 'when the Git command fails' do
+ before do
+ expect(Gitlab::Popen).to receive(:popen_with_detail)
+ .with(cmd)
+ .and_return(Gitlab::Popen::Result.new(cmd, '', 'fatal: Not a git repository', double('Process::Status', success?: false)))
+ end
+
+ it 'returns "Unknown"' do
+ expect(described_class.revision).to eq('Unknown')
+ end
+ end
+ end
+ end
describe '.com?' do
it 'is true when on GitLab.com' do
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index 96173889ccd..77179028ede 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -1546,7 +1546,7 @@ describe Ci::Build do
{ key: 'GITLAB_FEATURES', value: project.licensed_features.join(','), public: true },
{ key: 'CI_SERVER_NAME', value: 'GitLab', public: true },
{ key: 'CI_SERVER_VERSION', value: Gitlab::VERSION, public: true },
- { key: 'CI_SERVER_REVISION', value: Gitlab::REVISION, public: true },
+ { key: 'CI_SERVER_REVISION', value: Gitlab.revision, public: true },
{ key: 'CI_JOB_NAME', value: 'test', public: true },
{ key: 'CI_JOB_STAGE', value: 'test', public: true },
{ key: 'CI_COMMIT_SHA', value: build.sha, public: true },
diff --git a/spec/requests/api/version_spec.rb b/spec/requests/api/version_spec.rb
index 7bbf34422b8..38b618191fb 100644
--- a/spec/requests/api/version_spec.rb
+++ b/spec/requests/api/version_spec.rb
@@ -18,7 +18,7 @@ describe API::Version do
expect(response).to have_gitlab_http_status(200)
expect(json_response['version']).to eq(Gitlab::VERSION)
- expect(json_response['revision']).to eq(Gitlab::REVISION)
+ expect(json_response['revision']).to eq(Gitlab.revision)
end
end
end
diff --git a/spec/services/clusters/applications/schedule_installation_service_spec.rb b/spec/services/clusters/applications/schedule_installation_service_spec.rb
index 473dbcbb692..bca1e71bef2 100644
--- a/spec/services/clusters/applications/schedule_installation_service_spec.rb
+++ b/spec/services/clusters/applications/schedule_installation_service_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Clusters::Applications::ScheduleInstallationService do
def count_scheduled
- application_class&.with_status(:scheduled)&.count || 0
+ application&.class&.with_status(:scheduled)&.count || 0
end
shared_examples 'a failing service' do
@@ -10,45 +10,42 @@ describe Clusters::Applications::ScheduleInstallationService do
expect(ClusterInstallAppWorker).not_to receive(:perform_async)
count_before = count_scheduled
- expect { service.execute }.to raise_error(StandardError)
+ expect { service.execute(application) }.to raise_error(StandardError)
expect(count_scheduled).to eq(count_before)
end
end
describe '#execute' do
- let(:application_class) { Clusters::Applications::Helm }
- let(:cluster) { create(:cluster, :project, :provided_by_gcp) }
- let(:project) { cluster.project }
- let(:service) { described_class.new(project, nil, cluster: cluster, application_class: application_class) }
+ let(:project) { double(:project) }
+ let(:service) { described_class.new(project, nil) }
- it 'creates a new application' do
- allow(ClusterInstallAppWorker).to receive(:perform_async)
+ context 'when application is installable' do
+ let(:application) { create(:clusters_applications_helm, :installable) }
- expect { service.execute }.to change { application_class.count }.by(1)
- end
-
- it 'make the application scheduled' do
- expect(ClusterInstallAppWorker).to receive(:perform_async).with(application_class.application_name, kind_of(Numeric)).once
+ it 'make the application scheduled' do
+ expect(ClusterInstallAppWorker).to receive(:perform_async).with(application.name, kind_of(Numeric)).once
- expect { service.execute }.to change { application_class.with_status(:scheduled).count }.by(1)
+ expect { service.execute(application) }.to change { application.class.with_status(:scheduled).count }.by(1)
+ end
end
context 'when installation is already in progress' do
let(:application) { create(:clusters_applications_helm, :installing) }
- let(:cluster) { application.cluster }
it_behaves_like 'a failing service'
end
- context 'when application_class is nil' do
- let(:application_class) { nil }
+ context 'when application is nil' do
+ let(:application) { nil }
it_behaves_like 'a failing service'
end
context 'when application cannot be persisted' do
+ let(:application) { create(:clusters_applications_helm) }
+
before do
- expect_any_instance_of(application_class).to receive(:make_scheduled!).once.and_raise(ActiveRecord::RecordInvalid)
+ expect(application).to receive(:make_scheduled!).once.and_raise(ActiveRecord::RecordInvalid)
end
it_behaves_like 'a failing service'
diff --git a/spec/services/projects/open_issues_count_service_spec.rb b/spec/services/projects/open_issues_count_service_spec.rb
index f964f9972cd..06b470849b3 100644
--- a/spec/services/projects/open_issues_count_service_spec.rb
+++ b/spec/services/projects/open_issues_count_service_spec.rb
@@ -2,20 +2,53 @@ require 'spec_helper'
describe Projects::OpenIssuesCountService do
describe '#count' do
- it 'returns the number of open issues' do
- project = create(:project)
- create(:issue, :opened, project: project)
+ let(:project) { create(:project) }
- expect(described_class.new(project).count).to eq(1)
+ context 'when user is nil' do
+ it 'does not include confidential issues in the issue count' do
+ create(:issue, :opened, project: project)
+ create(:issue, :opened, confidential: true, project: project)
+
+ expect(described_class.new(project).count).to eq(1)
+ end
end
- it 'does not include confidential issues in the issue count' do
- project = create(:project)
+ context 'when user is provided' do
+ let(:user) { create(:user) }
+
+ context 'when user can read confidential issues' do
+ before do
+ project.add_reporter(user)
+ end
+
+ it 'returns the right count with confidential issues' do
+ create(:issue, :opened, project: project)
+ create(:issue, :opened, confidential: true, project: project)
+
+ expect(described_class.new(project, user).count).to eq(2)
+ end
+
+ it 'uses total_open_issues_count cache key' do
+ expect(described_class.new(project, user).cache_key_name).to eq('total_open_issues_count')
+ end
+ end
+
+ context 'when user cannot read confidential issues' do
+ before do
+ project.add_guest(user)
+ end
+
+ it 'does not include confidential issues' do
+ create(:issue, :opened, project: project)
+ create(:issue, :opened, confidential: true, project: project)
- create(:issue, :opened, project: project)
- create(:issue, :opened, confidential: true, project: project)
+ expect(described_class.new(project, user).count).to eq(1)
+ end
- expect(described_class.new(project).count).to eq(1)
+ it 'uses public_open_issues_count cache key' do
+ expect(described_class.new(project, user).cache_key_name).to eq('public_open_issues_count')
+ end
+ end
end
end
end
diff --git a/spec/views/admin/dashboard/index.html.haml_spec.rb b/spec/views/admin/dashboard/index.html.haml_spec.rb
index 099baacf019..59c777ea338 100644
--- a/spec/views/admin/dashboard/index.html.haml_spec.rb
+++ b/spec/views/admin/dashboard/index.html.haml_spec.rb
@@ -22,6 +22,6 @@ describe 'admin/dashboard/index.html.haml' do
it "includes revision of GitLab" do
render
- expect(rendered).to have_content "#{Gitlab::VERSION} (#{Gitlab::REVISION})"
+ expect(rendered).to have_content "#{Gitlab::VERSION} (#{Gitlab.revision})"
end
end
diff --git a/spec/views/help/index.html.haml_spec.rb b/spec/views/help/index.html.haml_spec.rb
index 0a78606171d..836d452304c 100644
--- a/spec/views/help/index.html.haml_spec.rb
+++ b/spec/views/help/index.html.haml_spec.rb
@@ -39,7 +39,7 @@ describe 'help/index' do
def stub_version(version, revision)
stub_const('Gitlab::VERSION', version)
- stub_const('Gitlab::REVISION', revision)
+ allow(Gitlab).to receive(:revision).and_return(revision)
end
def stub_helpers
diff --git a/spec/workers/update_merge_requests_worker_spec.rb b/spec/workers/update_merge_requests_worker_spec.rb
index 0fa19ac84bb..80137815d2b 100644
--- a/spec/workers/update_merge_requests_worker_spec.rb
+++ b/spec/workers/update_merge_requests_worker_spec.rb
@@ -18,8 +18,13 @@ describe UpdateMergeRequestsWorker do
end
it 'executes MergeRequests::RefreshService with expected values' do
- expect(MergeRequests::RefreshService).to receive(:new).with(project, user).and_call_original
- expect_any_instance_of(MergeRequests::RefreshService).to receive(:execute).with(oldrev, newrev, ref)
+ expect(MergeRequests::RefreshService).to receive(:new)
+ .with(project, user).and_wrap_original do |method, *args|
+ method.call(*args).tap do |refresh_service|
+ expect(refresh_service)
+ .to receive(:execute).with(oldrev, newrev, ref)
+ end
+ end
perform
end
diff --git a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml
index 45cb43ae8ef..589ebcf1414 100644
--- a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml
+++ b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml
@@ -77,7 +77,7 @@ test:
only:
- branches
-codequality:
+code_quality:
image: docker:stable
variables:
DOCKER_DRIVER: overlay2
@@ -86,9 +86,9 @@ codequality:
- docker:stable-dind
script:
- setup_docker
- - codeclimate
+ - code_quality
artifacts:
- paths: [codeclimate.json]
+ paths: [gl-code-quality-report.json]
performance:
stage: performance
@@ -409,7 +409,7 @@ rollout 100%:
./clair-scanner -c http://docker:6060 --ip $(hostname -i) -r gl-container-scanning-report.json -l clair.log -w clair-whitelist.yml ${CI_APPLICATION_REPOSITORY}:${CI_APPLICATION_TAG} || true
}
- function codeclimate() {
+ function code_quality() {
docker run --env SOURCE_CODE="$PWD" \
--volume "$PWD":/code \
--volume /var/run/docker.sock:/var/run/docker.sock \
diff --git a/yarn.lock b/yarn.lock
index e0d46609f7d..bbc4672f84b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -54,9 +54,9 @@
lodash "^4.2.0"
to-fast-properties "^2.0.0"
-"@gitlab-org/gitlab-svgs@^1.22.0":
- version "1.22.0"
- resolved "https://registry.yarnpkg.com/@gitlab-org/gitlab-svgs/-/gitlab-svgs-1.22.0.tgz#9f2daefebcda911cba8341313c8c464c8087fe44"
+"@gitlab-org/gitlab-svgs@^1.23.0":
+ version "1.23.0"
+ resolved "https://registry.yarnpkg.com/@gitlab-org/gitlab-svgs/-/gitlab-svgs-1.23.0.tgz#42047aeedcc06bc12d417ed1efadad1749af9670"
"@mrmlnc/readdir-enhanced@^2.2.1":
version "2.2.1"