diff options
17 files changed, 333 insertions, 18 deletions
diff --git a/app/models/concerns/has_status.rb b/app/models/concerns/has_status.rb index dff7b6e3523..3c9c6584e02 100644 --- a/app/models/concerns/has_status.rb +++ b/app/models/concerns/has_status.rb @@ -82,7 +82,7 @@ module HasStatus scope :failed_or_canceled, -> { where(status: [:failed, :canceled]) } scope :cancelable, -> do - where(status: [:running, :pending, :created, :manual]) + where(status: [:running, :pending, :created]) end end diff --git a/changelogs/unreleased/fix-gb-exclude-manual-actions-from-cancelable-jobs.yml b/changelogs/unreleased/fix-gb-exclude-manual-actions-from-cancelable-jobs.yml new file mode 100644 index 00000000000..a16fc775b5e --- /dev/null +++ b/changelogs/unreleased/fix-gb-exclude-manual-actions-from-cancelable-jobs.yml @@ -0,0 +1,4 @@ +--- +title: Exclude manual actions when checking if pipeline can be canceled +merge_request: 11562 +author: diff --git a/db/post_migrate/20170518200835_rename_users_with_renamed_namespace.rb b/db/post_migrate/20170518200835_rename_users_with_renamed_namespace.rb new file mode 100644 index 00000000000..da0fcda87a6 --- /dev/null +++ b/db/post_migrate/20170518200835_rename_users_with_renamed_namespace.rb @@ -0,0 +1,50 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class RenameUsersWithRenamedNamespace < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + DISALLOWED_ROOT_PATHS = %w[ + abuse_reports + api + autocomplete + explore + health_check + import + invites + jwt + koding + member + notification_settings + oauth + sent_notifications + unicorn_test + uploads + users + ] + + def up + DISALLOWED_ROOT_PATHS.each do |path| + users = Arel::Table.new(:users) + namespaces = Arel::Table.new(:namespaces) + predicate = namespaces[:owner_id].eq(users[:id]) + .and(namespaces[:type].eq(nil)) + .and(users[:username].matches(path)) + update_sql = if Gitlab::Database.postgresql? + "UPDATE users SET username = namespaces.path "\ + "FROM namespaces WHERE #{predicate.to_sql}" + else + "UPDATE users INNER JOIN namespaces "\ + "ON namespaces.owner_id = users.id "\ + "SET username = namespaces.path "\ + "WHERE #{predicate.to_sql}" + end + + connection.execute(update_sql) + end + end + + def down + end +end diff --git a/db/post_migrate/20170518231126_fix_wrongly_renamed_routes.rb b/db/post_migrate/20170518231126_fix_wrongly_renamed_routes.rb new file mode 100644 index 00000000000..c78beda9d21 --- /dev/null +++ b/db/post_migrate/20170518231126_fix_wrongly_renamed_routes.rb @@ -0,0 +1,104 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class FixWronglyRenamedRoutes < ActiveRecord::Migration + include Gitlab::Database::RenameReservedPathsMigration::V1 + + DOWNTIME = false + + disable_ddl_transaction! + + DISALLOWED_ROOT_PATHS = %w[ + - + abuse_reports + api + autocomplete + explore + health_check + import + invites + jwt + koding + member + notification_settings + oauth + sent_notifications + unicorn_test + uploads + users + ] + + FIXED_PATHS = DISALLOWED_ROOT_PATHS.map { |p| "#{p}0" } + + class Route < Gitlab::Database::RenameReservedPathsMigration::V1::MigrationClasses::Route + self.table_name = 'routes' + end + + def routes + @routes ||= Route.arel_table + end + + def namespaces + @namespaces ||= Arel::Table.new(:namespaces) + end + + def wildcard_collection(collection) + collection.map { |word| "#{word}%" } + end + + # The routes that got incorrectly renamed before, still have a namespace that + # contains the correct path. + # This query fetches all rows from the `routes` table that meet the following + # conditions using `api` as an example: + # - route.path ILIKE `api0%` + # - route.source_type = `Namespace` + # - namespace.parent_id IS NULL + # - namespace.path ILIKE `api%` + # - NOT(namespace.path ILIKE `api0%`) + # This gives us all root-routes, that were renamed, but their namespace was not. + # + def wrongly_renamed + Route.joins("INNER JOIN namespaces ON routes.source_id = namespaces.id") + .where( + routes[:source_type].eq('Namespace') + .and(namespaces[:parent_id].eq(nil)) + ) + .where(namespaces[:path].matches_any(wildcard_collection(DISALLOWED_ROOT_PATHS))) + .where.not(namespaces[:path].matches_any(wildcard_collection(FIXED_PATHS))) + .where(routes[:path].matches_any(wildcard_collection(FIXED_PATHS))) + end + + # Using the query above, we just fetch the `route.path` & the `namespace.path` + # `route.path` is the part of the route that is now incorrect + # `namespace.path` is what it should be + # We can use `route.path` to find all the namespaces that need to be fixed + # And we can use `namespace.path` to apply the correct name. + # + def paths_and_corrections + connection.select_all( + wrongly_renamed.select(routes[:path], namespaces[:path].as('namespace_path')).to_sql + ) + end + + # This can be used to limit the `update_in_batches` call to all routes for a + # single namespace, note the `/` that's what went wrong in the initial migration. + # + def routes_in_namespace_query(namespace) + routes[:path].matches_any([namespace, "#{namespace}/%"]) + end + + def up + paths_and_corrections.each do |root_namespace| + wrong_path = root_namespace['path'] + correct_path = root_namespace['namespace_path'] + replace_statement = replace_sql(Route.arel_table[:path], wrong_path, correct_path) + + update_column_in_batches(:routes, :path, replace_statement) do |table, query| + query.where(routes_in_namespace_query(wrong_path)) + end + end + end + + def down + end +end diff --git a/db/schema.rb b/db/schema.rb index 294e0b531eb..d14126401c9 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170516183131) do +ActiveRecord::Schema.define(version: 20170518231126) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" diff --git a/doc/user/img/gitlab_snippet.png b/doc/user/img/gitlab_snippet.png Binary files differnew file mode 100644 index 00000000000..718347fc2d4 --- /dev/null +++ b/doc/user/img/gitlab_snippet.png diff --git a/doc/user/project/issues/img/create_new_merge_request.png b/doc/user/project/issues/img/create_new_merge_request.png Binary files differdeleted file mode 100644 index d4bfb6fa463..00000000000 --- a/doc/user/project/issues/img/create_new_merge_request.png +++ /dev/null diff --git a/doc/user/project/issues/img/issues_main_view.png b/doc/user/project/issues/img/issues_main_view.png Binary files differindex e9a94a3aab0..4faa42e40ee 100755..100644 --- a/doc/user/project/issues/img/issues_main_view.png +++ b/doc/user/project/issues/img/issues_main_view.png diff --git a/doc/user/project/issues/img/issues_main_view_numbered.jpg b/doc/user/project/issues/img/issues_main_view_numbered.jpg Binary files differnew file mode 100644 index 00000000000..4b5d7fba459 --- /dev/null +++ b/doc/user/project/issues/img/issues_main_view_numbered.jpg diff --git a/doc/user/project/issues/img/issues_main_view_numbered.png b/doc/user/project/issues/img/issues_main_view_numbered.png Binary files differdeleted file mode 100755 index 9cff61d7041..00000000000 --- a/doc/user/project/issues/img/issues_main_view_numbered.png +++ /dev/null diff --git a/doc/user/project/issues/index.md b/doc/user/project/issues/index.md index c726da17259..9598cb801be 100644 --- a/doc/user/project/issues/index.md +++ b/doc/user/project/issues/index.md @@ -49,6 +49,10 @@ Read through the [documentation on creating issues](create_new_issue.md). Read through the distinct ways to [close issues](closing_issues.md) on GitLab. +## Create a merge request from an issue + +Learn more about it on the [GitLab Issues Functionalities documentation](issues_functionalities.md#18-new-merge-request). + ## Search for an issue Learn how to [find an issue](../../search/index.md) by searching for and filtering them. diff --git a/doc/user/project/issues/issues_functionalities.md b/doc/user/project/issues/issues_functionalities.md index e1923e91042..ba843201e1a 100644 --- a/doc/user/project/issues/issues_functionalities.md +++ b/doc/user/project/issues/issues_functionalities.md @@ -6,7 +6,7 @@ Please read through the [GitLab Issue Documentation](index.md) for an overview o The image bellow illustrates how an issue looks like: -![Issue view](img/issues_main_view_numbered.png) +![Issue view](img/issues_main_view_numbered.jpg) You can find all the information on that issue on one screen. @@ -41,6 +41,21 @@ it's reassigned to someone else to take it from there. if a user is not member of that project, it can only be assigned to them if they created the issue themselves. +##### 3.1. Multiple Assignees (EES/EEP) + +Issue Weights are only available in [GitLab Enterprise Edition](https://about.gitlab.com/gitlab-ee/). + +Often multiple people likely work on the same issue together, +which can especially be difficult to track in large teams +where there is shared ownership of an issue. + +In GitLab Enterprise Edition, you can also select multiple assignees +to an issue. + +> **Note:** +Multiple Assignees was [introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/1904) +in [GitLab Enterprise Edition 9.2](https://about.gitlab.com/2017/05/22/gitlab-9-2-released/#multiple-assignees-for-issues). + #### 4. Milestone - Select a [milestone](../milestones/index.md) to attribute that issue to. @@ -153,14 +168,9 @@ Once you wrote your comment, you can either: - Click "Start discussion": start a thread within that issue's thread to discuss specific points. - Click "Comment and close issue": post your comment and close that issue in one click. -#### 18. New branch - -- [New branch](../repository/web_editor.md#create-a-new-branch-from-an-issue): -create a new branch, followed by a new merge request which will automatically close that -issue as soon as that merge request is merged. - -#### 19. New merge request - -- Create a new merge request (with source branch) in one action. Optionally just create a new branch, as explained above. +#### 18. New Merge Request -![Create new merge request](img/create_new_merge_request.png) +- Create a new merge request (with a new source branch named after the issue) in one action. +The merge request will automatically close that issue as soon as merged. +- Optionally, you can just create a [new branch](../repository/web_editor.md#create-a-new-branch-from-an-issue) +named after that issue. diff --git a/doc/user/snippets.md b/doc/user/snippets.md index 417360e08ac..78861625f8a 100644 --- a/doc/user/snippets.md +++ b/doc/user/snippets.md @@ -2,8 +2,18 @@ Snippets are little bits of code or text. +![GitLab Snippet](img/gitlab_snippet.png) + There are 2 types of snippets - project snippets and personal snippets. +## Comments + +With GitLab Snippets you engage in a conversation about that piece of code, +facilitating the collaboration among users. + +> **Note:** +Comments on snippets was [introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/12910) in [GitLab Community Edition 9.2](https://about.gitlab.com/2017/05/22/gitlab-9-2-released/#comments-for-personal-snippets). + ## Project snippets Project snippets are always related to a specific project - see [Project features](../workflow/project_features.md) for more information. diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb index fb4a4721a58..c880da1e36a 100644 --- a/spec/controllers/projects/pipelines_controller_spec.rb +++ b/spec/controllers/projects/pipelines_controller_spec.rb @@ -38,7 +38,7 @@ describe Projects::PipelinesController do end describe 'GET show JSON' do - let!(:pipeline) { create(:ci_pipeline_with_one_job, project: project) } + let(:pipeline) { create(:ci_pipeline_with_one_job, project: project) } it 'returns the pipeline' do get_pipeline_json @@ -49,20 +49,48 @@ describe Projects::PipelinesController do expect(json_response['details']).to have_key 'stages' end - context 'when the pipeline has multiple jobs' do + context 'when the pipeline has multiple stages and groups' do + before do + RequestStore.begin! + + create_build('build', 0, 'build') + create_build('test', 1, 'rspec 0') + create_build('deploy', 2, 'production') + create_build('post deploy', 3, 'pages 0') + end + + after do + RequestStore.end! + RequestStore.clear! + end + + let(:project) { create(:project) } + let(:pipeline) do + create(:ci_empty_pipeline, project: project, user: user, sha: project.commit.id) + end + it 'does not perform N + 1 queries' do control_count = ActiveRecord::QueryRecorder.new { get_pipeline_json }.count - create(:ci_build, pipeline: pipeline) + create_build('test', 1, 'rspec 1') + create_build('test', 1, 'spinach 0') + create_build('test', 1, 'spinach 1') + create_build('test', 1, 'audit') + create_build('post deploy', 3, 'pages 1') + create_build('post deploy', 3, 'pages 2') - # The plus 2 is needed to group and sort - expect { get_pipeline_json }.not_to exceed_query_limit(control_count + 2) + new_count = ActiveRecord::QueryRecorder.new { get_pipeline_json }.count + expect(new_count).to be_within(12).of(control_count) end end def get_pipeline_json get :show, namespace_id: project.namespace, project_id: project, id: pipeline, format: :json end + + def create_build(stage, stage_idx, name) + create(:ci_build, pipeline: pipeline, stage: stage, stage_idx: stage_idx, name: name) + end end describe 'GET stages.json' do diff --git a/spec/migrations/fix_wrongly_renamed_routes_spec.rb b/spec/migrations/fix_wrongly_renamed_routes_spec.rb new file mode 100644 index 00000000000..148290b0e7d --- /dev/null +++ b/spec/migrations/fix_wrongly_renamed_routes_spec.rb @@ -0,0 +1,73 @@ +require 'spec_helper' +require Rails.root.join('db', 'post_migrate', '20170518231126_fix_wrongly_renamed_routes.rb') + +describe FixWronglyRenamedRoutes, truncate: true do + let(:subject) { described_class.new } + let(:broken_namespace) do + namespace = create(:group, name: 'apiis') + namespace.route.update_attribute(:path, 'api0is') + namespace + end + + describe '#wrongly_renamed' do + it "includes routes that have names that don't match their namespace" do + broken_namespace + _other_namespace = create(:group, name: 'api0') + + expect(subject.wrongly_renamed.map(&:id)) + .to contain_exactly(broken_namespace.route.id) + end + end + + describe "#paths_and_corrections" do + it 'finds the wrong path and gets the correction from the namespace' do + broken_namespace + namespace = create(:group, name: 'uploads-test') + namespace.route.update_attribute(:path, 'uploads0-test') + + expected_result = [ + { 'namespace_path' => 'apiis', 'path' => 'api0is' }, + { 'namespace_path' => 'uploads-test', 'path' => 'uploads0-test' } + ] + + expect(subject.paths_and_corrections).to include(*expected_result) + end + end + + describe '#routes_in_namespace_query' do + it 'includes only the required routes' do + namespace = create(:group, path: 'hello') + project = create(:empty_project, namespace: namespace) + _other_namespace = create(:group, path: 'hello0') + + result = Route.where(subject.routes_in_namespace_query('hello')) + + expect(result).to contain_exactly(namespace.route, project.route) + end + end + + describe '#up' do + let(:broken_project) do + project = create(:empty_project, namespace: broken_namespace, path: 'broken-project') + project.route.update_attribute(:path, 'api0is/broken-project') + project + end + + it 'renames incorrectly named routes' do + broken_project + + subject.up + + expect(broken_project.route.reload.path).to eq('apiis/broken-project') + expect(broken_namespace.route.reload.path).to eq('apiis') + end + + it "doesn't touch namespaces that look like something that should be renamed" do + namespace = create(:group, path: 'api0') + + subject.up + + expect(namespace.route.reload.path).to eq('api0') + end + end +end diff --git a/spec/migrations/rename_users_with_renamed_namespace_spec.rb b/spec/migrations/rename_users_with_renamed_namespace_spec.rb new file mode 100644 index 00000000000..1e9aab3d9a1 --- /dev/null +++ b/spec/migrations/rename_users_with_renamed_namespace_spec.rb @@ -0,0 +1,22 @@ +require 'spec_helper' +require Rails.root.join('db', 'post_migrate', '20170518200835_rename_users_with_renamed_namespace.rb') + +describe RenameUsersWithRenamedNamespace, truncate: true do + it 'renames a user that had their namespace renamed to the namespace path' do + other_user = create(:user, username: 'kodingu') + other_user1 = create(:user, username: 'api0') + + user = create(:user, username: "Users0") + user.update_attribute(:username, 'Users') + user1 = create(:user, username: "import0") + user1.update_attribute(:username, 'import') + + described_class.new.up + + expect(user.reload.username).to eq('Users0') + expect(user1.reload.username).to eq('import0') + + expect(other_user.reload.username).to eq('kodingu') + expect(other_user1.reload.username).to eq('api0') + end +end diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 157d17fbb68..56b24ce62f3 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -854,6 +854,16 @@ describe Ci::Pipeline, models: true do end end end + + context 'when there is a manual action present in the pipeline' do + before do + create(:ci_build, :manual, pipeline: pipeline) + end + + it 'is not cancelable' do + expect(pipeline).not_to be_cancelable + end + end end describe '#cancel_running' do |