diff options
29 files changed, 358 insertions, 81 deletions
diff --git a/app/controllers/projects/protected_branches_controller.rb b/app/controllers/projects/protected_branches_controller.rb index c5454883060..d4f7d0bc521 100644 --- a/app/controllers/projects/protected_branches_controller.rb +++ b/app/controllers/projects/protected_branches_controller.rb @@ -19,9 +19,13 @@ class Projects::ProtectedBranchesController < Projects::ProtectedRefsController [:merge_access_levels, :push_access_levels] end - def protected_ref_params - params.require(:protected_branch).permit(:name, - merge_access_levels_attributes: access_level_attributes, - push_access_levels_attributes: access_level_attributes) + def protected_ref_params(*attrs) + attrs = ([:name, + merge_access_levels_attributes: access_level_attributes, + push_access_levels_attributes: access_level_attributes] + attrs).uniq + + params.require(:protected_branch).permit(attrs) end end + +Projects::ProtectedBranchesController.prepend_if_ee('EE::Projects::ProtectedBranchesController') diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index b8beecf823c..abd19df9a3d 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -376,6 +376,7 @@ class ProjectsController < Projects::ApplicationController :tag_list, :visibility_level, :template_name, + :template_project_id, :merge_method, :initialize_with_readme, diff --git a/app/models/concerns/checksummable.rb b/app/models/concerns/checksummable.rb new file mode 100644 index 00000000000..1f76eb87aa5 --- /dev/null +++ b/app/models/concerns/checksummable.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module Checksummable + extend ActiveSupport::Concern + + class_methods do + def hexdigest(path) + Digest::SHA256.file(path).hexdigest + end + end +end diff --git a/app/models/lfs_object.rb b/app/models/lfs_object.rb index d31d6226559..535c3cf2ba1 100644 --- a/app/models/lfs_object.rb +++ b/app/models/lfs_object.rb @@ -2,6 +2,7 @@ class LfsObject < ApplicationRecord include AfterCommitQueue + include Checksummable include EachBatch include ObjectStorage::BackgroundMove @@ -46,7 +47,7 @@ class LfsObject < ApplicationRecord # rubocop: enable DestroyAll def self.calculate_oid(path) - Digest::SHA256.file(path).hexdigest + self.hexdigest(path) end end diff --git a/app/models/protected_branch.rb b/app/models/protected_branch.rb index 8769d3eb916..1857a59e01c 100644 --- a/app/models/protected_branch.rb +++ b/app/models/protected_branch.rb @@ -40,6 +40,11 @@ class ProtectedBranch < ApplicationRecord def self.protected_refs(project) project.protected_branches.select(:name) end + + def self.branch_requires_code_owner_approval?(project, branch_name) + # NOOP + # + end end ProtectedBranch.prepend_if_ee('EE::ProtectedBranch') diff --git a/app/models/upload.rb b/app/models/upload.rb index 384949ddb86..df8f9c56fa8 100644 --- a/app/models/upload.rb +++ b/app/models/upload.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true class Upload < ApplicationRecord + include Checksummable # Upper limit for foreground checksum processing CHECKSUM_THRESHOLD = 100.megabytes @@ -21,10 +22,6 @@ class Upload < ApplicationRecord # hooks are not executed and the file will not be deleted after_destroy :delete_file!, if: -> { uploader_class <= FileUploader } - def self.hexdigest(path) - Digest::SHA256.file(path).hexdigest - end - class << self ## # FastDestroyAll concerns @@ -55,7 +52,7 @@ class Upload < ApplicationRecord self.checksum = nil return unless needs_checksum? - self.checksum = Digest::SHA256.file(absolute_path).hexdigest + self.checksum = self.class.hexdigest(absolute_path) end # Initialize the associated Uploader class with current model diff --git a/app/services/projects/create_from_template_service.rb b/app/services/projects/create_from_template_service.rb index 91ece024e13..a207fd2c574 100644 --- a/app/services/projects/create_from_template_service.rb +++ b/app/services/projects/create_from_template_service.rb @@ -4,8 +4,11 @@ module Projects class CreateFromTemplateService < BaseService include Gitlab::Utils::StrongMemoize + attr_reader :template_name + def initialize(user, params) @current_user, @params = user, params.to_h.dup + @template_name = @params.delete(:template_name).presence end def execute @@ -21,12 +24,6 @@ module Projects file&.close end - def template_name - strong_memoize(:template_name) do - params.delete(:template_name).presence - end - end - private def validate_template! diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb index 728eb039b54..ef06545b27d 100644 --- a/app/services/projects/create_service.rb +++ b/app/services/projects/create_service.rb @@ -13,7 +13,7 @@ module Projects end def execute - if @params[:template_name].present? + if create_from_template? return ::Projects::CreateFromTemplateService.new(current_user, params).execute end @@ -184,6 +184,10 @@ module Projects private + def create_from_template? + @params[:template_name].present? || @params[:template_project_id].present? + end + def import_schedule if @project.errors.empty? @project.import_state.schedule if @project.import? && !@project.bare_repository_import? diff --git a/app/views/projects/protected_branches/shared/_branches_list.html.haml b/app/views/projects/protected_branches/shared/_branches_list.html.haml index 1913d06a6f8..ff8dae08ad0 100644 --- a/app/views/projects/protected_branches/shared/_branches_list.html.haml +++ b/app/views/projects/protected_branches/shared/_branches_list.html.haml @@ -1,9 +1,9 @@ .protected-branches-list.js-protected-branches-list.qa-protected-branches-list - if @protected_branches.empty? .card-header.bg-white - Protected branch (#{@protected_branches_count}) + = s_("ProtectedBranch|Protected branch (%{protected_branches_count})") % { protected_branches_count: @protected_branches_count } %p.settings-message.text-center - There are currently no protected branches, protect a branch with the form above. + = s_("ProtectedBranch|There are currently no protected branches, protect a branch with the form above.") - else %table.table.table-bordered %colgroup @@ -15,10 +15,17 @@ %col %thead %tr - %th Protected branch (#{@protected_branches_count}) - %th Last commit - %th Allowed to merge - %th Allowed to push + %th + = s_("ProtectedBranch|Protected branch (%{protected_branches_count})") % { protected_branches_count: @protected_branches_count } + %th + = s_("ProtectedBranch|Last commit") + %th + = s_("ProtectedBranch|Allowed to merge") + %th + = s_("ProtectedBranch|Allowed to push") + + = render_if_exists 'projects/protected_branches/ee/code_owner_approval_table_head' + - if can_admin_project %th %tbody diff --git a/app/views/projects/protected_branches/shared/_create_protected_branch.html.haml b/app/views/projects/protected_branches/shared/_create_protected_branch.html.haml index bba4949277d..f84c7b39733 100644 --- a/app/views/projects/protected_branches/shared/_create_protected_branch.html.haml +++ b/app/views/projects/protected_branches/shared/_create_protected_branch.html.haml @@ -2,7 +2,7 @@ %input{ type: 'hidden', name: 'update_section', value: 'js-protected-branches-settings' } .card .card-header - Protect a branch + = s_("ProtectedBranch|Protect a branch") .card-body = form_errors(@protected_branch) .form-group.row @@ -11,22 +11,19 @@ .col-md-10 = render partial: "projects/protected_branches/shared/dropdown", locals: { f: f } .form-text.text-muted - = link_to 'Wildcards', help_page_path('user/project/protected_branches', anchor: 'wildcard-protected-branches') - such as - %code *-stable - or - %code production/* - are supported + - wildcards_url = help_page_url('user/project/protected_branches', anchor: 'wildcard-protected-branches') + - wildcards_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: wildcards_url } + = (s_("ProtectedBranch|%{wildcards_link_start}Wildcards%{wildcards_link_end} such as %{code_tag_start}*-stable%{code_tag_end} or %{code_tag_start}production/*%{code_tag_end} are supported") % { wildcards_link_start: wildcards_link_start, wildcards_link_end: '</a>', code_tag_start: '<code>', code_tag_end: '</code>' }).html_safe .form-group.row %label.col-md-2.text-right{ for: 'merge_access_levels_attributes' } - Allowed to merge: + = s_("ProtectedBranch|Allowed to merge:") .col-md-10 = yield :merge_access_levels .form-group.row %label.col-md-2.text-right{ for: 'push_access_levels_attributes' } - Allowed to push: + = s_("ProtectedBranch|Allowed to push:") .col-md-10 = yield :push_access_levels - + = render_if_exists 'projects/protected_branches/ee/code_owner_approval_form' .card-footer - = f.submit 'Protect', class: 'btn-success btn', disabled: true, data: { qa_selector: 'protect_button' } + = f.submit s_('ProtectedBranch|Protect'), class: 'btn-success btn', disabled: true, data: { qa_selector: 'protect_button' } diff --git a/app/views/projects/protected_branches/shared/_protected_branch.html.haml b/app/views/projects/protected_branches/shared/_protected_branch.html.haml index 81dcab1d1ab..2768e4ac5a5 100644 --- a/app/views/projects/protected_branches/shared/_protected_branch.html.haml +++ b/app/views/projects/protected_branches/shared/_protected_branch.html.haml @@ -19,6 +19,8 @@ = yield + = render_if_exists 'projects/protected_branches/ee/code_owner_approval_table', protected_branch: protected_branch + - if can_admin_project %td = link_to 'Unprotect', [@project.namespace.becomes(Namespace), @project, protected_branch, { update_section: 'js-protected-branches-settings' }], disabled: local_assigns[:disabled], data: { confirm: 'Branch will be writable for developers. Are you sure?' }, method: :delete, class: "btn btn-warning" diff --git a/changelogs/unreleased/12764-refactor-checksum-code.yml b/changelogs/unreleased/12764-refactor-checksum-code.yml new file mode 100644 index 00000000000..b29d7bad5be --- /dev/null +++ b/changelogs/unreleased/12764-refactor-checksum-code.yml @@ -0,0 +1,5 @@ +--- +title: Refactor checksum code in uploads +merge_request: 18065 +author: briankabiro +type: other diff --git a/changelogs/unreleased/sh-use-template-project-id-backend.yml b/changelogs/unreleased/sh-use-template-project-id-backend.yml new file mode 100644 index 00000000000..00be1dcbd42 --- /dev/null +++ b/changelogs/unreleased/sh-use-template-project-id-backend.yml @@ -0,0 +1,5 @@ +--- +title: Add backend support for selecting custom templates by ID +merge_request: 18178 +author: +type: fixed diff --git a/db/post_migrate/20190827102026_migrate_code_owner_approval_status_to_protected_branches_in_batches.rb b/db/post_migrate/20190827102026_migrate_code_owner_approval_status_to_protected_branches_in_batches.rb new file mode 100644 index 00000000000..b109f582909 --- /dev/null +++ b/db/post_migrate/20190827102026_migrate_code_owner_approval_status_to_protected_branches_in_batches.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +class MigrateCodeOwnerApprovalStatusToProtectedBranchesInBatches < ActiveRecord::Migration[5.2] + include Gitlab::Database::MigrationHelpers + + disable_ddl_transaction! + + DOWNTIME = false + BATCH_SIZE = 200 + + class Project < ActiveRecord::Base + include EachBatch + + self.table_name = 'projects' + self.inheritance_column = :_type_disabled + + has_many :protected_branches + end + + class ProtectedBranch < ActiveRecord::Base + include EachBatch + + self.table_name = 'protected_branches' + self.inheritance_column = :_type_disabled + + belongs_to :project + end + + def up + add_concurrent_index :projects, :id, name: "temp_active_projects_with_prot_branches", where: 'archived = false and pending_delete = false and merge_requests_require_code_owner_approval = true' + + ProtectedBranch + .joins(:project) + .where(projects: { archived: false, pending_delete: false, merge_requests_require_code_owner_approval: true }) + .each_batch(of: BATCH_SIZE) do |batch| + batch.update_all(code_owner_approval_required: true) + end + + remove_concurrent_index_by_name(:projects, "temp_active_projects_with_prot_branches") + end + + def down + # noop + # + end +end diff --git a/doc/administration/auth/ldap-ee.md b/doc/administration/auth/ldap-ee.md index 924cc153b0c..e2894318fe5 100644 --- a/doc/administration/auth/ldap-ee.md +++ b/doc/administration/auth/ldap-ee.md @@ -281,7 +281,7 @@ sync to run once every 2 hours at the top of the hour. > Introduced in GitLab Enterprise Edition Starter 8.9. Using the `external_groups` setting will allow you to mark all users belonging -to these groups as [external users](../../user/permissions.md#external-users-permissions). +to these groups as [external users](../../user/permissions.md#external-users-core-only). Group membership is checked periodically through the `LdapGroupSync` background task. diff --git a/doc/api/protected_branches.md b/doc/api/protected_branches.md index debf1b264f9..4a750b42f65 100644 --- a/doc/api/protected_branches.md +++ b/doc/api/protected_branches.md @@ -296,3 +296,21 @@ curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" 'https://git | --------- | ---- | -------- | ----------- | | `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | | `name` | string | yes | The name of the branch | + +## Require code owner approvals for a single branch + +Update the "code owner approval required" option for the given protected branch protected branch. + +``` +PATCH /projects/:id/protected_branches/:name +``` + +```bash +curl --request PATCH --header "PRIVATE-TOKEN: <your_access_token>" 'https://gitlab.example.com/api/v4/projects/5/protected_branches/feature-branch' +``` + +| Attribute | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | +| `name` | string | yes | The name of the branch | +| `code_owner_approval_required` | boolean | no | **(PREMIUM)** Prevent pushes to this branch if it matches an item in the [`CODEOWNERS` file](../user/project/code_owners.md). (defaults: false)| diff --git a/doc/user/permissions.md b/doc/user/permissions.md index 196f2afcfe3..2bf7f24bbab 100644 --- a/doc/user/permissions.md +++ b/doc/user/permissions.md @@ -241,58 +241,83 @@ nested groups if you have membership in one of its parents. To learn more, read through the documentation on [subgroups memberships](group/subgroups/index.md#membership). -## Free Guest users **(ULTIMATE)** - -When a user is given `Guest` permissions on a project and/or group, and holds no -higher permission level on any other project or group on the instance, the user -is considered a guest user by GitLab and will not consume a license seat. -There is no other specific "guest" designation for newly created users. - -If the user is assigned a higher role on any projects or groups, the user will -take a license seat. If a user creates a project, the user becomes a `Maintainer` -on the project, resulting in the use of a license seat. - -To prevent a guest user from creating projects, you can edit the user profile to mark the user as -[External](#external-users-permissions). - -## External users permissions +## External users **(CORE ONLY)** In cases where it is desired that a user has access only to some internal or private projects, there is the option of creating **External Users**. This feature may be useful when for example a contractor is working on a given project and should only have access to that project. -External users can only access projects to which they are explicitly granted -access, thus hiding all other internal or private ones from them. Access can be -granted by adding the user as member to the project or group. +External users: + +- Cannot create groups or projects. +- Can only access projects to which they are explicitly granted access, + thus hiding all other internal or private ones from them (like being + logged out). +Access can be granted by adding the user as member to the project or group. They will, like usual users, receive a role in the project or group with all -the abilities that are mentioned in the table above. They cannot however create -groups or projects, and they have the same access as logged out users in all -other cases. +the abilities that are mentioned in the [permissions table above](#project-members-permissions). +For example, if an external user is added as Guest, and your project is +private, they will not have access to the code; you would need to grant the external +user access at the Reporter level or above if you want them to have access to the code. You should +always take into account the +[project's visibility and permissions settings](project/settings/index.md#sharing-and-permissions) +as well as the permission level of the user. -An administrator can flag a user as external [through the API](../api/users.md) -or by checking the checkbox on the admin panel. As an administrator, navigate -to **Admin > Users** to create a new user or edit an existing one. There, you -will find the option to flag the user as external. +NOTE: **Note:** +External users still count towards a license seat. + +An administrator can flag a user as external by either of the following methods: -By default new users are not set as external users. This behavior can be changed -by an administrator under **Admin > Application Settings**. +- Either [through the API](../api/users.md#user-modification). +- Or by navigating to the **Admin area > Overview > Users** to create a new user + or edit an existing one. There, you will find the option to flag the user as + external. -### Default internal users +### Setting new users to external -The "Internal users" field allows specifying an e-mail address regex pattern to identify default internal users. +By default, new users are not set as external users. This behavior can be changed +by an administrator under the **Admin Area > Settings > General > Account and limit** page. -New users whose email address matches the regex pattern will be set to internal by default rather than an external collaborator. +If you change the default behavior of creating new users as external, you will +have the option to narrow it down by defining a set of internal users. +The **Internal users** field allows specifying an email address regex pattern to +identify default internal users. New users whose email address matches the regex +pattern will be set to internal by default rather than an external collaborator. -The regex pattern format is Ruby, but it needs to be convertible to JavaScript, and the ignore case flag will be set, e.g. "/regex pattern/i". +The regex pattern format is Ruby, but it needs to be convertible to JavaScript, +and the ignore case flag will be set (`/regex pattern/i`). Here are some examples: -Here are some examples: +- Use `\.internal@domain\.com$` to mark email addresses ending with + `.internal@domain.com` as internal. +- Use `^(?:(?!\.ext@domain\.com).)*$\r?` to mark users with email addresses + NOT including `.ext@domain.com` as internal. -- Use `\.internal@domain\.com$` to mark email addresses ending with ".internal@domain.com" internal. -- Use `^(?:(?!\.ext@domain\.com).)*$\r?` to mark users with email addresses NOT including .ext@domain.com internal. +CAUTION: **Warning:** +Be aware that this regex could lead to a +[regular expression denial of service (ReDoS) attack](https://en.wikipedia.org/wiki/ReDoS). + +## Free Guest users **(ULTIMATE)** -Please be aware that this regex could lead to a DOS attack, [see](https://en.wikipedia.org/wiki/ReDoS?) ReDos on Wikipedia. +When a user is given Guest permissions on a project, group, or both, and holds no +higher permission level on any other project or group on the GitLab instance, +the user is considered a guest user by GitLab and will not consume a license seat. +There is no other specific "guest" designation for newly created users. + +If the user is assigned a higher role on any projects or groups, the user will +take a license seat. If a user creates a project, the user becomes a Maintainer +on the project, resulting in the use of a license seat. Also, note that if your +project is internal or private, Guest users will have all the abilities that are +mentioned in the [permissions table above](#project-members-permissions) (they +will not be able to browse the project's repository for example). + +TIP: **Tip:** +To prevent a guest user from creating projects, as an admin, you can edit the +user's profile to mark the user as [external](#external-users-core-only). +Beware though that even if a user is external, if they already have Reporter or +higher permissions in any project or group, they will **not** be counted as a +free guest user. ## Auditor users **(PREMIUM ONLY)** diff --git a/doc/user/project/img/protected_branches_list_v12_3.png b/doc/user/project/img/protected_branches_list_v12_3.png Binary files differindex 365d8d99e5a..2353ddd23be 100644 --- a/doc/user/project/img/protected_branches_list_v12_3.png +++ b/doc/user/project/img/protected_branches_list_v12_3.png diff --git a/doc/user/project/img/protected_branches_page_v12_3.png b/doc/user/project/img/protected_branches_page_v12_3.png Binary files differindex 17f19642552..9a194c85c41 100644 --- a/doc/user/project/img/protected_branches_page_v12_3.png +++ b/doc/user/project/img/protected_branches_page_v12_3.png diff --git a/doc/user/project/integrations/jira.md b/doc/user/project/integrations/jira.md index 8f5b7c3c421..6d2a0563ec1 100644 --- a/doc/user/project/integrations/jira.md +++ b/doc/user/project/integrations/jira.md @@ -21,7 +21,7 @@ Here's how the integration responds when you take the following actions in GitLa - GitLab hyperlinks to the Jira issue. - The Jira issue adds an issue link to the commit/MR in GitLab. - The Jira issue adds a comment reflecting the comment made in GitLab, the comment author, and a link to the commit/MR in GitLab. -- **Mention that a commit or MR 'closes', 'resolves', or 'fixes' a Jira issue ID**. When the commit is made on master or the change is merged to master: +- **Mention that a commit or MR 'closes', 'resolves', or 'fixes' a Jira issue ID**. When the commit is made on the project's default branch (usually master) or the change is merged to the default branch: - GitLab's merge request page displays a note that it "Closed" the Jira issue, with a link to the issue. (Note: Before the merge, an MR will display that it "Closes" the Jira issue.) - The Jira issue shows the activity and the Jira issue is closed, or otherwise transitioned. diff --git a/doc/user/project/new_ci_build_permissions_model.md b/doc/user/project/new_ci_build_permissions_model.md index 0e60c4eca75..5f3bb83df70 100644 --- a/doc/user/project/new_ci_build_permissions_model.md +++ b/doc/user/project/new_ci_build_permissions_model.md @@ -47,7 +47,7 @@ It is important to note that we have a few types of users: Administrator will have to be a member of it in order to have access to it via another project's job. -- **External users**: CI jobs created by [external users](../permissions.md#external-users-permissions) will have +- **External users**: CI jobs created by [external users](../permissions.md#external-users-core-only) will have access only to projects to which user has at least reporter access. This rules out accessing all internal projects by default. @@ -58,7 +58,7 @@ Let's consider the following scenario: hosted in private repositories and you have multiple CI jobs that make use of these repositories. -1. You invite a new [external user](../permissions.md#external-users-permissions). CI jobs created by that user do not +1. You invite a new [external user](../permissions.md#external-users-core-only). CI jobs created by that user do not have access to internal repositories, because the user also doesn't have the access from within GitLab. You as an employee have to grant explicit access for this user. This allows us to prevent from accidental data leakage. diff --git a/doc/user/project/protected_branches.md b/doc/user/project/protected_branches.md index 9a6cd3dc362..1bd272bdd0c 100644 --- a/doc/user/project/protected_branches.md +++ b/doc/user/project/protected_branches.md @@ -86,6 +86,20 @@ Click **Protect** and the branch will appear in the "Protected branch" list. ![Roles and users list](img/protected_branches_select_roles_and_users_list.png) +## Code Owners approvals **(PREMIUM)** + +It is possible to require at least one approval for each entry in the +[`CODEOWNERS` file](code_owners.md) that matches a file changed in +the merge request. To enable this feature: + +1. Toggle the **Require approval from code owners** slider. + +1. Click **Protect**. + +When this feature is enabled, all merge requests need approval +from one code owner per matched rule before they can be merged. Additionally, +pushes to the protected branch are denied if a rule is matched. + ## Wildcard protected branches > [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/4665) in GitLab 8.10. diff --git a/lib/api/protected_branches.rb b/lib/api/protected_branches.rb index ca75ee906ce..c7665c20234 100644 --- a/lib/api/protected_branches.rb +++ b/lib/api/protected_branches.rb @@ -42,7 +42,7 @@ module API end # rubocop: enable CodeReuse/ActiveRecord - desc 'Protect a single branch or wildcard' do + desc 'Protect a single branch' do success Entities::ProtectedBranch end params do @@ -93,3 +93,5 @@ module API end end end + +API::ProtectedBranches.prepend_if_ee('EE::API::ProtectedBranches') diff --git a/lib/gitlab/ci/trace.rb b/lib/gitlab/ci/trace.rb index 5b8c2d2f7c7..941f7178dac 100644 --- a/lib/gitlab/ci/trace.rb +++ b/lib/gitlab/ci/trace.rb @@ -4,6 +4,7 @@ module Gitlab module Ci class Trace include ::Gitlab::ExclusiveLeaseHelpers + include Checksummable LOCK_TTL = 10.minutes LOCK_RETRIES = 2 @@ -193,7 +194,7 @@ module Gitlab project: job.project, file_type: :trace, file: stream, - file_sha256: Digest::SHA256.file(path).hexdigest) + file_sha256: self.class.hexdigest(path)) end end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index c61c27033c5..8c322b57d8b 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -358,6 +358,9 @@ msgstr[1] "" msgid "%{tabname} changed" msgstr "" +msgid "%{template_project_id} is unknown or invalid" +msgstr "" + msgid "%{text} %{files}" msgid_plural "%{text} %{files} files" msgstr[0] "" @@ -12812,6 +12815,48 @@ msgstr "" msgid "Protected branches" msgstr "" +msgid "ProtectedBranch|%{wildcards_link_start}Wildcards%{wildcards_link_end} such as %{code_tag_start}*-stable%{code_tag_end} or %{code_tag_start}production/*%{code_tag_end} are supported" +msgstr "" + +msgid "ProtectedBranch|Allowed to merge" +msgstr "" + +msgid "ProtectedBranch|Allowed to merge:" +msgstr "" + +msgid "ProtectedBranch|Allowed to push" +msgstr "" + +msgid "ProtectedBranch|Allowed to push:" +msgstr "" + +msgid "ProtectedBranch|Code owner approval" +msgstr "" + +msgid "ProtectedBranch|Last commit" +msgstr "" + +msgid "ProtectedBranch|Protect" +msgstr "" + +msgid "ProtectedBranch|Protect a branch" +msgstr "" + +msgid "ProtectedBranch|Protected branch (%{protected_branches_count})" +msgstr "" + +msgid "ProtectedBranch|Pushes that change filenames matched by the CODEOWNERS file will be rejected" +msgstr "" + +msgid "ProtectedBranch|Require approval from code owners:" +msgstr "" + +msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above." +msgstr "" + +msgid "ProtectedBranch|Toggle code owner approval" +msgstr "" + msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?" msgstr "" @@ -13468,9 +13513,6 @@ msgstr "" msgid "Require all users to accept Terms of Service and Privacy Policy when they access GitLab." msgstr "" -msgid "Require approval from code owners" -msgstr "" - msgid "Require user password to approve" msgstr "" diff --git a/spec/migrations/migrate_code_owner_approval_status_to_protected_branches_in_batches_spec.rb b/spec/migrations/migrate_code_owner_approval_status_to_protected_branches_in_batches_spec.rb new file mode 100644 index 00000000000..67ac40d4d39 --- /dev/null +++ b/spec/migrations/migrate_code_owner_approval_status_to_protected_branches_in_batches_spec.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +require 'spec_helper' +require Rails.root.join('db', 'post_migrate', '20190827102026_migrate_code_owner_approval_status_to_protected_branches_in_batches.rb') + +describe MigrateCodeOwnerApprovalStatusToProtectedBranchesInBatches, :migration do + let(:namespaces) { table(:namespaces) } + let(:projects) { table(:projects) } + let(:protected_branches) { table(:protected_branches) } + + let(:namespace) do + namespaces.create!( + path: 'gitlab-instance-administrators', + name: 'GitLab Instance Administrators' + ) + end + + let(:project) do + projects.create!( + namespace_id: namespace.id, + name: 'GitLab Instance Administration' + ) + end + + let!(:protected_branch_1) do + protected_branches.create!( + name: "branch name", + project_id: project.id + ) + end + + describe '#up' do + context "when there's no projects needing approval" do + it "doesn't change any protected branch records" do + expect { migrate! } + .not_to change { ProtectedBranch.where(code_owner_approval_required: true).count } + end + end + + context "when there's a project needing approval" do + let!(:project_needing_approval) do + projects.create!( + namespace_id: namespace.id, + name: 'GitLab Instance Administration', + merge_requests_require_code_owner_approval: true + ) + end + + let!(:protected_branch_2) do + protected_branches.create!( + name: "branch name", + project_id: project_needing_approval.id + ) + end + + it "changes N protected branch records" do + expect { migrate! } + .to change { ProtectedBranch.where(code_owner_approval_required: true).count } + .by(1) + end + end + end +end diff --git a/spec/models/concerns/checksummable_spec.rb b/spec/models/concerns/checksummable_spec.rb new file mode 100644 index 00000000000..017077bd297 --- /dev/null +++ b/spec/models/concerns/checksummable_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Checksummable do + describe ".hexdigest" do + let(:fake_class) do + Class.new do + include Checksummable + end + end + + it 'returns the SHA256 sum of the file' do + expected = Digest::SHA256.file(__FILE__).hexdigest + + expect(fake_class.hexdigest(__FILE__)).to eq(expected) + end + end +end diff --git a/spec/models/lfs_object_spec.rb b/spec/models/lfs_object_spec.rb index 5b22f9e3e81..47cae5cf197 100644 --- a/spec/models/lfs_object_spec.rb +++ b/spec/models/lfs_object_spec.rb @@ -156,4 +156,15 @@ describe LfsObject do end end end + + describe ".calculate_oid" do + let(:lfs_object) { create(:lfs_object, :with_file) } + + it 'returns SHA256 sum of the file' do + path = lfs_object.file.path + expected = Digest::SHA256.file(path).hexdigest + + expect(described_class.calculate_oid(path)).to eq expected + end + end end diff --git a/spec/support/shared_examples/ci_trace_shared_examples.rb b/spec/support/shared_examples/ci_trace_shared_examples.rb index e2b4b50d41d..441d3f4ccb9 100644 --- a/spec/support/shared_examples/ci_trace_shared_examples.rb +++ b/spec/support/shared_examples/ci_trace_shared_examples.rb @@ -423,7 +423,7 @@ shared_examples_for 'trace with disabled live trace feature' do expect(build.job_artifacts_trace.file.filename).to eq('job.log') expect(File.exist?(src_path)).to be_falsy expect(src_checksum) - .to eq(Digest::SHA256.file(build.job_artifacts_trace.file.path).hexdigest) + .to eq(described_class.hexdigest(build.job_artifacts_trace.file.path)) expect(build.job_artifacts_trace.file_sha256).to eq(src_checksum) end end @@ -449,7 +449,7 @@ shared_examples_for 'trace with disabled live trace feature' do expect(build.job_artifacts_trace.file.filename).to eq('job.log') expect(build.old_trace).to be_nil expect(src_checksum) - .to eq(Digest::SHA256.file(build.job_artifacts_trace.file.path).hexdigest) + .to eq(described_class.hexdigest(build.job_artifacts_trace.file.path)) expect(build.job_artifacts_trace.file_sha256).to eq(src_checksum) end end @@ -787,7 +787,7 @@ shared_examples_for 'trace with enabled live trace feature' do expect(build.job_artifacts_trace.file.filename).to eq('job.log') expect(Ci::BuildTraceChunk.where(build: build)).not_to be_exist expect(src_checksum) - .to eq(Digest::SHA256.file(build.job_artifacts_trace.file.path).hexdigest) + .to eq(described_class.hexdigest(build.job_artifacts_trace.file.path)) expect(build.job_artifacts_trace.file_sha256).to eq(src_checksum) end end |