2025-05-05 09:29:55 +02:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
2013-09-05 14:59:15 +01:00
|
|
|
#-- copyright
|
2020-01-15 11:31:26 +01:00
|
|
|
# OpenProject is an open source project management software.
|
2024-07-30 13:42:36 +02:00
|
|
|
# Copyright (C) the OpenProject GmbH
|
2013-09-05 14:59:15 +01:00
|
|
|
#
|
|
|
|
|
# This program is free software; you can redistribute it and/or
|
|
|
|
|
# modify it under the terms of the GNU General Public License version 3.
|
|
|
|
|
#
|
2013-09-16 17:59:31 +02:00
|
|
|
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
2021-01-13 17:47:45 +01:00
|
|
|
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
2013-09-16 17:59:31 +02:00
|
|
|
# Copyright (C) 2010-2013 the ChiliProject Team
|
|
|
|
|
#
|
|
|
|
|
# This program is free software; you can redistribute it and/or
|
|
|
|
|
# modify it under the terms of the GNU General Public License
|
|
|
|
|
# as published by the Free Software Foundation; either version 2
|
|
|
|
|
# of the License, or (at your option) any later version.
|
|
|
|
|
#
|
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
|
#
|
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
|
# along with this program; if not, write to the Free Software
|
|
|
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
|
#
|
2021-09-02 21:49:06 +02:00
|
|
|
# See COPYRIGHT and LICENSE files for more details.
|
2013-09-05 14:59:15 +01:00
|
|
|
#++
|
|
|
|
|
|
|
|
|
|
require "spec_helper"
|
|
|
|
|
|
2023-05-31 12:15:15 +02:00
|
|
|
RSpec.describe RepositoriesController do
|
2026-02-03 10:56:15 +01:00
|
|
|
let(:project) { create(:project) }
|
|
|
|
|
let(:user) { create(:user, member_with_permissions: { project => permissions }) }
|
|
|
|
|
let(:permissions) { [] }
|
2015-07-16 16:01:37 +02:00
|
|
|
let (:url) { "file:///tmp/something/does/not/exist.svn" }
|
2015-03-12 20:44:41 +01:00
|
|
|
|
|
|
|
|
let(:repository) do
|
2015-08-19 12:09:47 +02:00
|
|
|
allow(Setting).to receive(:enabled_scm).and_return(["subversion"])
|
2022-01-24 19:22:35 +01:00
|
|
|
repo = build_stubbed(:repository_subversion,
|
2022-02-02 21:48:06 +01:00
|
|
|
scm_type: "local",
|
|
|
|
|
url:,
|
|
|
|
|
project:)
|
2026-02-09 15:26:41 +01:00
|
|
|
|
|
|
|
|
allow(repo).to receive_messages({
|
|
|
|
|
default_branch: "master",
|
|
|
|
|
branches: ["master"],
|
|
|
|
|
save: true
|
|
|
|
|
})
|
2015-03-12 20:44:41 +01:00
|
|
|
|
|
|
|
|
repo
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
before do
|
2015-10-02 12:01:17 +02:00
|
|
|
login_as(user)
|
2026-02-03 10:56:15 +01:00
|
|
|
|
2026-02-09 15:26:41 +01:00
|
|
|
visible_relation = instance_double(Project.all.class).as_null_object
|
2026-02-03 10:56:15 +01:00
|
|
|
allow(Project).to receive(:visible).and_return(visible_relation)
|
|
|
|
|
allow(visible_relation).to receive(:find).and_return(project)
|
|
|
|
|
|
2015-03-12 20:44:41 +01:00
|
|
|
allow(project).to receive(:repository).and_return(repository)
|
|
|
|
|
end
|
|
|
|
|
|
2015-06-29 13:16:14 +02:00
|
|
|
describe "manages the repository" do
|
2026-02-03 10:56:15 +01:00
|
|
|
let(:permissions) { [:manage_repository] }
|
2015-03-12 20:44:41 +01:00
|
|
|
|
|
|
|
|
before do
|
|
|
|
|
# authorization checked in spec/permissions/manage_repositories_spec.rb
|
|
|
|
|
allow(controller).to receive(:authorize).and_return(true)
|
|
|
|
|
end
|
|
|
|
|
|
2015-07-20 08:32:25 +02:00
|
|
|
context "with #destroy" do
|
|
|
|
|
before do
|
|
|
|
|
allow(repository).to receive(:destroy).and_return(true)
|
2018-01-22 08:44:15 +01:00
|
|
|
delete :destroy, params: { project_id: project.id }, xhr: true
|
2015-07-20 08:32:25 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "redirects to settings" do
|
2021-11-01 13:58:57 +01:00
|
|
|
expect(response).to redirect_to project_settings_repository_path(project.identifier)
|
2015-07-20 08:32:25 +02:00
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2015-06-29 13:16:14 +02:00
|
|
|
context "with #update" do
|
2015-03-12 20:44:41 +01:00
|
|
|
before do
|
2018-01-22 08:44:15 +01:00
|
|
|
put :update, params: { project_id: project.id }, xhr: true
|
2015-06-29 13:16:14 +02:00
|
|
|
end
|
|
|
|
|
|
2018-03-05 07:40:01 +01:00
|
|
|
it "redirects to settings" do
|
2021-11-01 13:58:57 +01:00
|
|
|
expect(response).to redirect_to project_settings_repository_path(project.identifier)
|
2018-03-05 07:40:01 +01:00
|
|
|
end
|
2015-06-29 13:16:14 +02:00
|
|
|
end
|
2015-03-12 20:44:41 +01:00
|
|
|
|
2015-06-29 13:16:14 +02:00
|
|
|
context "with #create" do
|
|
|
|
|
before do
|
2017-07-19 21:17:37 +02:00
|
|
|
post :create,
|
|
|
|
|
params: {
|
2018-01-22 08:44:15 +01:00
|
|
|
project_id: project.id,
|
2017-07-19 21:17:37 +02:00
|
|
|
scm_vendor: "subversion",
|
|
|
|
|
scm_type: "local",
|
|
|
|
|
url: "file:///tmp/repo.svn/"
|
2018-03-05 07:40:01 +01:00
|
|
|
}
|
2015-03-12 20:44:41 +01:00
|
|
|
end
|
|
|
|
|
|
2018-03-05 07:40:01 +01:00
|
|
|
it "redirects to settings" do
|
2021-11-01 13:58:57 +01:00
|
|
|
expect(response).to redirect_to project_settings_repository_path(project.identifier)
|
2015-06-29 13:16:14 +02:00
|
|
|
end
|
2015-03-12 20:44:41 +01:00
|
|
|
end
|
2013-09-05 16:51:02 +01:00
|
|
|
end
|
2013-09-05 14:59:15 +01:00
|
|
|
|
2015-07-23 09:48:44 +02:00
|
|
|
describe "with empty repository" do
|
2026-02-03 10:56:15 +01:00
|
|
|
let(:permissions) { [:browse_repository] }
|
2021-11-01 13:58:57 +01:00
|
|
|
|
2015-07-23 09:48:44 +02:00
|
|
|
before do
|
|
|
|
|
allow(repository.scm)
|
|
|
|
|
.to receive(:check_availability!)
|
2020-02-11 08:04:46 +01:00
|
|
|
.and_raise(OpenProject::SCM::Exceptions::SCMEmpty)
|
2015-07-23 09:48:44 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "with #show" do
|
|
|
|
|
before do
|
2016-10-17 10:21:42 +02:00
|
|
|
get :show, params: { project_id: project.identifier }
|
2015-07-23 09:48:44 +02:00
|
|
|
end
|
2022-05-31 11:55:27 +02:00
|
|
|
|
2015-07-23 09:48:44 +02:00
|
|
|
it "renders an empty warning view" do
|
|
|
|
|
expect(response).to render_template "repositories/empty"
|
|
|
|
|
expect(response.code).to eq("200")
|
|
|
|
|
end
|
|
|
|
|
end
|
2015-08-20 22:47:09 +02:00
|
|
|
|
|
|
|
|
context "with #show and checkout" do
|
|
|
|
|
render_views
|
|
|
|
|
|
2021-02-11 16:02:18 +01:00
|
|
|
let(:checkout_hash) do
|
2015-08-20 22:47:09 +02:00
|
|
|
{
|
|
|
|
|
"subversion" => { "enabled" => "1",
|
|
|
|
|
"text" => "foo",
|
2021-02-11 16:02:18 +01:00
|
|
|
"base_url" => "http://localhost" }
|
2015-08-20 22:47:09 +02:00
|
|
|
}
|
2021-02-11 16:02:18 +01:00
|
|
|
end
|
2015-08-20 22:47:09 +02:00
|
|
|
|
|
|
|
|
before do
|
|
|
|
|
allow(Setting).to receive(:repository_checkout_data).and_return(checkout_hash)
|
2016-10-17 10:21:42 +02:00
|
|
|
get :show, params: { project_id: project.identifier }
|
2015-08-20 22:47:09 +02:00
|
|
|
end
|
2015-08-20 23:01:25 +02:00
|
|
|
|
|
|
|
|
it "renders an empty warning view" do
|
|
|
|
|
expect(response).to render_template "repositories/empty"
|
|
|
|
|
expect(response).to render_template partial: "repositories/_checkout_instructions"
|
|
|
|
|
expect(response.code).to eq("200")
|
|
|
|
|
end
|
2015-08-20 22:47:09 +02:00
|
|
|
end
|
2015-07-23 09:48:44 +02:00
|
|
|
end
|
|
|
|
|
|
2017-06-19 12:55:28 +02:00
|
|
|
describe "with subversion repository" do
|
2016-02-24 10:37:19 +01:00
|
|
|
with_subversion_repository do |repo_dir|
|
|
|
|
|
let(:root_url) { repo_dir }
|
|
|
|
|
let(:url) { "file://#{root_url}" }
|
|
|
|
|
|
2021-02-11 16:02:18 +01:00
|
|
|
let(:repository) do
|
2022-01-24 19:22:35 +01:00
|
|
|
create(:repository_subversion, project:, url:, root_url: url)
|
2021-02-11 16:02:18 +01:00
|
|
|
end
|
2015-07-16 16:01:37 +02:00
|
|
|
|
|
|
|
|
describe "commits per author graph" do
|
|
|
|
|
before do
|
2016-10-17 10:21:42 +02:00
|
|
|
get :graph, params: { project_id: project.identifier, graph: "commits_per_author" }
|
2015-07-16 16:01:37 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "requested by an authorized user" do
|
2026-02-03 10:56:15 +01:00
|
|
|
let(:permissions) { %i[browse_repository view_commit_author_statistics] }
|
2015-07-16 16:01:37 +02:00
|
|
|
|
|
|
|
|
it "is successful" do
|
2018-11-23 15:06:32 +01:00
|
|
|
expect(response).to be_successful
|
2015-07-16 16:01:37 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "has the right content type" do
|
|
|
|
|
expect(response.content_type).to eq("image/svg+xml")
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "requested by an unauthorized user" do
|
2026-02-03 10:56:15 +01:00
|
|
|
let(:permissions) { [:browse_repository] }
|
2015-07-16 16:01:37 +02:00
|
|
|
|
|
|
|
|
it "returns 403" do
|
|
|
|
|
expect(response.code).to eq("403")
|
|
|
|
|
end
|
|
|
|
|
end
|
2013-09-05 14:59:15 +01:00
|
|
|
end
|
2013-09-05 16:51:02 +01:00
|
|
|
|
2016-02-24 10:37:19 +01:00
|
|
|
describe "committers" do
|
2026-02-03 10:56:15 +01:00
|
|
|
let(:permissions) { [:manage_repository] }
|
2016-09-12 11:02:27 +02:00
|
|
|
|
2016-02-24 10:37:19 +01:00
|
|
|
describe "#get" do
|
|
|
|
|
before do
|
2018-01-22 08:44:15 +01:00
|
|
|
get :committers, params: { project_id: project.id }
|
2016-02-24 10:37:19 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "is successful" do
|
2018-11-23 15:06:32 +01:00
|
|
|
expect(response).to be_successful
|
2016-02-24 10:37:19 +01:00
|
|
|
expect(response).to render_template "repositories/committers"
|
|
|
|
|
end
|
|
|
|
|
end
|
2016-09-12 11:02:27 +02:00
|
|
|
|
2016-02-24 10:37:19 +01:00
|
|
|
describe "#post" do
|
|
|
|
|
before do
|
|
|
|
|
repository.fetch_changesets
|
2018-01-22 08:44:15 +01:00
|
|
|
post :committers, params: { project_id: project.id, committers: { "0" => ["oliver", user.id] },
|
2016-09-12 11:02:27 +02:00
|
|
|
commit: "Update" }
|
2016-02-24 10:37:19 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "is successful" do
|
2016-09-12 11:02:27 +02:00
|
|
|
expect(response).to redirect_to committers_project_repository_path(project)
|
2016-02-24 10:37:19 +01:00
|
|
|
expect(repository.committers).to include(["oliver", user.id])
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2015-07-16 16:01:37 +02:00
|
|
|
describe "stats" do
|
|
|
|
|
before do
|
2016-10-17 10:21:42 +02:00
|
|
|
get :stats, params: { project_id: project.identifier }
|
2015-07-16 16:01:37 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
describe "requested by a user with view_commit_author_statistics permission" do
|
2026-02-03 10:56:15 +01:00
|
|
|
let(:permissions) { %i[browse_repository view_commit_author_statistics] }
|
2015-07-16 16:01:37 +02:00
|
|
|
|
|
|
|
|
it "show the commits per author graph" do
|
|
|
|
|
expect(assigns(:show_commits_per_author)).to be(true)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
describe "requested by a user without view_commit_author_statistics permission" do
|
2026-02-03 10:56:15 +01:00
|
|
|
let(:permissions) { [:browse_repository] }
|
2015-07-16 16:01:37 +02:00
|
|
|
|
|
|
|
|
it "does not show the commits per author graph" do
|
|
|
|
|
expect(assigns(:show_commits_per_author)).to be(false)
|
|
|
|
|
end
|
|
|
|
|
end
|
2013-09-05 16:51:02 +01:00
|
|
|
end
|
2016-03-07 10:30:39 +01:00
|
|
|
|
2016-04-18 11:12:19 +02:00
|
|
|
shared_examples "renders the repository title" do |active_breadcrumb|
|
|
|
|
|
it do
|
2018-11-23 15:06:32 +01:00
|
|
|
expect(response).to be_successful
|
2025-06-11 13:14:32 +02:00
|
|
|
expect(response.body).to have_css(".PageHeader-breadcrumbs", text: active_breadcrumb)
|
2016-04-18 11:12:19 +02:00
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2016-04-13 21:09:07 +02:00
|
|
|
describe "show" do
|
|
|
|
|
render_views
|
2026-02-03 10:56:15 +01:00
|
|
|
let(:permissions) { [:browse_repository] }
|
2016-04-18 11:12:19 +02:00
|
|
|
|
2016-04-13 21:09:07 +02:00
|
|
|
before do
|
2018-02-26 15:53:26 +01:00
|
|
|
get :show, params: { project_id: project.identifier, repo_path: path }
|
2016-04-13 21:09:07 +02:00
|
|
|
end
|
|
|
|
|
|
2016-04-18 11:12:19 +02:00
|
|
|
context "with brackets" do
|
|
|
|
|
let(:path) { "subversion_test/[folder_with_brackets]" }
|
2022-05-31 11:55:27 +02:00
|
|
|
|
2016-04-18 11:12:19 +02:00
|
|
|
it_behaves_like "renders the repository title", "[folder_with_brackets]"
|
2016-04-13 21:09:07 +02:00
|
|
|
end
|
|
|
|
|
|
2016-04-18 11:12:19 +02:00
|
|
|
context "with unicode" do
|
|
|
|
|
let(:path) { "Föbar/äm/Sägepütz!%5D§" }
|
2022-05-31 11:55:27 +02:00
|
|
|
|
2016-04-18 11:12:19 +02:00
|
|
|
it_behaves_like "renders the repository title", "Sägepütz!%5D§"
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
describe "changes" do
|
|
|
|
|
render_views
|
2026-02-03 10:56:15 +01:00
|
|
|
let(:permissions) { [:browse_repository] }
|
2016-04-18 11:12:19 +02:00
|
|
|
|
|
|
|
|
before do
|
2018-02-26 15:53:26 +01:00
|
|
|
get :changes, params: { project_id: project.identifier, repo_path: path }
|
2018-11-23 15:06:32 +01:00
|
|
|
expect(response).to be_successful
|
2016-04-18 11:12:19 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "with brackets" do
|
2016-04-13 21:09:07 +02:00
|
|
|
let(:path) { "subversion_test/[folder_with_brackets]" }
|
2022-05-31 11:55:27 +02:00
|
|
|
|
2016-04-18 11:12:19 +02:00
|
|
|
it_behaves_like "renders the repository title", "[folder_with_brackets]"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "with unicode" do
|
|
|
|
|
let(:path) { "Föbar/äm" }
|
2022-05-31 11:55:27 +02:00
|
|
|
|
2016-04-18 11:12:19 +02:00
|
|
|
it_behaves_like "renders the repository title", "äm"
|
2016-04-13 21:09:07 +02:00
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2026-03-13 15:05:28 +01:00
|
|
|
describe "#entry" do
|
2026-03-16 12:13:57 +01:00
|
|
|
let(:permissions) { [:browse_repository] }
|
2026-03-13 14:44:56 +01:00
|
|
|
|
|
|
|
|
it "serves raw files as application/octet-stream attachment" do
|
|
|
|
|
get :entry, params: { project_id: project.identifier, repo_path: "subversion_test/textfile.txt", format: "raw" }
|
|
|
|
|
|
|
|
|
|
expect(response).to be_successful
|
|
|
|
|
expect(response.headers["Content-Type"]).to eq("application/octet-stream")
|
|
|
|
|
expect(response.headers["Content-Disposition"]).to match(/attachment/)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2016-03-07 10:30:39 +01:00
|
|
|
describe "checkout path" do
|
|
|
|
|
render_views
|
|
|
|
|
|
2026-02-03 10:56:15 +01:00
|
|
|
let(:permissions) { [:browse_repository] }
|
2021-02-11 16:02:18 +01:00
|
|
|
let(:checkout_hash) do
|
2016-03-07 10:30:39 +01:00
|
|
|
{
|
|
|
|
|
"subversion" => { "enabled" => "1",
|
|
|
|
|
"text" => "foo",
|
2021-02-11 16:02:18 +01:00
|
|
|
"base_url" => "http://localhost" }
|
2016-03-07 10:30:39 +01:00
|
|
|
}
|
2021-02-11 16:02:18 +01:00
|
|
|
end
|
2016-03-07 10:30:39 +01:00
|
|
|
|
|
|
|
|
before do
|
|
|
|
|
allow(Setting).to receive(:repository_checkout_data).and_return(checkout_hash)
|
2018-02-26 15:53:26 +01:00
|
|
|
get :show, params: { project_id: project.identifier, repo_path: "subversion_test" }
|
2016-03-07 10:30:39 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it "renders an empty warning view" do
|
|
|
|
|
expected_path = "http://localhost/#{project.identifier}/subversion_test"
|
|
|
|
|
|
|
|
|
|
expect(response.code).to eq("200")
|
|
|
|
|
expect(response).to render_template partial: "repositories/_checkout_instructions"
|
2024-01-04 17:01:17 +01:00
|
|
|
expect(response.body).to have_css("#repository-checkout-url[value='#{expected_path}']")
|
2016-03-07 10:30:39 +01:00
|
|
|
end
|
|
|
|
|
end
|
2013-09-05 16:51:02 +01:00
|
|
|
end
|
|
|
|
|
end
|
2017-06-19 12:55:28 +02:00
|
|
|
|
|
|
|
|
describe "when not being logged in" do
|
2022-01-24 19:22:35 +01:00
|
|
|
let(:anonymous) { build_stubbed(:anonymous) }
|
2017-06-19 12:55:28 +02:00
|
|
|
|
|
|
|
|
before do
|
|
|
|
|
login_as(anonymous)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
describe "#show" do
|
|
|
|
|
it "redirects to login while preserving the path" do
|
2018-02-26 15:53:26 +01:00
|
|
|
params = { repo_path: "aDir/within/aDir", rev: "42", project_id: project.id }
|
2023-03-07 15:07:44 +01:00
|
|
|
get(:show, params:)
|
2017-06-19 12:55:28 +02:00
|
|
|
|
|
|
|
|
expect(response)
|
|
|
|
|
.to redirect_to signin_path(back_url: show_revisions_path_project_repository_url(params))
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
2013-09-05 14:59:15 +01:00
|
|
|
end
|