From cad97cd4dd4de0bcf119983ae70801b68ec9504c Mon Sep 17 00:00:00 2001 From: Ben Bodenmiller Date: Sat, 29 Oct 2016 03:38:19 +0000 Subject: add container registry images to not exported list --- app/views/projects/edit.html.haml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml index 30473d14b9b..d2623e85c87 100644 --- a/app/views/projects/edit.html.haml +++ b/app/views/projects/edit.html.haml @@ -180,6 +180,7 @@ %ul %li Build traces and artifacts %li LFS objects + %li Container registry images %hr - if can? current_user, :archive_project, @project .row.prepend-top-default -- cgit v1.2.1 From 03b932df19b160072d2e3b20dfb279079e81160a Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Mon, 24 Oct 2016 16:17:51 +0100 Subject: Add a bin/changelog script --- bin/changelog | 163 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100755 bin/changelog diff --git a/bin/changelog b/bin/changelog new file mode 100755 index 00000000000..2b08e3e4c2a --- /dev/null +++ b/bin/changelog @@ -0,0 +1,163 @@ +#!/usr/bin/env ruby +# +# Generate a changelog entry file in the correct location. +# +# Automatically stages the file and amends the previous commit if the `--amend` +# argument is used. + +require 'optparse' +require 'yaml' + +Options = Struct.new( + :amend, + :author, + :dry_run, + :merge_request, + :title +) + +class ChangelogOptionParser + def self.parse(argv) + options = Options.new + + parser = OptionParser.new do |opts| + opts.banner = "Usage: #{__FILE__} [options]" + + # Note: We do not provide a shorthand for this in order to match the `git + # commit` interface + opts.on('--amend', 'Amend the previous commit') do |value| + options.amend = value + end + + opts.on('-m', '--merge-request [integer]', Integer, 'Merge Request ID') do |value| + options.merge_request = value + end + + opts.on('-n', '--dry-run', "Don't actually write anything, just print") do |value| + options.dry_run = value + end + + opts.on('-u', '--git-username', 'Use Git user.name configuration as the author') do |value| + options.author = git_user_name if value + end + + opts.on('-h', '--help', 'Print help message') do + puts opts + exit + end + end + + parser.parse!(argv) + + # Title is everything that remains, but let's clean it up a bit + options.title = argv.join(' ').strip.squeeze(' ').tr("\r\n", '') + + options + end + + def self.git_user_name + %x{git config user.name}.strip + end +end + +class ChangelogEntry + attr_reader :options + + def initialize(options) + @options = options + + assert_feature_branch! + assert_new_file! + assert_title! + + $stdout.puts "\e[32mcreate\e[0m #{file_path}" + $stdout.puts contents + unless options.dry_run + write + amend_commit if options.amend + end + end + + def contents + YAML.dump( + 'title' => title, + 'merge_request' => options.merge_request, + 'author' => options.author + ) + end + + def write + File.write(file_path, contents) + end + + def amend_commit + %x{git add #{file_path}} + exec("git commit --amend") + end + + private + + def fail_with(message) + $stderr.puts "\e[31merror\e[0m #{message}" + exit 1 + end + + def assert_feature_branch! + return unless branch_name == 'master' + + fail_with "Create a branch first!" + end + + def assert_new_file! + return unless File.exist?(file_path) + + fail_with "#{file_path} already exists!" + end + + def assert_title! + return if options.title.length > 0 || options.amend + + fail_with "Provide a title for the changelog entry or use `--amend`" \ + " to use the title from the previous commit." + end + + def title + if options.title.empty? + last_commit_subject + else + options.title + end + end + + def last_commit_subject + %x{git log --format="%s" -1}.strip + end + + def file_path + File.join( + unreleased_path, + branch_name.gsub(/[^\w-]/, '-') << '.yml' + ) + end + + def unreleased_path + File.join('changelogs', 'unreleased').tap do |path| + path << '-ee' if ee? + end + end + + def ee? + @ee ||= File.exist?(File.expand_path('../CHANGELOG-EE.md', __dir__)) + end + + def branch_name + @branch_name ||= %x{git symbolic-ref HEAD}.strip.sub(%r{\Arefs/heads/}, '') + end +end + +if $0 == __FILE__ + options = ChangelogOptionParser.parse(ARGV) + ChangelogEntry.new(options) +end + +# vim: ft=ruby -- cgit v1.2.1 From 23312b484f14c4843c782fd195a690e5e288af11 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 25 Oct 2016 13:09:46 +0100 Subject: Add changelog documentation --- CONTRIBUTING.md | 9 +-- doc/development/README.md | 1 + doc/development/changelog.md | 164 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 167 insertions(+), 7 deletions(-) create mode 100644 doc/development/changelog.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b4635e50c28..54673947707 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -247,13 +247,7 @@ request is as follows: 1. Fork the project into your personal space on GitLab.com 1. Create a feature branch, branch away from `master` 1. Write [tests](https://gitlab.com/gitlab-org/gitlab-development-kit#running-the-tests) and code -1. Add your changes to the [CHANGELOG.md](CHANGELOG.md): - 1. If you are fixing a ~regression issue, you can add your entry to the next - patch release (e.g. `8.12.5` if current version is `8.12.4`) - 1. Otherwise, add your entry to the next minor release (e.g. `8.13.0` if - current version is `8.12.4` - 1. Please add your entry at a random place among the entries of the targeted - release +1. [Generate a changelog entry with `bin/changelog`][changelog] 1. If you are writing documentation, make sure to follow the [documentation styleguide][doc-styleguide] 1. If you have multiple commits please combine them into one commit by @@ -469,6 +463,7 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor [contributor-covenant]: http://contributor-covenant.org [rss-source]: https://github.com/bbatsov/ruby-style-guide/blob/master/README.md#source-code-layout [rss-naming]: https://github.com/bbatsov/ruby-style-guide/blob/master/README.md#naming +[changelog]: doc/development/changelog.md "Generate a changelog entry" [doc-styleguide]: doc/development/doc_styleguide.md "Documentation styleguide" [scss-styleguide]: doc/development/scss_styleguide.md "SCSS styleguide" [newlines-styleguide]: doc/development/newlines_styleguide.md "Newlines styleguide" diff --git a/doc/development/README.md b/doc/development/README.md index 14d6f08e43a..9e0a5178eeb 100644 --- a/doc/development/README.md +++ b/doc/development/README.md @@ -21,6 +21,7 @@ ## Process +- [Generate a changelog entry with `bin/changelog`](changelog.md) - [Code review guidelines](code_review.md) for reviewing code and having code reviewed. - [Merge request performance guidelines](merge_request_performance_guidelines.md) for ensuring merge requests do not negatively impact GitLab performance diff --git a/doc/development/changelog.md b/doc/development/changelog.md new file mode 100644 index 00000000000..f10f4c6722a --- /dev/null +++ b/doc/development/changelog.md @@ -0,0 +1,164 @@ +# Generate a changelog entry + +This guide contains instructions for generating a changelog entry data file, as +well as information and history about our changelog process. + +## Overview + +Each bullet point, or **entry**, in our [`CHANGELOG.md`][changelog.md] file is +generated from a single data file in the [`changelogs/unreleased/`][unreleased] +(or corresponding EE) folder. The file is expected to be a [YAML] file in the +following format: + +```yaml +--- +title: "Going through change[log]s" +merge_request: 1972 +author: Ozzy Osbourne +``` + +The `merge_request` value is a reference to a merge request that adds this +entry, and the `author` key is used to give attribution to community +contributors. Both are optional. + +If you're working on the GitLab EE repository, the entry will be added to +`changelogs/unreleased-ee/` instead. + +[changelog.md]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CHANGELOG.md +[unreleased]: https://gitlab.com/gitlab-org/gitlab-ce/tree/master/changelogs/ +[YAML]: https://en.wikipedia.org/wiki/YAML + +## Instructions + +A `bin/changelog` script is available to generate the changelog entry file +automatically. + +Its simplest usage is to provide the value for `title`: + +```text +$ bin/changelog Hey DZ, I added a feature to GitLab! +create changelogs/unreleased/my-feature.yml +--- +title: Hey DZ, I added a feature to GitLab! +merge_request: +author: +``` + +The entry filename is based on the name of the current Git branch. If you run +the command above on a branch called `feature/hey-dz`, it will generate a +`changelogs/unreleased/feature-hey-dz` file. + +### Arguments + +| Argument | Shorthand | Purpose | +| ----------------- | --------- | --------------------------------------------- | +| `--amend` | | Amend the previous commit | +| `--merge-request` | `-m` | Merge Request ID | +| `--dry-run` | `-n` | Don't actually write anything, just print | +| `--git-username` | `-u` | Use Git user.name configuration as the author | +| `--help` | `-h` | Print help message | + +#### `--amend` + +You can pass the **`--amend`** argument to automatically stage the generated +file and amend it to the previous commit. + +If you use **`--amend`** and don't provide a title, it will automatically use +the "subject" of the previous commit, which is the first line of the commit +message: + +```text +$ git show --oneline +ab88683 Added an awesome new feature to GitLab + +$ bin/changelog --amend +create changelogs/unreleased/feature-hey-dz.yml +--- +title: Added an awesome new feature to GitLab +merge_request: +author: +``` + +#### `--merge-request` or `-m` + +Use the **`--merge-request`** or **`-m`** argument to provide the +`merge_request` value: + +```text +$ bin/changelog Hey DZ, I added a feature to GitLab! -m 1983 +create changelogs/unreleased/feature-hey-dz.yml +--- +title: Hey DZ, I added a feature to GitLab! +merge_request: 1983 +author: +``` + +#### `--dry-run` or `-n` + +Use the **`--dry-run`** or **`-n`** argument to prevent actually writing or +committing anything: + +```text +$ bin/changelog --amend --dry-run +create changelogs/unreleased/feature-hey-dz.yml +--- +title: Added an awesome new feature to GitLab +merge_request: +author: + +$ ls changelogs/unreleased/ +``` + +#### `--git-username` or `-u` + +Use the **`--git-username`** or **`-u`** argument to automatically fill in the +`author` value with your configured Git `user.name` value: + +```text +$ git config user.name +Jane Doe + +$ bin/changelog --u Hey DZ, I added a feature to GitLab! +create changelogs/unreleased/feature-hey-dz.yml +--- +title: Hey DZ, I added a feature to GitLab! +merge_request: +author: Jane Doe +``` + +## History and Reasoning + +Our `CHANGELOG` file was previously updated manually by each contributor that +felt their change warranted an entry. When two merge requests added their own +entries at the same spot in the list, it created a merge conflict in one as soon +as the other was merged. When we had dozens of merge requests fighting for the +same changelog entry location, this quickly became a major source of merge +conflicts and delays in development. + +This led us to a [boring solution] of "add your entry in a random location in +the list." This actually worked pretty well as we got further along in each +monthly release cycle, but at the start of a new cycle, when a new version +section was added and there were fewer places to "randomly" add an entry, the +conflicts became a problem again until we had a sufficient number of entries. + +On top of all this, it created an entirely different headache for [release managers] +when they cherry-picked a commit into a stable branch for a patch release. If +the commit included an entry in the `CHANGELOG`, it would include the entire +changelog for the latest version in `master`, so the release manager would have +to manually remove the later entries. They often would have had to do this +multiple times per patch release. This was compounded when we had to release +multiple patches at once due to a security issue. + +We needed to automate all of this manual work. So we [started brainstorming]. +After much discussion we settled on the current solution of one file per entry, +and then compiling the entries into the overall `CHANGELOG.md` file during the +[release process]. + +[boring solution]: https://about.gitlab.com/handbook/#boring-solutions +[release managers]: https://gitlab.com/gitlab-org/release-tools/blob/master/doc/release-manager.md +[started brainstorming]: https://gitlab.com/gitlab-org/gitlab-ce/issues/17826 +[release process]: https://gitlab.com/gitlab-org/release-tools + +--- + +[Return to Development documentation](README.md) -- cgit v1.2.1 From 5acb3230efce11148c55dce9a53cd2a85e7d120a Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Sat, 29 Oct 2016 19:10:47 +0100 Subject: Add specs for ChangelogOptionParser in bin/changelog --- bin/changelog | 3 ++- spec/bin/changelog_spec.rb | 65 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 spec/bin/changelog_spec.rb diff --git a/bin/changelog b/bin/changelog index 2b08e3e4c2a..a0d1ad2d730 100755 --- a/bin/changelog +++ b/bin/changelog @@ -42,7 +42,7 @@ class ChangelogOptionParser end opts.on('-h', '--help', 'Print help message') do - puts opts + $stdout.puts opts exit end end @@ -72,6 +72,7 @@ class ChangelogEntry $stdout.puts "\e[32mcreate\e[0m #{file_path}" $stdout.puts contents + unless options.dry_run write amend_commit if options.amend diff --git a/spec/bin/changelog_spec.rb b/spec/bin/changelog_spec.rb new file mode 100644 index 00000000000..da167dc570f --- /dev/null +++ b/spec/bin/changelog_spec.rb @@ -0,0 +1,65 @@ +require 'spec_helper' + +load File.expand_path('../../bin/changelog', __dir__) + +describe 'bin/changelog' do + describe ChangelogOptionParser do + it 'parses --ammend' do + options = described_class.parse(%w[foo bar --amend]) + + expect(options.amend).to eq true + end + + it 'parses --merge-request' do + options = described_class.parse(%w[foo --merge-request 1234 bar]) + + expect(options.merge_request).to eq 1234 + end + + it 'parses -m' do + options = described_class.parse(%w[foo -m 4321 bar]) + + expect(options.merge_request).to eq 4321 + end + + it 'parses --dry-run' do + options = described_class.parse(%w[foo --dry-run bar]) + + expect(options.dry_run).to eq true + end + + it 'parses -n' do + options = described_class.parse(%w[foo -n bar]) + + expect(options.dry_run).to eq true + end + + it 'parses --git-username' do + allow(described_class).to receive(:git_user_name).and_return('Jane Doe') + options = described_class.parse(%w[foo --git-username bar]) + + expect(options.author).to eq 'Jane Doe' + end + + it 'parses -u' do + allow(described_class).to receive(:git_user_name).and_return('John Smith') + options = described_class.parse(%w[foo -u bar]) + + expect(options.author).to eq 'John Smith' + end + + it 'parses -h' do + expect do + $stdout = StringIO.new + + described_class.parse(%w[foo -h bar]) + end.to raise_error(SystemExit) + end + + it 'assigns title' do + options = described_class.parse(%W[foo -m 1 bar\n -u baz\r\n --amend]) + + expect(options.title).to eq 'foo bar baz' + end + end +end -- cgit v1.2.1 From dfb2bc3d26ecbac3b2dcf28e4622e279c416cbbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20R=C3=BCger?= Date: Sat, 29 Oct 2016 02:40:13 +0200 Subject: Update rack-attack gem to 4.4.1 See: https://github.com/kickstarter/rack-attack/blob/master/CHANGELOG.md --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 5f16cc063e2..69ad5476403 100644 --- a/Gemfile +++ b/Gemfile @@ -196,7 +196,7 @@ gem 'loofah', '~> 2.0.3' gem 'licensee', '~> 8.0.0' # Protect against bruteforcing -gem 'rack-attack', '~> 4.3.1' +gem 'rack-attack', '~> 4.4.1' # Ace editor gem 'ace-rails-ap', '~> 4.1.0' diff --git a/Gemfile.lock b/Gemfile.lock index f8116e1894f..312313334d7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -520,7 +520,7 @@ GEM rack (1.6.4) rack-accept (0.4.5) rack (>= 0.4) - rack-attack (4.3.1) + rack-attack (4.4.1) rack rack-cors (0.4.0) rack-mount (0.8.3) @@ -929,7 +929,7 @@ DEPENDENCIES poltergeist (~> 1.9.0) premailer-rails (~> 1.9.0) pry-rails (~> 0.3.4) - rack-attack (~> 4.3.1) + rack-attack (~> 4.4.1) rack-cors (~> 0.4.0) rack-oauth2 (~> 1.2.1) rails (= 4.2.7.1) -- cgit v1.2.1 From 5a80f5d79bfd37ccc53c5c87d805b04e4107bb6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20R=C3=BCger?= Date: Sat, 29 Oct 2016 02:29:42 +0200 Subject: Update diffy gem to 3.1.0 ChangeLog: https://github.com/samg/diffy/blob/master/CHANGELOG --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 5f16cc063e2..f0cf72ba74d 100644 --- a/Gemfile +++ b/Gemfile @@ -117,7 +117,7 @@ gem 'truncato', '~> 0.7.8' gem 'nokogiri', '~> 1.6.7', '>= 1.6.7.2' # Diffs -gem 'diffy', '~> 3.0.3' +gem 'diffy', '~> 3.1.0' # Application server group :unicorn do diff --git a/Gemfile.lock b/Gemfile.lock index f8116e1894f..68ee206a818 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -180,7 +180,7 @@ GEM railties rotp (~> 2.0) diff-lcs (1.2.5) - diffy (3.0.7) + diffy (3.1.0) docile (1.1.5) doorkeeper (4.2.0) railties (>= 4.2) @@ -847,7 +847,7 @@ DEPENDENCIES default_value_for (~> 3.0.0) devise (~> 4.2) devise-two-factor (~> 3.0.0) - diffy (~> 3.0.3) + diffy (~> 3.1.0) doorkeeper (~> 4.2.0) dropzonejs-rails (~> 0.7.1) email_reply_parser (~> 0.5.8) -- cgit v1.2.1 From e45a9f5bff2456aad442c4c7ef37254219226fc5 Mon Sep 17 00:00:00 2001 From: Nur Rony Date: Wed, 26 Oct 2016 17:18:29 +0600 Subject: fixes milestone dropdown not select issue changelog entry added adds merge request number adds test for milestone dropdown selected text removes calling unnecessary escape function adds changelog entry in 8.13.2 and removed redundant changelog sections moves changelog entry to 8.14 as there is conflict --- CHANGELOG.md | 2 +- app/views/shared/issuable/_milestone_dropdown.html.haml | 4 ++-- spec/features/issues/filter_by_milestone_spec.rb | 6 ++++++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 372ddecc98b..c92ea2f6e8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ Please view this file on the master branch, on stable branches it's out of date. ## 8.14.0 (2016-11-22) - +- Fix Milestone dropdown not stay selected for `Upcoming` and `No Milestone` option !7117 - Backups do not fail anymore when using tar on annex and custom_hooks only. !5814 - Adds user project membership expired event to clarify why user was removed (Callum Dryden) - Trim leading and trailing whitespace on project_path (Linus Thiel) diff --git a/app/views/shared/issuable/_milestone_dropdown.html.haml b/app/views/shared/issuable/_milestone_dropdown.html.haml index f27a9002ec2..40fe53e6a8d 100644 --- a/app/views/shared/issuable/_milestone_dropdown.html.haml +++ b/app/views/shared/issuable/_milestone_dropdown.html.haml @@ -1,10 +1,10 @@ - project = @target_project || @project - extra_class = extra_class || '' - show_menu_above = show_menu_above || false -- selected_text = selected.try(:title) +- selected_text = selected.try(:title) || params[:milestone_title] - dropdown_title = local_assigns.fetch(:dropdown_title, "Filter by milestone") - if selected.present? - = hidden_field_tag(name, name == :milestone_title ? selected.title : selected.id) + = hidden_field_tag(name, name == :milestone_title ? selected_text : selected.id) = dropdown_tag(milestone_dropdown_label(selected_text), options: { title: dropdown_title, toggle_class: "js-milestone-select js-filter-submit #{extra_class}", filter: true, dropdown_class: "dropdown-menu-selectable dropdown-menu-milestone", placeholder: "Search milestones", footer_content: project.present?, data: { show_no: true, show_menu_above: show_menu_above, show_any: show_any, show_upcoming: show_upcoming, field_name: name, selected: selected.try(:title), project_id: project.try(:id), milestones: milestones_filter_dropdown_path, default_label: "Milestone" } }) do - if project diff --git a/spec/features/issues/filter_by_milestone_spec.rb b/spec/features/issues/filter_by_milestone_spec.rb index 88e1549a22b..9dfa5d1de19 100644 --- a/spec/features/issues/filter_by_milestone_spec.rb +++ b/spec/features/issues/filter_by_milestone_spec.rb @@ -11,6 +11,7 @@ feature 'Issue filtering by Milestone', feature: true do visit_issues(project) filter_by_milestone(Milestone::None.title) + expect(page).to have_css('.milestone-filter .dropdown-toggle-text', text: 'No Milestone') expect(page).to have_css('.issue', count: 1) end @@ -22,6 +23,7 @@ feature 'Issue filtering by Milestone', feature: true do visit_issues(project) filter_by_milestone(Milestone::Upcoming.title) + expect(page).to have_css('.milestone-filter .dropdown-toggle-text', text: 'Upcoming') expect(page).to have_css('.issue', count: 0) end @@ -33,6 +35,7 @@ feature 'Issue filtering by Milestone', feature: true do visit_issues(project) filter_by_milestone(Milestone::Upcoming.title) + expect(page).to have_css('.milestone-filter .dropdown-toggle-text', text: 'Upcoming') expect(page).to have_css('.issue', count: 1) end @@ -44,6 +47,7 @@ feature 'Issue filtering by Milestone', feature: true do visit_issues(project) filter_by_milestone(Milestone::Upcoming.title) + expect(page).to have_css('.milestone-filter .dropdown-toggle-text', text: 'Upcoming') expect(page).to have_css('.issue', count: 0) end end @@ -55,6 +59,7 @@ feature 'Issue filtering by Milestone', feature: true do visit_issues(project) filter_by_milestone(milestone.title) + expect(page).to have_css('.milestone-filter .dropdown-toggle-text', text: milestone.title) expect(page).to have_css('.issue', count: 1) end @@ -70,6 +75,7 @@ feature 'Issue filtering by Milestone', feature: true do visit_issues(project) filter_by_milestone(milestone.title) + expect(page).to have_css('.milestone-filter .dropdown-toggle-text', text: milestone.title) expect(page).to have_css('.issue', count: 1) end end -- cgit v1.2.1 From 517dd4a3f38ff36feadf5cacf88ce0fdd30be2fe Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Mon, 17 Oct 2016 17:23:51 +0200 Subject: Allow owners to fetch source code in CI builds Due to different way of handling owners of a project, they were not allowed to fetch CI sources for project. --- app/policies/project_policy.rb | 12 ++++++---- spec/lib/gitlab/git_access_spec.rb | 8 +++++++ spec/policies/project_policy_spec.rb | 14 +++++++++++ spec/requests/lfs_http_spec.rb | 12 +++++++++- ...ntainer_registry_authentication_service_spec.rb | 28 ++++++++++++++++++---- 5 files changed, 65 insertions(+), 9 deletions(-) diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb index fbb3d4507d6..1ee31023e26 100644 --- a/app/policies/project_policy.rb +++ b/app/policies/project_policy.rb @@ -2,11 +2,11 @@ class ProjectPolicy < BasePolicy def rules team_access!(user) - owner = user.admin? || - project.owner == user || + owner = project.owner == user || (project.group && project.group.has_owner?(user)) - owner_access! if owner + owner_access! if user.admin? || owner + team_member_owner_access! if owner if project.public? || (project.internal? && !user.external?) guest_access! @@ -16,7 +16,7 @@ class ProjectPolicy < BasePolicy can! :read_build if project.public_builds? if project.request_access_enabled && - !(owner || project.team.member?(user) || project_group_member?(user)) + !(owner || user.admin? || project.team.member?(user) || project_group_member?(user)) can! :request_access end end @@ -135,6 +135,10 @@ class ProjectPolicy < BasePolicy can! :destroy_issue end + def team_member_owner_access! + team_member_reporter_access! + end + # Push abilities on the users team role def team_access!(user) access = project.team.max_member_access(user.id) diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb index a5aa387f4f7..62aa212f1f6 100644 --- a/spec/lib/gitlab/git_access_spec.rb +++ b/spec/lib/gitlab/git_access_spec.rb @@ -122,6 +122,14 @@ describe Gitlab::GitAccess, lib: true do describe 'build authentication_abilities permissions' do let(:authentication_abilities) { build_authentication_abilities } + describe 'owner' do + let(:project) { create(:project, namespace: user.namespace) } + + context 'pull code' do + it { expect(subject).to be_allowed } + end + end + describe 'reporter user' do before { project.team << [user, :reporter] } diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb index 658e3c13a73..96249a7d8c3 100644 --- a/spec/policies/project_policy_spec.rb +++ b/spec/policies/project_policy_spec.rb @@ -6,6 +6,7 @@ describe ProjectPolicy, models: true do let(:dev) { create(:user) } let(:master) { create(:user) } let(:owner) { create(:user) } + let(:admin) { create(:admin) } let(:project) { create(:empty_project, :public, namespace: owner.namespace) } let(:guest_permissions) do @@ -152,6 +153,19 @@ describe ProjectPolicy, models: true do context 'owner' do let(:current_user) { owner } + it do + is_expected.to include(*guest_permissions) + is_expected.to include(*reporter_permissions) + is_expected.to include(*team_member_reporter_permissions) + is_expected.to include(*developer_permissions) + is_expected.to include(*master_permissions) + is_expected.to include(*owner_permissions) + end + end + + context 'admin' do + let(:current_user) { admin } + it do is_expected.to include(*guest_permissions) is_expected.to include(*reporter_permissions) diff --git a/spec/requests/lfs_http_spec.rb b/spec/requests/lfs_http_spec.rb index dbdf83a0dff..9bfc84c7425 100644 --- a/spec/requests/lfs_http_spec.rb +++ b/spec/requests/lfs_http_spec.rb @@ -284,7 +284,17 @@ describe 'Git LFS API and storage' do let(:authorization) { authorize_ci_project } shared_examples 'can download LFS only from own projects' do - context 'for own project' do + context 'for owned project' do + let(:project) { create(:empty_project, namespace: user.namespace) } + + let(:update_permissions) do + project.lfs_objects << lfs_object + end + + it_behaves_like 'responds with a file' + end + + context 'for member of project' do let(:pipeline) { create(:ci_empty_pipeline, project: project) } let(:update_permissions) do diff --git a/spec/services/auth/container_registry_authentication_service_spec.rb b/spec/services/auth/container_registry_authentication_service_spec.rb index c64df4979b0..bb26513103d 100644 --- a/spec/services/auth/container_registry_authentication_service_spec.rb +++ b/spec/services/auth/container_registry_authentication_service_spec.rb @@ -245,6 +245,12 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do it_behaves_like 'a pullable' end + + context 'when you are owner' do + let(:project) { create(:empty_project, namespace: current_user.namespace) } + + it_behaves_like 'a pullable' + end end context 'for private' do @@ -266,6 +272,12 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do it_behaves_like 'a pullable' end + + context 'when you are owner' do + let(:project) { create(:empty_project, namespace: current_user.namespace) } + + it_behaves_like 'a pullable' + end end end end @@ -276,13 +288,21 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do end context 'disallow for all' do - let(:project) { create(:empty_project, :public) } + context 'when you are member' do + let(:project) { create(:empty_project, :public) } - before do - project.team << [current_user, :developer] + before do + project.team << [current_user, :developer] + end + + it_behaves_like 'an inaccessible' end - it_behaves_like 'an inaccessible' + context 'when you are owner' do + let(:project) { create(:empty_project, :public, namespace: current_user.namespace) } + + it_behaves_like 'an inaccessible' + end end end end -- cgit v1.2.1 From dec4376027266ca15798d9feab8f997b879d22d4 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 7 Oct 2016 13:07:10 +0100 Subject: Updated Sortable JS plugin Fixes an issue in Safari that stops issues from being draggable Closes #23048 --- CHANGELOG.md | 1 + app/assets/stylesheets/pages/boards.scss | 4 + vendor/assets/javascripts/Sortable.js | 199 ++++++++++++++++++++++--------- 3 files changed, 149 insertions(+), 55 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 372ddecc98b..9491be9cd1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ Please view this file on the master branch, on stable branches it's out of date. - Escape ref and path for relative links !6050 (winniehell) - Fixed link typo on /help/ui to Alerts section. !6915 (Sam Rose) - Fix filtering of milestones with quotes in title (airatshigapov) +- Fix issue boards dragging bug in Safari - Refactor less readable existance checking code from CoffeeScript !6289 (jlogandavison) - Update mail_room and enable sentinel support to Reply By Email (!7101) - Add task completion status in Issues and Merge Requests tabs: "X of Y tasks completed" (!6527, @gmesalazar) diff --git a/app/assets/stylesheets/pages/boards.scss b/app/assets/stylesheets/pages/boards.scss index ef6833c9845..608804c63ec 100644 --- a/app/assets/stylesheets/pages/boards.scss +++ b/app/assets/stylesheets/pages/boards.scss @@ -12,6 +12,10 @@ opacity: 1!important; * { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; // !important to make sure no style can override this when dragging cursor: -webkit-grabbing!important; cursor: grabbing!important; diff --git a/vendor/assets/javascripts/Sortable.js b/vendor/assets/javascripts/Sortable.js index eca7c5012b2..f9e57bcb855 100644 --- a/vendor/assets/javascripts/Sortable.js +++ b/vendor/assets/javascripts/Sortable.js @@ -4,8 +4,7 @@ * @license MIT */ - -(function (factory) { +(function sortableModule(factory) { "use strict"; if (typeof define === "function" && define.amd) { @@ -15,15 +14,22 @@ module.exports = factory(); } else if (typeof Package !== "undefined") { + //noinspection JSUnresolvedVariable Sortable = factory(); // export for Meteor.js } else { /* jshint sub:true */ window["Sortable"] = factory(); } -})(function () { +})(function sortableFactory() { "use strict"; + if (typeof window == "undefined" || !window.document) { + return function sortableError() { + throw new Error("Sortable.js requires a window with a document"); + }; + } + var dragEl, parentEl, ghostEl, @@ -33,6 +39,7 @@ scrollEl, scrollParentEl, + scrollCustomFn, lastEl, lastCSS, @@ -42,6 +49,8 @@ newIndex, activeGroup, + putSortable, + autoScroll = {}, tapEvt, @@ -58,8 +67,15 @@ document = win.document, parseInt = win.parseInt, + $ = win.jQuery || win.Zepto, + Polymer = win.Polymer, + supportDraggable = !!('draggable' in document.createElement('div')), supportCssPointerEvents = (function (el) { + // false when IE11 + if (!!navigator.userAgent.match(/Trident.*rv[ :]?11\./)) { + return false; + } el = document.createElement('x'); el.style.cssText = 'pointer-events:auto'; return el.style.pointerEvents === 'auto'; @@ -88,13 +104,17 @@ winHeight = window.innerHeight, vx, - vy + vy, + + scrollOffsetX, + scrollOffsetY ; // Delect scrollEl if (scrollParentEl !== rootEl) { scrollEl = options.scroll; scrollParentEl = rootEl; + scrollCustomFn = options.scrollFn; if (scrollEl === true) { scrollEl = rootEl; @@ -136,11 +156,18 @@ if (el) { autoScroll.pid = setInterval(function () { + scrollOffsetY = vy ? vy * speed : 0; + scrollOffsetX = vx ? vx * speed : 0; + + if ('function' === typeof(scrollCustomFn)) { + return scrollCustomFn.call(_this, scrollOffsetX, scrollOffsetY, evt); + } + if (el === win) { - win.scrollTo(win.pageXOffset + vx * speed, win.pageYOffset + vy * speed); + win.scrollTo(win.pageXOffset + scrollOffsetX, win.pageYOffset + scrollOffsetY); } else { - vy && (el.scrollTop += vy * speed); - vx && (el.scrollLeft += vx * speed); + el.scrollTop += scrollOffsetY; + el.scrollLeft += scrollOffsetX; } }, 24); } @@ -149,19 +176,39 @@ }, 30), _prepareGroup = function (options) { - var group = options.group; + function toFn(value, pull) { + if (value === void 0 || value === true) { + value = group.name; + } - if (!group || typeof group != 'object') { - group = options.group = {name: group}; + if (typeof value === 'function') { + return value; + } else { + return function (to, from) { + var fromGroup = from.options.group.name; + + return pull + ? value + : value && (value.join + ? value.indexOf(fromGroup) > -1 + : (fromGroup == value) + ); + }; + } } - ['pull', 'put'].forEach(function (key) { - if (!(key in group)) { - group[key] = true; - } - }); + var group = {}; + var originalGroup = options.group; + + if (!originalGroup || typeof originalGroup != 'object') { + originalGroup = {name: originalGroup}; + } - options.groups = ' ' + group.name + (group.put.join ? ' ' + group.put.join(' ') : '') + ' '; + group.name = originalGroup.name; + group.checkPull = toFn(originalGroup.pull, true); + group.checkPut = toFn(originalGroup.put); + + options.group = group; } ; @@ -198,6 +245,7 @@ draggable: /[uo]l/i.test(el.nodeName) ? 'li' : '>*', ghostClass: 'sortable-ghost', chosenClass: 'sortable-chosen', + dragClass: 'sortable-drag', ignore: 'a, img', filter: null, animation: 0, @@ -211,7 +259,8 @@ forceFallback: false, fallbackClass: 'sortable-fallback', fallbackOnBody: false, - fallbackTolerance: 0 + fallbackTolerance: 0, + fallbackOffset: {x: 0, y: 0} }; @@ -224,7 +273,7 @@ // Bind all private methods for (var fn in this) { - if (fn.charAt(0) === '_') { + if (fn.charAt(0) === '_' && typeof this[fn] === 'function') { this[fn] = this[fn].bind(this); } } @@ -258,7 +307,7 @@ type = evt.type, touch = evt.touches && evt.touches[0], target = (touch || evt).target, - originalTarget = target, + originalTarget = evt.target.shadowRoot && evt.path[0] || target, filter = options.filter, startIndex; @@ -271,13 +320,13 @@ return; // only left button or enabled } - target = _closest(target, options.draggable, el); - - if (!target) { + if (options.handle && !_closest(originalTarget, options.handle, el)) { return; } - if (options.handle && !_closest(originalTarget, options.handle, el)) { + target = _closest(target, options.draggable, el); + + if (!target) { return; } @@ -332,16 +381,18 @@ this._lastX = (touch || evt).clientX; this._lastY = (touch || evt).clientY; + dragEl.style['will-change'] = 'transform'; + dragStartFn = function () { // Delayed drag has been triggered // we can re-enable the events: touchmove/mousemove _this._disableDelayedDrag(); // Make the element draggable - dragEl.draggable = true; + dragEl.draggable = _this.nativeDraggable; // Chosen item - _toggleClass(dragEl, _this.options.chosenClass, true); + _toggleClass(dragEl, options.chosenClass, true); // Bind the events: dragstart/dragend _this._triggerDragStart(touch); @@ -408,7 +459,10 @@ try { if (document.selection) { - document.selection.empty(); + // Timeout neccessary for IE9 + setTimeout(function () { + document.selection.empty(); + }); } else { window.getSelection().removeAllRanges(); } @@ -418,8 +472,11 @@ _dragStarted: function () { if (rootEl && dragEl) { + var options = this.options; + // Apply effect - _toggleClass(dragEl, this.options.ghostClass, true); + _toggleClass(dragEl, options.ghostClass, true); + _toggleClass(dragEl, options.dragClass, false); Sortable.active = this; @@ -443,12 +500,11 @@ var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY), parent = target, - groupName = ' ' + this.options.group.name + '', i = touchDragOverListeners.length; if (parent) { do { - if (parent[expando] && parent[expando].options.groups.indexOf(groupName) > -1) { + if (parent[expando]) { while (i--) { touchDragOverListeners[i]({ clientX: touchEvt.clientX, @@ -478,9 +534,10 @@ if (tapEvt) { var options = this.options, fallbackTolerance = options.fallbackTolerance, + fallbackOffset = options.fallbackOffset, touch = evt.touches ? evt.touches[0] : evt, - dx = touch.clientX - tapEvt.clientX, - dy = touch.clientY - tapEvt.clientY, + dx = (touch.clientX - tapEvt.clientX) + fallbackOffset.x, + dy = (touch.clientY - tapEvt.clientY) + fallbackOffset.y, translate3d = evt.touches ? 'translate3d(' + dx + 'px,' + dy + 'px,0)' : 'translate(' + dx + 'px,' + dy + 'px)'; // only set the status to dragging, when we are actually dragging @@ -520,6 +577,7 @@ _toggleClass(ghostEl, options.ghostClass, false); _toggleClass(ghostEl, options.fallbackClass, true); + _toggleClass(ghostEl, options.dragClass, true); _css(ghostEl, 'top', rect.top - parseInt(css.marginTop, 10)); _css(ghostEl, 'left', rect.left - parseInt(css.marginLeft, 10)); @@ -545,13 +603,15 @@ this._offUpEvents(); - if (activeGroup.pull == 'clone') { - cloneEl = dragEl.cloneNode(true); + if (activeGroup.checkPull(this, this, dragEl, evt) == 'clone') { + cloneEl = _clone(dragEl); _css(cloneEl, 'display', 'none'); rootEl.insertBefore(cloneEl, dragEl); _dispatchEvent(this, rootEl, 'clone', dragEl); } + _toggleClass(dragEl, options.dragClass, true); + if (useFallback) { if (useFallback === 'touch') { // Bind touch events @@ -581,10 +641,11 @@ var el = this.el, target, dragRect, + targetRect, revert, options = this.options, group = options.group, - groupPut = group.put, + activeSortable = Sortable.active, isOwner = (activeGroup === group), canSort = options.sort; @@ -598,9 +659,9 @@ if (activeGroup && !options.disabled && (isOwner ? canSort || (revert = !rootEl.contains(dragEl)) // Reverting item into the original list - : activeGroup.pull && groupPut && ( - (activeGroup.name === group.name) || // by Name - (groupPut.indexOf && ~groupPut.indexOf(activeGroup.name)) // by Array + : ( + putSortable === this || + activeGroup.checkPull(this, activeSortable, dragEl, evt) && group.checkPut(this, activeSortable, dragEl, evt) ) ) && (evt.rootEl === void 0 || evt.rootEl === this.el) // touch fallback @@ -614,6 +675,7 @@ target = _closest(evt.target, options.draggable, el); dragRect = dragEl.getBoundingClientRect(); + putSortable = this; if (revert) { _cloneHide(true); @@ -633,7 +695,6 @@ if ((el.children.length === 0) || (el.children[0] === ghostEl) || (el === evt.target) && (target = _ghostIsLast(el, evt)) ) { - if (target) { if (target.animated) { return; @@ -644,7 +705,7 @@ _cloneHide(isOwner); - if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect) !== false) { + if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt) !== false) { if (!dragEl.contains(el)) { el.appendChild(dragEl); parentEl = el; // actualization @@ -661,9 +722,9 @@ lastParentCSS = _css(target.parentNode); } + targetRect = target.getBoundingClientRect(); - var targetRect = target.getBoundingClientRect(), - width = targetRect.right - targetRect.left, + var width = targetRect.right - targetRect.left, height = targetRect.bottom - targetRect.top, floating = /left|right|inline/.test(lastCSS.cssFloat + lastCSS.display) || (lastParentCSS.display == 'flex' && lastParentCSS['flex-direction'].indexOf('row') === 0), @@ -671,7 +732,7 @@ isLong = (target.offsetHeight > dragEl.offsetHeight), halfway = (floating ? (evt.clientX - targetRect.left) / width : (evt.clientY - targetRect.top) / height) > 0.5, nextSibling = target.nextElementSibling, - moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect), + moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt), after ; @@ -784,6 +845,7 @@ } _disableDraggable(dragEl); + dragEl.style['will-change'] = ''; // Remove class's _toggleClass(dragEl, this.options.ghostClass, false); @@ -793,15 +855,16 @@ newIndex = _index(dragEl, options.draggable); if (newIndex >= 0) { - // drag from one list and drop into another - _dispatchEvent(null, parentEl, 'sort', dragEl, rootEl, oldIndex, newIndex); - _dispatchEvent(this, rootEl, 'sort', dragEl, rootEl, oldIndex, newIndex); // Add event _dispatchEvent(null, parentEl, 'add', dragEl, rootEl, oldIndex, newIndex); // Remove event _dispatchEvent(this, rootEl, 'remove', dragEl, rootEl, oldIndex, newIndex); + + // drag from one list and drop into another + _dispatchEvent(null, parentEl, 'sort', dragEl, rootEl, oldIndex, newIndex); + _dispatchEvent(this, rootEl, 'sort', dragEl, rootEl, oldIndex, newIndex); } } else { @@ -821,7 +884,8 @@ } if (Sortable.active) { - if (newIndex === null || newIndex === -1) { + /* jshint eqnull:true */ + if (newIndex == null || newIndex === -1) { newIndex = oldIndex; } @@ -837,7 +901,7 @@ this._nulling(); }, - _nulling: function () { + _nulling: function() { rootEl = dragEl = parentEl = @@ -857,6 +921,7 @@ lastEl = lastCSS = + putSortable = activeGroup = Sortable.active = null; }, @@ -1011,14 +1076,21 @@ if ((selector === '>*' && el.parentNode === ctx) || _matches(el, selector)) { return el; } - } - while (el !== ctx && (el = el.parentNode)); + /* jshint boss:true */ + } while (el = _getParentOrHost(el)); } return null; } + function _getParentOrHost(el) { + var parent = el.host; + + return (parent && parent.nodeType) ? parent : el.parentNode; + } + + function _globalDragOver(/**Event*/evt) { if (evt.dataTransfer) { evt.dataTransfer.dropEffect = 'move'; @@ -1094,8 +1166,10 @@ function _dispatchEvent(sortable, rootEl, name, targetEl, fromEl, startIndex, newIndex) { + sortable = (sortable || rootEl[expando]); + var evt = document.createEvent('Event'), - options = (sortable || rootEl[expando]).options, + options = sortable.options, onName = 'on' + name.charAt(0).toUpperCase() + name.substr(1); evt.initEvent(name, true, true); @@ -1116,7 +1190,7 @@ } - function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect) { + function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, originalEvt) { var evt, sortable = fromEl[expando], onMoveFn = sortable.options.onMove, @@ -1135,7 +1209,7 @@ fromEl.dispatchEvent(evt); if (onMoveFn) { - retVal = onMoveFn.call(sortable, evt); + retVal = onMoveFn.call(sortable, evt, originalEvt); } return retVal; @@ -1155,9 +1229,14 @@ /** @returns {HTMLElement|false} */ function _ghostIsLast(el, evt) { var lastEl = el.lastElementChild, - rect = lastEl.getBoundingClientRect(); - - return ((evt.clientY - (rect.top + rect.height) > 5) || (evt.clientX - (rect.right + rect.width) > 5)) && lastEl; // min delta + rect = lastEl.getBoundingClientRect(); + + // 5 — min delta + // abs — нельзя добавлять, а то глюки при наведении сверху + return ( + (evt.clientY - (rect.top + rect.height) > 5) || + (evt.clientX - (rect.right + rect.width) > 5) + ) && lastEl; } @@ -1251,6 +1330,15 @@ return dst; } + function _clone(el) { + return $ + ? $(el).clone(true)[0] + : (Polymer && Polymer.dom + ? Polymer.dom(el).cloneNode(true) + : el.cloneNode(true) + ); + } + // Export utils Sortable.utils = { @@ -1265,6 +1353,7 @@ throttle: _throttle, closest: _closest, toggleClass: _toggleClass, + clone: _clone, index: _index }; -- cgit v1.2.1 From 504282cf4c05a9fd9e70566c1dfcd56927f8c4e2 Mon Sep 17 00:00:00 2001 From: Hiroyuki Sato Date: Thu, 27 Oct 2016 23:23:58 +0900 Subject: Fix edit button wiki --- app/views/projects/wikis/_form.html.haml | 9 +++++++-- app/views/projects/wikis/_main_links.html.haml | 3 --- app/views/projects/wikis/edit.html.haml | 2 -- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/views/projects/wikis/_form.html.haml b/app/views/projects/wikis/_form.html.haml index 6624d5cb427..4e41a15d9f4 100644 --- a/app/views/projects/wikis/_form.html.haml +++ b/app/views/projects/wikis/_form.html.haml @@ -33,7 +33,12 @@ .form-actions - if @page && @page.persisted? = f.submit 'Save changes', class: "btn-save btn" - = link_to "Cancel", namespace_project_wiki_path(@project.namespace, @project, @page), class: "btn btn-cancel" + .pull-right + - if can?(current_user, :admin_wiki, @project) + = link_to namespace_project_wiki_path(@project.namespace, @project, @page), data: { confirm: "Are you sure you want to delete this page?"}, method: :delete, class: "btn btn-danger btn-grouped" do + Delete + = link_to "Cancel", namespace_project_wiki_path(@project.namespace, @project, @page), class: "btn btn-cancel btn-grouped" - else = f.submit 'Create page', class: "btn-create btn" - = link_to "Cancel", namespace_project_wiki_path(@project.namespace, @project, :home), class: "btn btn-cancel" + .pull-right + = link_to "Cancel", namespace_project_wiki_path(@project.namespace, @project, :home), class: "btn btn-cancel" diff --git a/app/views/projects/wikis/_main_links.html.haml b/app/views/projects/wikis/_main_links.html.haml index 4ea75dbbf0c..763c2fea39b 100644 --- a/app/views/projects/wikis/_main_links.html.haml +++ b/app/views/projects/wikis/_main_links.html.haml @@ -7,6 +7,3 @@ - if can?(current_user, :create_wiki, @project) = link_to namespace_project_wiki_edit_path(@project.namespace, @project, @page), class: "btn" do Edit - - if can?(current_user, :admin_wiki, @project) - = link_to namespace_project_wiki_path(@project.namespace, @project, @page), data: { confirm: "Are you sure you want to delete this page?"}, method: :delete, class: "btn btn-remove" do - Delete diff --git a/app/views/projects/wikis/edit.html.haml b/app/views/projects/wikis/edit.html.haml index 233538bb488..679d6018bef 100644 --- a/app/views/projects/wikis/edit.html.haml +++ b/app/views/projects/wikis/edit.html.haml @@ -19,7 +19,5 @@ - if can?(current_user, :create_wiki, @project) = link_to '#modal-new-wiki', class: "add-new-wiki btn btn-new", "data-toggle" => "modal" do New Page - = render 'main_links' - = render 'form' -- cgit v1.2.1 From 12a1668da9bfcf60040b8f9a6d74ad28a94349ad Mon Sep 17 00:00:00 2001 From: Hiroyuki Sato Date: Sat, 29 Oct 2016 10:28:58 +0900 Subject: Add a CHANGELOG entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 372ddecc98b..621f2ee8aa7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ Please view this file on the master branch, on stable branches it's out of date. - Fix extra space on Build sidebar on Firefox !7060 - Fix mobile layout issues in admin user overview page !7087 - Fix HipChat notifications rendering (airatshigapov, eisnerd) +- Remove 'Edit' button from wiki edit view !7143 (Hiroyuki Sato) - Refactor Jira service to use jira-ruby gem - Add hover to trash icon in notes !7008 (blackst0ne) - Only show one error message for an invalid email !5905 (lycoperdon) -- cgit v1.2.1 From c85c146aa2042710caddc6666ce8f9e07b2fe5ca Mon Sep 17 00:00:00 2001 From: Gauvain Pocentek Date: Sun, 23 Oct 2016 09:46:39 +0200 Subject: Add support for token attr in project hooks API The UI allows to define a token to validate payload on the target URL, this patch adds the feature to the API. --- CHANGELOG.md | 1 + doc/api/projects.md | 2 ++ lib/api/entities.rb | 2 +- lib/api/project_hooks.rb | 6 ++++-- spec/requests/api/project_hooks_spec.rb | 4 ++++ 5 files changed, 12 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14907e1546e..4e0417885d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ Please view this file on the master branch, on stable branches it's out of date. - Adds user project membership expired event to clarify why user was removed (Callum Dryden) - Trim leading and trailing whitespace on project_path (Linus Thiel) - Prevent award emoji via notes for issues/MRs authored by user (barthc) +- Adds support for the `token` attribute in project hooks API (Gauvain Pocentek) - Adds an optional path parameter to the Commits API to filter commits by path (Luis HGO) - Fix extra space on Build sidebar on Firefox !7060 - Fix mobile layout issues in admin user overview page !7087 diff --git a/doc/api/projects.md b/doc/api/projects.md index b69db90e70d..96145c0cafa 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -1139,6 +1139,7 @@ Parameters: | `pipeline_events` | boolean | no | Trigger hook on pipeline events | | `wiki_events` | boolean | no | Trigger hook on wiki events | | `enable_ssl_verification` | boolean | no | Do SSL verification when triggering the hook | +| `token` | string | no | Secret token to validate received payloads | ### Edit project hook @@ -1164,6 +1165,7 @@ Parameters: | `pipeline_events` | boolean | no | Trigger hook on pipeline events | | `wiki_events` | boolean | no | Trigger hook on wiki events | | `enable_ssl_verification` | boolean | no | Do SSL verification when triggering the hook | +| `token` | string | no | Secret token to validate received payloads | ### Delete project hook diff --git a/lib/api/entities.rb b/lib/api/entities.rb index ab9d2d54f4b..94586040fa4 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -50,7 +50,7 @@ module API expose :project_id, :push_events expose :issues_events, :merge_requests_events, :tag_push_events expose :note_events, :build_events, :pipeline_events, :wiki_page_events - expose :enable_ssl_verification + expose :enable_ssl_verification, :token end class BasicProjectDetails < Grape::Entity diff --git a/lib/api/project_hooks.rb b/lib/api/project_hooks.rb index 14f5be3b5f6..dd93a85dc54 100644 --- a/lib/api/project_hooks.rb +++ b/lib/api/project_hooks.rb @@ -47,7 +47,8 @@ module API :build_events, :pipeline_events, :wiki_page_events, - :enable_ssl_verification + :enable_ssl_verification, + :token ] @hook = user_project.hooks.new(attrs) @@ -82,7 +83,8 @@ module API :build_events, :pipeline_events, :wiki_page_events, - :enable_ssl_verification + :enable_ssl_verification, + :token ] if @hook.update_attributes attrs diff --git a/spec/requests/api/project_hooks_spec.rb b/spec/requests/api/project_hooks_spec.rb index cfcdcad74cd..53113c62996 100644 --- a/spec/requests/api/project_hooks_spec.rb +++ b/spec/requests/api/project_hooks_spec.rb @@ -36,6 +36,7 @@ describe API::API, 'ProjectHooks', api: true do expect(json_response.first['pipeline_events']).to eq(true) expect(json_response.first['wiki_page_events']).to eq(true) expect(json_response.first['enable_ssl_verification']).to eq(true) + expect(json_response.first['token']).to eq('S3cr3t') end end @@ -62,6 +63,7 @@ describe API::API, 'ProjectHooks', api: true do expect(json_response['pipeline_events']).to eq(hook.pipeline_events) expect(json_response['wiki_page_events']).to eq(hook.wiki_page_events) expect(json_response['enable_ssl_verification']).to eq(hook.enable_ssl_verification) + expect(json_response['token']).to eq(hook.token) end it "returns a 404 error if hook id is not available" do @@ -99,6 +101,7 @@ describe API::API, 'ProjectHooks', api: true do expect(json_response['pipeline_events']).to eq(false) expect(json_response['wiki_page_events']).to eq(false) expect(json_response['enable_ssl_verification']).to eq(true) + expect(json_response['token']).to eq('S3cr3t') end it "returns a 400 error if url not given" do @@ -127,6 +130,7 @@ describe API::API, 'ProjectHooks', api: true do expect(json_response['pipeline_events']).to eq(hook.pipeline_events) expect(json_response['wiki_page_events']).to eq(hook.wiki_page_events) expect(json_response['enable_ssl_verification']).to eq(hook.enable_ssl_verification) + expect(json_response['token']).to eq(hook.token) end it "returns 404 error if hook id not found" do -- cgit v1.2.1 From f77be11cb9caa62cdd4690a53c73b6d34e102148 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Tue, 1 Nov 2016 11:40:06 +0000 Subject: Ensure hook tokens are write-only in the API --- doc/api/projects.md | 4 ++-- lib/api/entities.rb | 2 +- spec/requests/api/project_hooks_spec.rb | 36 +++++++++++++++++++++++++++++---- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/doc/api/projects.md b/doc/api/projects.md index 96145c0cafa..d7b99c35b33 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -1139,7 +1139,7 @@ Parameters: | `pipeline_events` | boolean | no | Trigger hook on pipeline events | | `wiki_events` | boolean | no | Trigger hook on wiki events | | `enable_ssl_verification` | boolean | no | Do SSL verification when triggering the hook | -| `token` | string | no | Secret token to validate received payloads | +| `token` | string | no | Secret token to validate received payloads; this will not be returned in the response | ### Edit project hook @@ -1165,7 +1165,7 @@ Parameters: | `pipeline_events` | boolean | no | Trigger hook on pipeline events | | `wiki_events` | boolean | no | Trigger hook on wiki events | | `enable_ssl_verification` | boolean | no | Do SSL verification when triggering the hook | -| `token` | string | no | Secret token to validate received payloads | +| `token` | string | no | Secret token to validate received payloads; this will not be returned in the response | ### Delete project hook diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 94586040fa4..ab9d2d54f4b 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -50,7 +50,7 @@ module API expose :project_id, :push_events expose :issues_events, :merge_requests_events, :tag_push_events expose :note_events, :build_events, :pipeline_events, :wiki_page_events - expose :enable_ssl_verification, :token + expose :enable_ssl_verification end class BasicProjectDetails < Grape::Entity diff --git a/spec/requests/api/project_hooks_spec.rb b/spec/requests/api/project_hooks_spec.rb index 53113c62996..5f39329a1b8 100644 --- a/spec/requests/api/project_hooks_spec.rb +++ b/spec/requests/api/project_hooks_spec.rb @@ -36,7 +36,6 @@ describe API::API, 'ProjectHooks', api: true do expect(json_response.first['pipeline_events']).to eq(true) expect(json_response.first['wiki_page_events']).to eq(true) expect(json_response.first['enable_ssl_verification']).to eq(true) - expect(json_response.first['token']).to eq('S3cr3t') end end @@ -63,7 +62,6 @@ describe API::API, 'ProjectHooks', api: true do expect(json_response['pipeline_events']).to eq(hook.pipeline_events) expect(json_response['wiki_page_events']).to eq(hook.wiki_page_events) expect(json_response['enable_ssl_verification']).to eq(hook.enable_ssl_verification) - expect(json_response['token']).to eq(hook.token) end it "returns a 404 error if hook id is not available" do @@ -90,6 +88,7 @@ describe API::API, 'ProjectHooks', api: true do expect do post api("/projects/#{project.id}/hooks", user), url: "http://example.com", issues_events: true end.to change {project.hooks.count}.by(1) + expect(response).to have_http_status(201) expect(json_response['url']).to eq('http://example.com') expect(json_response['issues_events']).to eq(true) @@ -101,7 +100,24 @@ describe API::API, 'ProjectHooks', api: true do expect(json_response['pipeline_events']).to eq(false) expect(json_response['wiki_page_events']).to eq(false) expect(json_response['enable_ssl_verification']).to eq(true) - expect(json_response['token']).to eq('S3cr3t') + expect(json_response).not_to include('token') + end + + it "adds the token without including it in the response" do + token = "secret token" + + expect do + post api("/projects/#{project.id}/hooks", user), url: "http://example.com", token: token + end.to change {project.hooks.count}.by(1) + + expect(response).to have_http_status(201) + expect(json_response["url"]).to eq("http://example.com") + expect(json_response).not_to include("token") + + hook = project.hooks.find(json_response["id"]) + + expect(hook.url).to eq("http://example.com") + expect(hook.token).to eq(token) end it "returns a 400 error if url not given" do @@ -130,7 +146,19 @@ describe API::API, 'ProjectHooks', api: true do expect(json_response['pipeline_events']).to eq(hook.pipeline_events) expect(json_response['wiki_page_events']).to eq(hook.wiki_page_events) expect(json_response['enable_ssl_verification']).to eq(hook.enable_ssl_verification) - expect(json_response['token']).to eq(hook.token) + end + + it "adds the token without including it in the response" do + token = "secret token" + + put api("/projects/#{project.id}/hooks/#{hook.id}", user), url: "http://example.org", token: token + + expect(response).to have_http_status(200) + expect(json_response["url"]).to eq("http://example.org") + expect(json_response).not_to include("token") + + expect(hook.reload.url).to eq("http://example.org") + expect(hook.reload.token).to eq(token) end it "returns 404 error if hook id not found" do -- cgit v1.2.1 From e3f5d8fc4c2326bce38325d2c076f939e5f4ae50 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Thu, 6 Oct 2016 13:41:20 +0200 Subject: Added guide for upgrading Postgres using Slony [ci skip] --- CHANGELOG.md | 1 + doc/update/README.md | 2 + doc/update/upgrading_postgresql_using_slony.md | 482 +++++++++++++++++++++++++ 3 files changed, 485 insertions(+) create mode 100644 doc/update/upgrading_postgresql_using_slony.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 498eac9a289..6091736e6d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Please view this file on the master branch, on stable branches it's out of date. - Refactor Jira service to use jira-ruby gem - Add hover to trash icon in notes !7008 (blackst0ne) - Only show one error message for an invalid email !5905 (lycoperdon) +- Added guide describing how to upgrade PostgreSQL using Slony - Fix sidekiq stats in admin area (blackst0ne) - Created cycle analytics bundle JavaScript file - API: Fix booleans not recognized as such when using the `to_boolean` helper diff --git a/doc/update/README.md b/doc/update/README.md index 975d72164b4..837b31abb97 100644 --- a/doc/update/README.md +++ b/doc/update/README.md @@ -85,6 +85,8 @@ possible. - [MySQL installation guide](../install/database_mysql.md) contains additional information about configuring GitLab to work with a MySQL database. - [Restoring from backup after a failed upgrade](restore_after_failure.md) +- [Upgrading PostgreSQL Using Slony](upgrading_postgresql_using_slony.md), for + upgrading a PostgreSQL database with minimal downtime. [omnidocker]: http://docs.gitlab.com/omnibus/docker/README.html [source-ee]: https://gitlab.com/gitlab-org/gitlab-ee/tree/master/doc/update diff --git a/doc/update/upgrading_postgresql_using_slony.md b/doc/update/upgrading_postgresql_using_slony.md new file mode 100644 index 00000000000..f009906256e --- /dev/null +++ b/doc/update/upgrading_postgresql_using_slony.md @@ -0,0 +1,482 @@ +# Upgrading PostgreSQL Using Slony + +This guide describes the steps one can take to upgrade their PostgreSQL database +to the latest version without the need for hours of downtime. This guide assumes +you have two database servers: one database server running an older version of +PostgreSQL (e.g. 9.2.18) and one server running a newer version (e.g. 9.6.0). + +For this process we'll use a PostgreSQL replication tool called +["Slony"](http://www.slony.info/). Slony allows replication between different +PostgreSQL versions and as such can be used to upgrade a cluster with a minimal +amount of downtime. + +In various places we'll refer to the user `gitlab-psql`. This user should be the +user used to run the various PostgreSQL OS processes. If you're using a +different user (e.g. `postgres`) you should replace `gitlab-psql` with the name +of said user. This guide also assumes your database is called +`gitlabhq_production`. If you happen to use a different database name you should +change this accordingly. + +## Database Dumps + +Slony only replicates data and not any schema changes. As a result we must +ensure that all databases have the same database structure. + +To do so we'll generate a dump of our current database. This dump will only +contain the structure, not any data. To generate this dump run the following +command on your active database server: + +```bash +sudo -u gitlab-psql /opt/gitlab/embedded/bin/pg_dump -h /var/opt/gitlab/postgresql -p 5432 -U gitlab-psql -s -f /tmp/structure.sql gitlabhq_production +``` + +If you're not using GitLab's Omnibus package you may have to adjust the paths to +`pg_dump` and the PostgreSQL installation directory to match the paths of your +configuration. + +Once the structure dump is generated we also need to generate a dump for the +`schema_migrations` table. This table doesn't have any primary keys and as such +can't be replicated easily by Slony. To generate this dump run the following +command on your active database server: + +```bash +sudo -u gitlab-psql /opt/gitlab/embedded/bin/pg_dump -h /var/opt/gitlab/postgresql/ -p 5432 -U gitlab-psql -a -t schema_migrations -f /tmp/migrations.sql gitlabhq_production +``` + +Next we'll need to move these files somewhere accessible by the new database +server. The easiest way is to simply download these files to your local system: + +```bash +scp your-user@production-database-host:/tmp/*.sql /tmp +``` + +This will copy all the SQL files located in `/tmp` to your local system's +`/tmp` directory. Once copied you can safely remove the files from the database +server. + +## Installing Slony + +Slony will be used to upgrade the database without requiring long downtimes. +Slony can be downloaded from http://www.slony.info/. If you have installed +PostgreSQL using your operating system's package manager you may also be able to +install Slony using said package manager. + +When compiling Slony from source you *must* use the following commands to do so: + +```bash +./configure --prefix=/path/to/installation/directory --with-perltools --with-pgconfigdir=/path/to/directory/containing/pg_config/bin +make +make install +``` + +Omnibus users can use the following commands: + +```bash +./configure --prefix=/opt/gitlab/embedded --with-perltools --with-pgconfigdir=/opt/gitlab/embedded/bin +make +make install +``` + +This assumes you have installed GitLab into /opt/gitlab. + +To test if Slony is installed properly, run the following commands: + +```bash +test -f /opt/gitlab/embedded/bin/slonik && echo 'Slony installed' || echo 'Slony not installed' +test -f /opt/gitlab/embedded/bin/slonik_init_cluster && echo 'Slony Perl tools are available' || echo 'Slony Perl tools are not available' +/opt/gitlab/embedded/bin/slonik -v +``` + +This assumes Slony was installed to `/opt/gitlab/embedded`. If Slony was +installed properly the output of these commands will be (the mentioned "slonik" +version may be different): + +``` +Slony installed +Slony Perl tools are available +slonik version 2.2.5 +``` + +## Slony User + +Next we must set up a PostgreSQL user that Slony can use to replicate your +database. To do so, log in to your production database using `psql` using a +super user account. Once done run the following SQL queries: + +```sql +CREATE ROLE slony WITH SUPERUSER LOGIN REPLICATION ENCRYPTED PASSWORD 'password string here'; +ALTER ROLE slony SET statement_timeout TO 0; +``` + +Make sure you replace "password string here" with the actual password for the +user. A password is *required*. This user must be created on _both_ the old and +new database server using the same password. + +Once the user has been created make sure you note down the password as we will +need it later on. + +## Configuring Slony + +Now we can finally start configuring Slony. Slony uses a configuration file for +most of the work so we'll need to set this one up. This configuration file +specifies where to put log files, how Slony should connect to the databases, +etc. + +First we'll need to create some required directories and set the correct +permissions. To do so, run the following commands on both the old and new +database server: + +```bash +sudo mkdir -p /var/log/gitlab/slony /var/run/slony1 /var/opt/gitlab/postgresql/slony +sudo chown gitlab-psql:root /var/log/gitlab/slony /var/run/slony1 /var/opt/gitlab/postgresql/slony +``` + +Here `gitlab-psql` is the user used to run the PostgreSQL database processes. If +you're using a different user you should replace this with the name of said +user. + +Now that the directories are in place we can create the configuration file. For +this we can use the following template: + +```perl +if ($ENV{"SLONYNODES"}) { + require $ENV{"SLONYNODES"}; +} else { + $CLUSTER_NAME = 'slony_replication'; + $LOGDIR = '/var/log/gitlab/slony'; + $MASTERNODE = 1; + $DEBUGLEVEL = 2; + + add_node(host => 'OLD_HOST', dbname => 'gitlabhq_production', port =>5432, + user=>'slony', password=>'SLONY_PASSWORD', node=>1); + + add_node(host => 'NEW_HOST', dbname => 'gitlabhq_production', port =>5432, + user=>'slony', password=>'SLONY_PASSWORD', node=>2, parent=>1 ); +} + +$SLONY_SETS = { + "set1" => { + "set_id" => 1, + "table_id" => 1, + "sequence_id" => 1, + "pkeyedtables" => [ + TABLES + ], + }, +}; + +if ($ENV{"SLONYSET"}) { + require $ENV{"SLONYSET"}; +} + +# Please do not add or change anything below this point. +1; +``` + +In this configuration file you should replace a few placeholders before you can +use it. The following placeholders should be replaced: + +* `OLD_HOST`: the address of the old database server. +* `NEW_HOST`: the address of the new database server. +* `SLONY_PASSWORD`: the password of the Slony user created earlier. +* `TABLES`: the tables to replicate. + +The list of tables to replicate can be generated by running the following +command on your old PostgreSQL database: + +``` +sudo gitlab-psql gitlabhq_production -c "select concat('\"', schemaname, '.', tablename, '\",') from pg_catalog.pg_tables where schemaname = 'public' and tableowner = 'gitlab' and tablename != 'schema_migrations' order by tablename asc;" -t +``` + +If you're not using Omnibus you should replace `gitlab-psql` with the +appropriate path to the `psql` executable. + +The above command outputs a list of tables in a format that can be copy-pasted +directly into the above configuration file. Make sure to _replace_ `TABLES` with +this output, don't just append it below it. Once done you'll end up with +something like this: + +```perl +"pkeyedtables" => [ + "public.abuse_reports", + "public.appearances", + "public.application_settings", + ... more rows here ... +] +``` + +Once you have the configuration file generated you must install it on both the +old and new database. To do so, place it in +`/var/opt/gitlab/postgresql/slony/slon_tools.conf` (for which we created the +directory earlier on). + +Now that the configuration file is in place we can _finally_ start replicating +our database. First we must set up the schema in our new database. To do so make +sure that the SQL files we generated earlier can be found in the `/tmp` +directory of the new server. Once these files are in place start a `psql` +session on this server: + +``` +sudo gitlab-psql gitlabhq_production +``` + +Now run the following commands: + +``` +\i /tmp/structure.sql +\i /tmp/migrations.sql +``` + +To verify if the structure is in place close the session, start it again, then +run `\d`. If all went well you should see output along the lines of the +following: + +``` + List of relations + Schema | Name | Type | Owner +--------+---------------------------------------------+----------+------------- + public | abuse_reports | table | gitlab + public | abuse_reports_id_seq | sequence | gitlab + public | appearances | table | gitlab + public | appearances_id_seq | sequence | gitlab + public | application_settings | table | gitlab + public | application_settings_id_seq | sequence | gitlab + public | approvals | table | gitlab + ... more rows here ... +``` + +Now we can initialize the required tables and what not that Slony will use for +its replication process. To do so, run the following on the old database: + +``` +sudo -u gitlab-psql /opt/gitlab/embedded/bin/slonik_init_cluster --conf /var/opt/gitlab/postgresql/slony/slon_tools.conf | /opt/gitlab/embedded/bin/slonik +``` + +If all went well this will produce something along the lines of: + +``` +:10: Set up replication nodes +:13: Next: configure paths for each node/origin +:16: Replication nodes prepared +:17: Please start a slon replication daemon for each node +``` + +Next we need to start a replication node on every server. To do so, run the +following on the old database: + +``` +sudo -u gitlab-psql /opt/gitlab/embedded/bin/slon_start 1 --conf /var/opt/gitlab/postgresql/slony/slon_tools.conf +``` + +If all went well this will produce output such as: + + +``` +Invoke slon for node 1 - /opt/gitlab/embedded/bin/slon -p /var/run/slony1/slony_replication_node1.pid -s 1000 -d2 slony_replication 'host=192.168.0.7 dbname=gitlabhq_production user=slony port=5432 password=hieng8ezohHuCeiqu0leeghai4aeyahp' > /var/log/gitlab/slony/node1/gitlabhq_production-2016-10-06.log 2>&1 & +Slon successfully started for cluster slony_replication, node node1 +PID [26740] +Start the watchdog process as well... +``` + +Next we need to run the following command on the _new_ database server: + +``` +sudo -u gitlab-psql /opt/gitlab/embedded/bin/slon_start 2 --conf /var/opt/gitlab/postgresql/slony/slon_tools.conf +``` + +This will produce similar output if all went well. + +Next we need to tell the new database server what it should replicate. This can +be done by running the following command on the _new_ database server: + +``` +sudo -u gitlab-psql /opt/gitlab/embedded/bin/slonik_create_set 1 --conf /var/opt/gitlab/postgresql/slony/slon_tools.conf | /opt/gitlab/embedded/bin/slonik +``` + +This should produce output along the lines of the following: + +``` +:11: Subscription set 1 (set1) created +:12: Adding tables to the subscription set +:16: Add primary keyed table public.abuse_reports +:20: Add primary keyed table public.appearances +:24: Add primary keyed table public.application_settings +... more rows here ... +:327: Adding sequences to the subscription set +:328: All tables added +``` + +Finally we can start the replication process by running the following on the +_new_ database server: + +``` +sudo -u gitlab-psql /opt/gitlab/embedded/bin/slonik_subscribe_set 1 2 --conf /var/opt/gitlab/postgresql/slony/slon_tools.conf | /opt/gitlab/embedded/bin/slonik +``` + +This should produce the following output: + +``` +:6: Subscribed nodes to set 1 +``` + +At this point the new database server will start replicating the data of the old +database server. This process can take anywhere from a few minutes to hours, if +not days. Unfortunately Slony itself doesn't really provide a way of knowing +when the two databases are in sync. To get an estimate of the progress you can +use the following shell script: + +``` +#!/usr/bin/env bash + +set -e + +user='slony' +pass='SLONY_PASSWORD' + +function main { + while : + do + local source + local target + + source=$(PGUSER="${user}" PGPASSWORD="${pass}" /opt/gitlab/embedded/bin/psql -h OLD_HOST gitlabhq_production -c "select pg_size_pretty(pg_database_size('gitlabhq_production'));" -t -A) + target=$(PGUSER="${user}" PGPASSWORD="${pass}" /opt/gitlab/embedded/bin/psql -h NEW_HOST gitlabhq_production -c "select pg_size_pretty(pg_database_size('gitlabhq_production'));" -t -A) + + echo "$(date): ${target} of ${source}" >> progress.log + echo "$(date): ${target} of ${source}" + + sleep 60 + done +} + +main +``` + +This script will compare the sizes of the old and new database every minute and +print the result to STDOUT as well as logging it to a file. Make sure to replace +`SLONY_PASSWORD`, `OLD_HOST`, and `NEW_HOST` with the correct values. + +## Stopping Replication + +At some point the two databases are in sync. Once this is the case you'll need +to plan for a few minutes of downtime. This small downtime window is used to +stop the replication process, remove any Slony data from both databases, restart +GitLab so it can use the new database, etc. + +First, let's stop all of GitLab. Omnibus users can do so by running the +following on their GitLab server(s): + +``` +sudo gitlab-ctl stop unicorn +sudo gitlab-ctl stop sidekiq +sudo gitlab-ctl stop mailroom +``` + +If you have any other processes that use PostgreSQL you should also stop those. + +Once everything has been stopped you should update any configuration settings, +DNS records, etc so they all point to the new database. + +Once the settings have been taken care of we need to stop the replication +process. It's crucial that no new data is written to the databases at this point +as this data will be lost. + +To stop replication, run the following on both database servers: + +```bash +sudo -u gitlab-psql /opt/gitlab/embedded/bin/slon_kill --conf /var/opt/gitlab/postgresql/slony/slon_tools.conf +``` + +This will stop all the Slony processes on the host the command was executed on. + +## Resetting Sequences + +The above setup does not replicate database sequences, as such these must be +reset manually in the target database. You can use the following script for +this: + +```bash +#!/usr/bin/env bash +set -e + +function main { + local fix_sequences + local fix_owners + + fix_sequences='/tmp/fix_sequences.sql' + fix_owners='/tmp/fix_owners.sql' + + # The SQL queries were taken from + # https://wiki.postgresql.org/wiki/Fixing_Sequences + sudo gitlab-psql gitlabhq_production -t -c " + SELECT 'ALTER SEQUENCE '|| quote_ident(MIN(schema_name)) ||'.'|| quote_ident(MIN(seq_name)) + ||' OWNED BY '|| quote_ident(MIN(TABLE_NAME)) ||'.'|| quote_ident(MIN(column_name)) ||';' + FROM ( + SELECT + n.nspname AS schema_name, + c.relname AS TABLE_NAME, + a.attname AS column_name, + SUBSTRING(d.adsrc FROM E'^nextval\\(''([^'']*)''(?:::text|::regclass)?\\)') AS seq_name + FROM pg_class c + JOIN pg_attribute a ON (c.oid=a.attrelid) + JOIN pg_attrdef d ON (a.attrelid=d.adrelid AND a.attnum=d.adnum) + JOIN pg_namespace n ON (c.relnamespace=n.oid) + WHERE has_schema_privilege(n.oid,'USAGE') + AND n.nspname NOT LIKE 'pg!_%' escape '!' + AND has_table_privilege(c.oid,'SELECT') + AND (NOT a.attisdropped) + AND d.adsrc ~ '^nextval' + ) seq + GROUP BY seq_name HAVING COUNT(*)=1; + " > "${fix_owners}" + + sudo gitlab-psql gitlabhq_production -t -c " + SELECT 'SELECT SETVAL(' || + quote_literal(quote_ident(PGT.schemaname) || '.' || quote_ident(S.relname)) || + ', COALESCE(MAX(' ||quote_ident(C.attname)|| '), 1) ) FROM ' || + quote_ident(PGT.schemaname)|| '.'||quote_ident(T.relname)|| ';' + FROM pg_class AS S, + pg_depend AS D, + pg_class AS T, + pg_attribute AS C, + pg_tables AS PGT + WHERE S.relkind = 'S' + AND S.oid = D.objid + AND D.refobjid = T.oid + AND D.refobjid = C.attrelid + AND D.refobjsubid = C.attnum + AND T.relname = PGT.tablename + ORDER BY S.relname; + " > "${fix_sequences}" + + sudo gitlab-psql gitlabhq_production -f "${fix_owners}" + sudo gitlab-psql gitlabhq_production -f "${fix_sequences}" + + rm "${fix_owners}" "${fix_sequences}" +} + +main +``` + +Upload this script to the _target_ server and execute it as follows: + +```bash +bash path/to/the/script/above.sh +``` + +This will correct the ownership of sequences and reset the next value for the +`id` column to the next available value. + +## Removing Slony + +Next we need to remove all Slony related data. To do so, run the following +command on the _target_ server: + +```bash +sudo gitlab-psql gitlabhq_production -c "DROP SCHEMA _slony_replication CASCADE;" +``` + +Once done you can safely remove any Slony related files (e.g. the log +directory), and uninstall Slony if desired. At this point you can start your +GitLab instance again and if all went well it should be using your new database +server. -- cgit v1.2.1 From af5322e90b47e830e7713482854ddf6450a0d8c1 Mon Sep 17 00:00:00 2001 From: Drew Blessing Date: Tue, 2 Aug 2016 22:46:43 -0600 Subject: Add Rake task to create/repair GitLab Shell hooks symlinks --- CHANGELOG.md | 1 + doc/administration/raketasks/maintenance.md | 220 ++++++++++++++++++++++++++++ doc/development/testing.md | 36 +++++ doc/raketasks/maintenance.md | 189 +----------------------- features/steps/dashboard/help.rb | 2 +- lib/tasks/gitlab/shell.rake | 15 +- spec/rake_helper.rb | 19 +++ spec/support/rake_helpers.rb | 10 ++ spec/tasks/gitlab/shell_rake_spec.rb | 26 ++++ 9 files changed, 327 insertions(+), 191 deletions(-) create mode 100644 doc/administration/raketasks/maintenance.md create mode 100644 spec/rake_helper.rb create mode 100644 spec/support/rake_helpers.rb create mode 100644 spec/tasks/gitlab/shell_rake_spec.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index 24b9219d9cf..3a1da1bcf97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ Please view this file on the master branch, on stable branches it's out of date. - Fix: Backup restore doesn't clear cache - Optimize Event queries by removing default order - API: Fix project deploy keys 400 and 500 errors when adding an existing key. !6784 (Joshua Welsh) +- Add Rake task to create/repair GitLab Shell hooks symlinks !5634 - Add job for removal of unreferenced LFS objects from both the database and the filesystem (Frank Groeneveld) - Replace jquery.cookie plugin with js.cookie !7085 - Use MergeRequestsClosingIssues cache data on Issue#closed_by_merge_requests method diff --git a/doc/administration/raketasks/maintenance.md b/doc/administration/raketasks/maintenance.md new file mode 100644 index 00000000000..f3c2e72341f --- /dev/null +++ b/doc/administration/raketasks/maintenance.md @@ -0,0 +1,220 @@ +# Maintenance Rake Tasks + +## Gather information about GitLab and the system it runs on + +This command gathers information about your GitLab installation and the System it runs on. These may be useful when asking for help or reporting issues. + +**Omnibus Installation** + +``` +sudo gitlab-rake gitlab:env:info +``` + +**Source Installation** + +``` +bundle exec rake gitlab:env:info RAILS_ENV=production +``` + +Example output: + +``` +System information +System: Debian 7.8 +Current User: git +Using RVM: no +Ruby Version: 2.1.5p273 +Gem Version: 2.4.3 +Bundler Version: 1.7.6 +Rake Version: 10.3.2 +Sidekiq Version: 2.17.8 + +GitLab information +Version: 7.7.1 +Revision: 41ab9e1 +Directory: /home/git/gitlab +DB Adapter: postgresql +URL: https://gitlab.example.com +HTTP Clone URL: https://gitlab.example.com/some-project.git +SSH Clone URL: git@gitlab.example.com:some-project.git +Using LDAP: no +Using Omniauth: no + +GitLab Shell +Version: 2.4.1 +Repositories: /home/git/repositories/ +Hooks: /home/git/gitlab-shell/hooks/ +Git: /usr/bin/git +``` + +## Check GitLab configuration + +Runs the following rake tasks: + +- `gitlab:gitlab_shell:check` +- `gitlab:sidekiq:check` +- `gitlab:app:check` + +It will check that each component was setup according to the installation guide and suggest fixes for issues found. + +You may also have a look at our [Trouble Shooting Guide](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Trouble-Shooting-Guide). + +**Omnibus Installation** + +``` +sudo gitlab-rake gitlab:check +``` + +**Source Installation** + +``` +bundle exec rake gitlab:check RAILS_ENV=production +``` + +NOTE: Use SANITIZE=true for gitlab:check if you want to omit project names from the output. + +Example output: + +``` +Checking Environment ... + +Git configured for git user? ... yes +Has python2? ... yes +python2 is supported version? ... yes + +Checking Environment ... Finished + +Checking GitLab Shell ... + +GitLab Shell version? ... OK (1.2.0) +Repo base directory exists? ... yes +Repo base directory is a symlink? ... no +Repo base owned by git:git? ... yes +Repo base access is drwxrws---? ... yes +post-receive hook up-to-date? ... yes +post-receive hooks in repos are links: ... yes + +Checking GitLab Shell ... Finished + +Checking Sidekiq ... + +Running? ... yes + +Checking Sidekiq ... Finished + +Checking GitLab ... + +Database config exists? ... yes +Database is SQLite ... no +All migrations up? ... yes +GitLab config exists? ... yes +GitLab config outdated? ... no +Log directory writable? ... yes +Tmp directory writable? ... yes +Init script exists? ... yes +Init script up-to-date? ... yes +Redis version >= 2.0.0? ... yes + +Checking GitLab ... Finished +``` + +## Rebuild authorized_keys file + +In some case it is necessary to rebuild the `authorized_keys` file. + +**Omnibus Installation** + +``` +sudo gitlab-rake gitlab:shell:setup +``` + +**Source Installation** + +``` +cd /home/git/gitlab +sudo -u git -H bundle exec rake gitlab:shell:setup RAILS_ENV=production +``` + +``` +This will rebuild an authorized_keys file. +You will lose any data stored in authorized_keys file. +Do you want to continue (yes/no)? yes +``` + +## Clear redis cache + +If for some reason the dashboard shows wrong information you might want to +clear Redis' cache. + +**Omnibus Installation** + +``` +sudo gitlab-rake cache:clear +``` + +**Source Installation** + +``` +cd /home/git/gitlab +sudo -u git -H bundle exec rake cache:clear RAILS_ENV=production +``` + +## Precompile the assets + +Sometimes during version upgrades you might end up with some wrong CSS or +missing some icons. In that case, try to precompile the assets again. + +Note that this only applies to source installations and does NOT apply to +Omnibus packages. + +**Source Installation** + +``` +cd /home/git/gitlab +sudo -u git -H bundle exec rake assets:precompile RAILS_ENV=production +``` + +For omnibus versions, the unoptimized assets (JavaScript, CSS) are frozen at +the release of upstream GitLab. The omnibus version includes optimized versions +of those assets. Unless you are modifying the JavaScript / CSS code on your +production machine after installing the package, there should be no reason to redo +rake assets:precompile on the production machine. If you suspect that assets +have been corrupted, you should reinstall the omnibus package. + +## Tracking Deployments + +GitLab provides a Rake task that lets you track deployments in GitLab +Performance Monitoring. This Rake task simply stores the current GitLab version +in the GitLab Performance Monitoring database. + +**Omnibus Installation** + +``` +sudo gitlab-rake gitlab:track_deployment +``` + +**Source Installation** + +``` +cd /home/git/gitlab +sudo -u git -H bundle exec rake gitlab:track_deployment RAILS_ENV=production +``` + +## Create or repair repository hooks symlink + +If the GitLab shell hooks directory location changes or another circumstance +leads to the hooks symlink becoming missing or invalid, run this Rake task +to create or repair the symlinks. + +**Omnibus Installation** + +``` +sudo gitlab-rake gitlab:shell:create_hooks +``` + +**Source Installation** + +``` +cd /home/git/gitlab +sudo -u git -H bundle exec rake gitlab:shell:create_hooks RAILS_ENV=production +``` diff --git a/doc/development/testing.md b/doc/development/testing.md index 8e91ac5e3ba..b0b26ccf57a 100644 --- a/doc/development/testing.md +++ b/doc/development/testing.md @@ -132,6 +132,42 @@ Adding new Spinach scenarios is acceptable _only if_ the new scenario requires no more than one new `step` definition. If more than that is required, the test should be re-implemented using RSpec instead. +## Testing Rake Tasks + +To make testing Rake tasks a little easier, there is a helper that can be included +in lieu of the standard Spec helper. Instead of `require 'spec_helper'`, use +`require 'rake_helper'`. The helper includes `spec_helper` for you, and configures +a few other things to make testing Rake tasks easier. + +At a minimum, requiring the Rake helper will redirect `stdout`, include the +runtime task helpers, and include the `RakeHelpers` Spec support module. + +The `RakeHelpers` module exposes a `run_rake_task()` method to make +executing tasks simple. See `spec/support/rake_helpers.rb` for all available +methods. + +Example: + +```ruby +require 'rake_helper' + +describe 'gitlab:shell rake tasks' do + before do + Rake.application.rake_require 'tasks/gitlab/shell' + + stub_warn_user_is_not_gitlab + end + + describe 'install task' do + it 'invokes create_hooks task' do + expect(Rake::Task['gitlab:shell:create_hooks']).to receive(:invoke) + + run_rake_task('gitlab:shell:install') + end + end +end +``` + --- [Return to Development documentation](README.md) diff --git a/doc/raketasks/maintenance.md b/doc/raketasks/maintenance.md index 315cb56a089..266aeb7d60e 100644 --- a/doc/raketasks/maintenance.md +++ b/doc/raketasks/maintenance.md @@ -1,188 +1,3 @@ -# Maintenance +# Maintenance Rake Tasks -## Gather information about GitLab and the system it runs on - -This command gathers information about your GitLab installation and the System it runs on. These may be useful when asking for help or reporting issues. - -``` -# omnibus-gitlab -sudo gitlab-rake gitlab:env:info - -# installation from source -bundle exec rake gitlab:env:info RAILS_ENV=production -``` - -Example output: - -``` -System information -System: Debian 7.8 -Current User: git -Using RVM: no -Ruby Version: 2.1.5p273 -Gem Version: 2.4.3 -Bundler Version: 1.7.6 -Rake Version: 10.3.2 -Sidekiq Version: 2.17.8 - -GitLab information -Version: 7.7.1 -Revision: 41ab9e1 -Directory: /home/git/gitlab -DB Adapter: postgresql -URL: https://gitlab.example.com -HTTP Clone URL: https://gitlab.example.com/some-project.git -SSH Clone URL: git@gitlab.example.com:some-project.git -Using LDAP: no -Using Omniauth: no - -GitLab Shell -Version: 2.4.1 -Repositories: /home/git/repositories/ -Hooks: /home/git/gitlab-shell/hooks/ -Git: /usr/bin/git -``` - -## Check GitLab configuration - -Runs the following rake tasks: - -- `gitlab:gitlab_shell:check` -- `gitlab:sidekiq:check` -- `gitlab:app:check` - -It will check that each component was setup according to the installation guide and suggest fixes for issues found. - -You may also have a look at our [Trouble Shooting Guide](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Trouble-Shooting-Guide). - -``` -# omnibus-gitlab -sudo gitlab-rake gitlab:check - -# installation from source -bundle exec rake gitlab:check RAILS_ENV=production -``` - -NOTE: Use SANITIZE=true for gitlab:check if you want to omit project names from the output. - -Example output: - -``` -Checking Environment ... - -Git configured for git user? ... yes -Has python2? ... yes -python2 is supported version? ... yes - -Checking Environment ... Finished - -Checking GitLab Shell ... - -GitLab Shell version? ... OK (1.2.0) -Repo base directory exists? ... yes -Repo base directory is a symlink? ... no -Repo base owned by git:git? ... yes -Repo base access is drwxrws---? ... yes -post-receive hook up-to-date? ... yes -post-receive hooks in repos are links: ... yes - -Checking GitLab Shell ... Finished - -Checking Sidekiq ... - -Running? ... yes - -Checking Sidekiq ... Finished - -Checking GitLab ... - -Database config exists? ... yes -Database is SQLite ... no -All migrations up? ... yes -GitLab config exists? ... yes -GitLab config outdated? ... no -Log directory writable? ... yes -Tmp directory writable? ... yes -Init script exists? ... yes -Init script up-to-date? ... yes -Redis version >= 2.0.0? ... yes - -Checking GitLab ... Finished -``` - -## Rebuild authorized_keys file - -In some case it is necessary to rebuild the `authorized_keys` file. - -For Omnibus-packages: -``` -sudo gitlab-rake gitlab:shell:setup -``` - -For installations from source: -``` -cd /home/git/gitlab -sudo -u git -H bundle exec rake gitlab:shell:setup RAILS_ENV=production -``` - -``` -This will rebuild an authorized_keys file. -You will lose any data stored in authorized_keys file. -Do you want to continue (yes/no)? yes -``` - -## Clear redis cache - -If for some reason the dashboard shows wrong information you might want to -clear Redis' cache. - -For Omnibus-packages: -``` -sudo gitlab-rake cache:clear -``` - -For installations from source: -``` -cd /home/git/gitlab -sudo -u git -H bundle exec rake cache:clear RAILS_ENV=production -``` - -## Precompile the assets - -Sometimes during version upgrades you might end up with some wrong CSS or -missing some icons. In that case, try to precompile the assets again. - -Note that this only applies to source installations and does NOT apply to -omnibus packages. - -For installations from source: -``` -cd /home/git/gitlab -sudo -u git -H bundle exec rake assets:precompile RAILS_ENV=production -``` - -For omnibus versions, the unoptimized assets (JavaScript, CSS) are frozen at -the release of upstream GitLab. The omnibus version includes optimized versions -of those assets. Unless you are modifying the JavaScript / CSS code on your -production machine after installing the package, there should be no reason to redo -rake assets:precompile on the production machine. If you suspect that assets -have been corrupted, you should reinstall the omnibus package. - -## Tracking Deployments - -GitLab provides a Rake task that lets you track deployments in GitLab -Performance Monitoring. This Rake task simply stores the current GitLab version -in the GitLab Performance Monitoring database. - -For Omnibus-packages: - -``` -sudo gitlab-rake gitlab:track_deployment -``` - -For installations from source: - -``` -cd /home/git/gitlab -sudo -u git -H bundle exec rake gitlab:track_deployment RAILS_ENV=production -``` +This document was moved to [administration/raketasks/maintenance](../administration/raketasks/maintenance.md). diff --git a/features/steps/dashboard/help.rb b/features/steps/dashboard/help.rb index 9c94dc70df0..3c5bf44c538 100644 --- a/features/steps/dashboard/help.rb +++ b/features/steps/dashboard/help.rb @@ -8,7 +8,7 @@ class Spinach::Features::DashboardHelp < Spinach::FeatureSteps end step 'I visit the "Rake Tasks" help page' do - visit help_page_path("raketasks/maintenance") + visit help_page_path("administration/raketasks/maintenance") end step 'I should see "Rake Tasks" page markdown rendered' do diff --git a/lib/tasks/gitlab/shell.rake b/lib/tasks/gitlab/shell.rake index 210899882b4..58761a129d4 100644 --- a/lib/tasks/gitlab/shell.rake +++ b/lib/tasks/gitlab/shell.rake @@ -63,11 +63,11 @@ namespace :gitlab do # Launch installation process system(*%W(bin/install) + repository_storage_paths_args) - - # (Re)create hooks - system(*%W(bin/create-hooks) + repository_storage_paths_args) end + # (Re)create hooks + Rake::Task['gitlab:shell:create_hooks'].invoke + # Required for debian packaging with PKGR: Setup .ssh/environment with # the current PATH, so that the correct ruby version gets loaded # Requires to set "PermitUserEnvironment yes" in sshd config (should not @@ -102,6 +102,15 @@ namespace :gitlab do end end end + + desc 'Create or repair repository hooks symlink' + task create_hooks: :environment do + warn_user_is_not_gitlab + + puts 'Creating/Repairing hooks symlinks for all repositories' + system(*%W(#{Gitlab.config.gitlab_shell.path}/bin/create-hooks) + repository_storage_paths_args) + puts 'done'.color(:green) + end end def setup diff --git a/spec/rake_helper.rb b/spec/rake_helper.rb new file mode 100644 index 00000000000..9b5b4bf9fea --- /dev/null +++ b/spec/rake_helper.rb @@ -0,0 +1,19 @@ +require 'spec_helper' +require 'rake' + +RSpec.configure do |config| + config.include RakeHelpers + + # Redirect stdout so specs don't have so much noise + config.before(:all) do + $stdout = StringIO.new + + Rake.application.rake_require 'tasks/gitlab/task_helpers' + Rake::Task.define_task :environment + end + + # Reset stdout + config.after(:all) do + $stdout = STDOUT + end +end diff --git a/spec/support/rake_helpers.rb b/spec/support/rake_helpers.rb new file mode 100644 index 00000000000..52d80c69835 --- /dev/null +++ b/spec/support/rake_helpers.rb @@ -0,0 +1,10 @@ +module RakeHelpers + def run_rake_task(task_name) + Rake::Task[task_name].reenable + Rake.application.invoke_task task_name + end + + def stub_warn_user_is_not_gitlab + allow_any_instance_of(Object).to receive(:warn_user_is_not_gitlab) + end +end diff --git a/spec/tasks/gitlab/shell_rake_spec.rb b/spec/tasks/gitlab/shell_rake_spec.rb new file mode 100644 index 00000000000..226d34fe2c9 --- /dev/null +++ b/spec/tasks/gitlab/shell_rake_spec.rb @@ -0,0 +1,26 @@ +require 'rake_helper' + +describe 'gitlab:shell rake tasks' do + before do + Rake.application.rake_require 'tasks/gitlab/shell' + + stub_warn_user_is_not_gitlab + end + + describe 'install task' do + it 'invokes create_hooks task' do + expect(Rake::Task['gitlab:shell:create_hooks']).to receive(:invoke) + + run_rake_task('gitlab:shell:install') + end + end + + describe 'create_hooks task' do + it 'calls gitlab-shell bin/create_hooks' do + expect_any_instance_of(Object).to receive(:system) + .with("#{Gitlab.config.gitlab_shell.path}/bin/create-hooks", *repository_storage_paths_args) + + run_rake_task('gitlab:shell:create_hooks') + end + end +end -- cgit v1.2.1 From e8e0461ee0536434c516b6651719a08d25cbdddd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Tue, 1 Nov 2016 21:46:37 +0000 Subject: remove extra spaces from app/workers/post_receive.rb --- app/workers/post_receive.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb index eee0ca12af9..2fff6b0105d 100644 --- a/app/workers/post_receive.rb +++ b/app/workers/post_receive.rb @@ -16,7 +16,7 @@ class PostReceive post_received = Gitlab::GitPostReceive.new(repo_path, identifier, changes) if post_received.project.nil? - log("Triggered hook for non-existing project with full path \"#{repo_path} \"") + log("Triggered hook for non-existing project with full path \"#{repo_path}\"") return false end @@ -25,7 +25,7 @@ class PostReceive elsif post_received.regular_project? process_project_changes(post_received) else - log("Triggered hook for unidentifiable repository type with full path \"#{repo_path} \"") + log("Triggered hook for unidentifiable repository type with full path \"#{repo_path}\"") false end end @@ -37,7 +37,7 @@ class PostReceive @user ||= post_received.identify(newrev) unless @user - log("Triggered hook for non-existing user \"#{post_received.identifier} \"") + log("Triggered hook for non-existing user \"#{post_received.identifier}\"") return false end -- cgit v1.2.1 From afc465d9ecce58df92b436d2ebf9732147e9a0cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Tue, 1 Nov 2016 22:00:34 +0000 Subject: Update gitlab.yml.example --- config/gitlab.yml.example | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 3451b68cea5..699ab6075b6 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -432,7 +432,9 @@ production: &base ## Repositories settings repositories: # Paths where repositories can be stored. Give the canonicalized absolute pathname. - # NOTE: REPOS PATHS MUST NOT CONTAIN ANY SYMLINK!!! + # IMPORTANT: None of the path components may be symlink, because + # gitlab-shell invokes Dir.pwd inside the repository path and that results + # real path not the symlink. storages: # You must have at least a `default` storage path. default: /home/git/repositories/ -- cgit v1.2.1 From c7dd62a0dae8a38a6104b2e4f771a7b324ac927b Mon Sep 17 00:00:00 2001 From: Daniel Axelrod Date: Tue, 1 Nov 2016 23:59:32 +0000 Subject: Fix gdb backtrace command Correct the command to get a gdb backtrace from all threads. `apply` is not a valid gdb command. See https://sourceware.org/gdb/onlinedocs/gdb/Threads.html#Threads . --- doc/administration/troubleshooting/debug.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/administration/troubleshooting/debug.md b/doc/administration/troubleshooting/debug.md index d8dce4388e1..6f1356ddf8f 100644 --- a/doc/administration/troubleshooting/debug.md +++ b/doc/administration/troubleshooting/debug.md @@ -107,7 +107,7 @@ downtime. Otherwise skip to the next section. 1. To see the current threads, run: ``` - apply all thread bt + thread apply all bt ``` 1. Once you're done debugging with `gdb`, be sure to detach from the process and exit: -- cgit v1.2.1 From 6ed2434afab6dcdfb8f01f757e757dd1781c4713 Mon Sep 17 00:00:00 2001 From: Daniel Axelrod Date: Wed, 2 Nov 2016 00:45:15 +0000 Subject: Replace MR Description Format links Replace links to the `Merge request description format` section with up-to-date instructions on using the MR template built into the UI. The `Merge request description format` section was removed in 2f7e28d1, but links were left in the table of contents and in the MR description instructions. --- CONTRIBUTING.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b4635e50c28..89d6b3f5bdf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,7 +19,6 @@ - [Technical debt](#technical-debt) - [Merge requests](#merge-requests) - [Merge request guidelines](#merge-request-guidelines) - - [Merge request description format](#merge-request-description-format) - [Contribution acceptance criteria](#contribution-acceptance-criteria) - [Changes for Stable Releases](#changes-for-stable-releases) - [Definition of done](#definition-of-done) @@ -262,8 +261,11 @@ request is as follows: 1. Submit a merge request (MR) to the `master` branch 1. The MR title should describe the change you want to make 1. The MR description should give a motive for your change and the method you - used to achieve it, see the [merge request description format] - (#merge-request-description-format) + used to achieve it. + 1. If you are contributing code, fill in the template already provided in the + "Description" field. + 1. If you are contributing documentation, choose `Documentation` from the + "Choose a template" menu and fill in the template. 1. If the MR changes the UI it should include *Before* and *After* screenshots 1. If the MR changes CSS classes please include the list of affected pages, `grep css-class ./app -R` -- cgit v1.2.1 From efc9ca6d71cb5c2351584e3edb289ec355521895 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 2 Nov 2016 08:58:11 +0000 Subject: GitLab 8.13 not 13 --- doc/integration/jira.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/integration/jira.md b/doc/integration/jira.md index cf1557ddc44..2e31fd994de 100644 --- a/doc/integration/jira.md +++ b/doc/integration/jira.md @@ -135,7 +135,7 @@ password as they will be needed when configuring GitLab in the next section. JIRA configuration in GitLab is done via a project's **Services**. -#### GitLab 13.0 with JIRA v1000.x +#### GitLab 8.13.0 with JIRA v1000.x To enable JIRA integration in a project, navigate to the project's and open the context menu clicking on the top right gear icon, then go to @@ -160,7 +160,7 @@ with the linked JIRA project. #### GitLab 6.x-7.7 with JIRA v6.x -_**Note:** GitLab versions 13.0 and up contain various integration improvements. +_**Note:** GitLab versions 8.13.0 and up contain various integration improvements. We strongly recommend upgrading._ In `gitlab.yml` enable the JIRA issue tracker section by -- cgit v1.2.1 From 697cd511f2ddd47614c2c2a82f466a823443edb8 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Wed, 2 Nov 2016 09:49:21 +0000 Subject: Removed z-index for filters on issue boards --- app/assets/stylesheets/pages/boards.scss | 5 ----- 1 file changed, 5 deletions(-) diff --git a/app/assets/stylesheets/pages/boards.scss b/app/assets/stylesheets/pages/boards.scss index ef6833c9845..df23e27be71 100644 --- a/app/assets/stylesheets/pages/boards.scss +++ b/app/assets/stylesheets/pages/boards.scss @@ -45,11 +45,6 @@ .page-with-sidebar { padding-bottom: 0; } - - .issues-filters { - position: relative; - z-index: 999999; - } } .boards-app { -- cgit v1.2.1 From 1ad62d9684ce5e04d96caf5094610a7fc2436f60 Mon Sep 17 00:00:00 2001 From: winniehell Date: Wed, 2 Nov 2016 11:36:44 +0100 Subject: Check that JavaScript file names match convention (!7238) --- .eslintrc | 6 ++++++ CHANGELOG.md | 1 + package.json | 1 + 3 files changed, 8 insertions(+) diff --git a/.eslintrc b/.eslintrc index 16eb18ecba2..b58007d90a9 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,5 +1,11 @@ { "extends": "airbnb", + "plugins": [ + "filenames" + ], + "rules": { + "filenames/match-regex": [2, "^[a-z_]+$"] + }, "globals": { "$": false, "_": false, diff --git a/CHANGELOG.md b/CHANGELOG.md index 11b6de57cf3..024e84f1ac1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ Please view this file on the master branch, on stable branches it's out of date. - Removed delete branch tooltip !6954 - Stop unauthorized users dragging on milestone page (blackst0ne) - Restore issue boards welcome message when a project is created !6899 +- Check that JavaScript file names match convention !7238 (winniehell) - Do not show tooltip for active element !7105 (winniehell) - Escape ref and path for relative links !6050 (winniehell) - Fixed link typo on /help/ui to Alerts section. !6915 (Sam Rose) diff --git a/package.json b/package.json index d440307bd10..a303c9c1eac 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "devDependencies": { "eslint": "^3.1.1", "eslint-config-airbnb": "^12.0.0", + "eslint-plugin-filenames": "^1.1.0", "eslint-plugin-import": "^2.0.1", "eslint-plugin-jsx-a11y": "^2.2.3", "eslint-plugin-react": "^6.4.1" -- cgit v1.2.1 From 71f2d7f7aab8b368b971d2199929a7d93c3a44b5 Mon Sep 17 00:00:00 2001 From: winniehell Date: Wed, 2 Nov 2016 11:21:09 +0100 Subject: Make ESLint ignore instrumented files for coverage analysis (!7236) --- .eslintignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.eslintignore b/.eslintignore index 453747e14e1..a57137b4d70 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,3 +1,4 @@ +/coverage-javascript/ /public/ /tmp/ /vendor/ -- cgit v1.2.1 From 6419fe366a83314258f24d4ee2852a461b590c61 Mon Sep 17 00:00:00 2001 From: Brian Kintz Date: Thu, 1 Sep 2016 01:50:27 -0400 Subject: Use the server's base URL without relative URL part when creating links in JIRA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- CHANGELOG.md | 1 + app/models/project_services/jira_service.rb | 2 +- spec/models/project_services/jira_service_spec.rb | 22 ++++++++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6ddc580f7e..840640a23e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ Please view this file on the master branch, on stable branches it's out of date. - Do not show tooltip for active element !7105 (winniehell) - Escape ref and path for relative links !6050 (winniehell) - Fixed link typo on /help/ui to Alerts section. !6915 (Sam Rose) +- Fix broken issue/merge request links in JIRA comments. !6143 (Brian Kintz) - Fix filtering of milestones with quotes in title (airatshigapov) - Refactor less readable existance checking code from CoffeeScript !6289 (jlogandavison) - Update mail_room and enable sentinel support to Reply By Email (!7101) diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb index 5bcf199d468..0a493b7a12b 100644 --- a/app/models/project_services/jira_service.rb +++ b/app/models/project_services/jira_service.rb @@ -237,7 +237,7 @@ class JiraService < IssueTrackerService end def resource_url(resource) - "#{Settings.gitlab['url'].chomp("/")}#{resource}" + "#{Settings.gitlab.base_url.chomp("/")}#{resource}" end def build_entity_url(entity_name, entity_id) diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb index a9f637147d1..a3e9adae4e2 100644 --- a/spec/models/project_services/jira_service_spec.rb +++ b/spec/models/project_services/jira_service_spec.rb @@ -1,4 +1,5 @@ require 'spec_helper' +include Gitlab::Routing.url_helpers describe JiraService, models: true do describe "Associations" do @@ -66,6 +67,27 @@ describe JiraService, models: true do ).once end + it "references the GitLab commit/merge request" do + @jira_service.execute(merge_request, ExternalIssue.new("JIRA-123", project)) + + expect(WebMock).to have_requested(:post, @comment_url).with( + body: /#{Gitlab.config.gitlab.url}\/#{project.path_with_namespace}\/commit\/#{merge_request.diff_head_sha}/ + ).once + end + + it "references the GitLab commit/merge request (relative URL)" do + stub_config_setting(relative_url_root: '/gitlab') + stub_config_setting(url: Settings.send(:build_gitlab_url)) + + Project.default_url_options[:script_name] = "/gitlab" + + @jira_service.execute(merge_request, ExternalIssue.new("JIRA-123", project)) + + expect(WebMock).to have_requested(:post, @comment_url).with( + body: /#{Gitlab.config.gitlab.url}\/#{project.path_with_namespace}\/commit\/#{merge_request.diff_head_sha}/ + ).once + end + it "calls the api with jira_issue_transition_id" do @jira_service.jira_issue_transition_id = 'this-is-a-custom-id' @jira_service.execute(merge_request, ExternalIssue.new("JIRA-123", project)) -- cgit v1.2.1 From c1ee879c66ea81b28d36d1c1f0b34ead296cffbf Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Wed, 2 Nov 2016 15:16:19 +0000 Subject: Update examples in changelog docs to use single quotes around title [ci skip] --- doc/development/changelog.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/development/changelog.md b/doc/development/changelog.md index f10f4c6722a..d08c476e9d6 100644 --- a/doc/development/changelog.md +++ b/doc/development/changelog.md @@ -36,7 +36,7 @@ automatically. Its simplest usage is to provide the value for `title`: ```text -$ bin/changelog Hey DZ, I added a feature to GitLab! +$ bin/changelog 'Hey DZ, I added a feature to GitLab!' create changelogs/unreleased/my-feature.yml --- title: Hey DZ, I added a feature to GitLab! @@ -85,7 +85,7 @@ Use the **`--merge-request`** or **`-m`** argument to provide the `merge_request` value: ```text -$ bin/changelog Hey DZ, I added a feature to GitLab! -m 1983 +$ bin/changelog 'Hey DZ, I added a feature to GitLab!' -m 1983 create changelogs/unreleased/feature-hey-dz.yml --- title: Hey DZ, I added a feature to GitLab! @@ -118,7 +118,7 @@ Use the **`--git-username`** or **`-u`** argument to automatically fill in the $ git config user.name Jane Doe -$ bin/changelog --u Hey DZ, I added a feature to GitLab! +$ bin/changelog --u 'Hey DZ, I added a feature to GitLab!' create changelogs/unreleased/feature-hey-dz.yml --- title: Hey DZ, I added a feature to GitLab! -- cgit v1.2.1 From 895673733a5712ee4b69c84195a1d717a72fc032 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Wed, 2 Nov 2016 22:15:20 +0000 Subject: Add a `--force` option to bin/changelog --- bin/changelog | 8 +++++++- doc/development/changelog.md | 20 +++++++++++++++++++- spec/bin/changelog_spec.rb | 12 ++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/bin/changelog b/bin/changelog index a0d1ad2d730..2cd337af778 100755 --- a/bin/changelog +++ b/bin/changelog @@ -12,6 +12,7 @@ Options = Struct.new( :amend, :author, :dry_run, + :force, :merge_request, :title ) @@ -29,6 +30,10 @@ class ChangelogOptionParser options.amend = value end + opts.on('-f', '--force', 'Overwrite an existing entry') do |value| + options.force = value + end + opts.on('-m', '--merge-request [integer]', Integer, 'Merge Request ID') do |value| options.merge_request = value end @@ -111,8 +116,9 @@ class ChangelogEntry def assert_new_file! return unless File.exist?(file_path) + return if options.force - fail_with "#{file_path} already exists!" + fail_with "#{file_path} already exists! Use `--force` to overwrite." end def assert_title! diff --git a/doc/development/changelog.md b/doc/development/changelog.md index d08c476e9d6..390eb549d0b 100644 --- a/doc/development/changelog.md +++ b/doc/development/changelog.md @@ -46,13 +46,14 @@ author: The entry filename is based on the name of the current Git branch. If you run the command above on a branch called `feature/hey-dz`, it will generate a -`changelogs/unreleased/feature-hey-dz` file. +`changelogs/unreleased/feature-hey-dz.yml` file. ### Arguments | Argument | Shorthand | Purpose | | ----------------- | --------- | --------------------------------------------- | | `--amend` | | Amend the previous commit | +| `--force` | `-f` | Overwrite an existing entry | | `--merge-request` | `-m` | Merge Request ID | | `--dry-run` | `-n` | Don't actually write anything, just print | | `--git-username` | `-u` | Use Git user.name configuration as the author | @@ -79,6 +80,23 @@ merge_request: author: ``` +#### `--force` or `-f` + +Use **`--force`** or **`-f`** to overwrite an existing changelog entry if it +already exists. + +```text +$ bin/changelog 'Hey DZ, I added a feature to GitLab!' +error changelogs/unreleased/feature-hey-dz.yml already exists! Use `--force` to overwrite. + +$ bin/changelog 'Hey DZ, I added a feature to GitLab!' --force +create changelogs/unreleased/feature-hey-dz.yml +--- +title: Hey DZ, I added a feature to GitLab! +merge_request: 1983 +author: +``` + #### `--merge-request` or `-m` Use the **`--merge-request`** or **`-m`** argument to provide the diff --git a/spec/bin/changelog_spec.rb b/spec/bin/changelog_spec.rb index da167dc570f..8c8bc1b0f1c 100644 --- a/spec/bin/changelog_spec.rb +++ b/spec/bin/changelog_spec.rb @@ -10,6 +10,18 @@ describe 'bin/changelog' do expect(options.amend).to eq true end + it 'parses --force' do + options = described_class.parse(%w[foo --force bar]) + + expect(options.force).to eq true + end + + it 'parses -f' do + options = described_class.parse(%w[foo -f bar]) + + expect(options.force).to eq true + end + it 'parses --merge-request' do options = described_class.parse(%w[foo --merge-request 1234 bar]) -- cgit v1.2.1