Replace current Wiki system with Gollum Wikis.

This commit replaces the old database backed Wiki system with the
excellent Gollum git based Wiki system.

The UI has been updated to allow for utilizing the extra features
that Gollum provides. Specifically:

* Edit page now allows you to choose the content format.
* Edit page allows you to provide a commit message for the change.
* History page now shows Format, Commit Message, and Commit Hash.
* A new Git Access page has been added with the Wiki Repo URL.
* The default page has been changed to Home from Index to match
the Gollum standard.

The old Wiki model has been left in tact to provide for the
development of a migration script that will move all content stored
in the old Wiki system into new Gollum Wikis.
5-0-stable
Dan Knox 2013-03-03 19:43:52 -08:00
parent 8e8372d5ce
commit ea9b3687db
21 changed files with 888 additions and 87 deletions

View File

@ -99,6 +99,13 @@ gem "colored"
# GitLab settings
gem 'settingslogic'
# Wiki
# - Use latest master to resolve Gem dependency with Pygemnts
# github-linquist needs pygments 0.4.2 but Gollum 2.4.11
# requires pygments 0.3.2. The latest master Gollum has been updated
# to use pygments 0.4.2. Change this after next Gollum release.
gem "gollum", "~> 2.4.0", git: "git://github.com/github/gollum.git"
# Misc
gem "foreman"
gem "git"

View File

@ -1,3 +1,19 @@
GIT
remote: git://github.com/github/gollum.git
revision: 544d499ab170c9d9b355b7a0160afc74139ee2a4
specs:
gollum (2.4.11)
github-markdown (~> 0.5.3)
github-markup (>= 0.7.5, < 1.0.0)
grit (~> 2.5.0)
mustache (>= 0.99.4, < 1.0.0)
nokogiri (~> 1.5.6)
pygments.rb (~> 0.4.2)
sanitize (~> 2.0.3)
sinatra (~> 1.3.5)
stringex (~> 1.5.1)
useragent (~> 0.4.16)
GIT
remote: https://github.com/ctran/annotate_models.git
revision: be4e26825b521f0b2d86b181e2dff89901aa9b1e
@ -139,6 +155,7 @@ GEM
escape_utils (~> 0.2.3)
mime-types (~> 1.19)
pygments.rb (>= 0.2.13)
github-markdown (0.5.3)
github-markup (0.7.5)
gitlab-grack (1.0.0)
rack (~> 1.4.1)
@ -170,6 +187,10 @@ GEM
grape-entity (0.2.0)
activesupport
multi_json (>= 1.3.2)
grit (2.5.0)
diff-lcs (~> 1.1)
mime-types (~> 1.15)
posix-spawn (~> 0.3.6)
grit_ext (0.6.2)
charlock_holmes (~> 0.6.9)
growl (1.0.3)
@ -231,7 +252,8 @@ GEM
sprockets (~> 2.0)
multi_json (1.6.1)
multi_xml (0.5.3)
multipart-post (1.2.0)
multipart-post (1.1.5)
mustache (0.99.4)
mysql2 (0.3.11)
net-ldap (0.2.2)
nokogiri (1.5.6)
@ -365,6 +387,8 @@ GEM
rspec-mocks (~> 2.12.0)
rubyntlm (0.1.1)
rubyzip (0.9.9)
sanitize (2.0.3)
nokogiri (>= 1.4.4, < 1.6)
sass (3.2.5)
sass-rails (3.2.5)
railties (~> 3.2.0)
@ -418,6 +442,7 @@ GEM
tilt (~> 1.1, != 1.3.0)
stamp (0.5.0)
state_machine (1.1.2)
stringex (1.5.1)
temple (0.5.5)
test_after_commit (0.0.1)
therubyracer (0.10.2)
@ -440,6 +465,7 @@ GEM
kgio (~> 2.6)
rack
raindrops (~> 0.7)
useragent (0.4.16)
virtus (0.5.4)
backports (~> 2.6.1)
descendants_tracker (~> 0.0.1)
@ -487,6 +513,7 @@ DEPENDENCIES
gitlab_meta (= 5.0)
gitlab_omniauth-ldap (= 1.0.2)
gitlab_yaml_db (= 1.0.0)
gollum (~> 2.4.0)!
gon
grape (~> 0.3.1)
grape-entity (~> 0.2.0)

View File

@ -33,6 +33,7 @@
@import "sections/login.scss";
@import "sections/editor.scss";
@import "sections/admin.scss";
@import "sections/wiki.scss";
@import "highlight/white.scss";
@import "highlight/dark.scss";

View File

@ -0,0 +1,6 @@
h3.page_title .edit-wiki-header {
width: 780px;
margin-left: auto;
margin-right: auto;
padding-right: 7px;
}

View File

@ -2,58 +2,94 @@ class WikisController < ProjectResourceController
before_filter :authorize_read_wiki!
before_filter :authorize_write_wiki!, only: [:edit, :create, :history]
before_filter :authorize_admin_wiki!, only: :destroy
before_filter :load_gollum_wiki
def pages
@wiki_pages = @project.wikis.group(:slug).ordered
@wiki_pages = @gollum_wiki.pages
end
def show
@most_recent_wiki = @project.wikis.where(slug: params[:id]).ordered.first
if params[:version_id]
@wiki = @project.wikis.find(params[:version_id])
else
@wiki = @most_recent_wiki
end
@wiki = @gollum_wiki.find_page(params[:id], params[:version_id])
if @wiki
render 'show'
else
if can?(current_user, :write_wiki, @project)
@wiki = @project.wikis.new(slug: params[:id])
render 'edit'
else
render 'empty'
end
return render('empty') unless can?(current_user, :write_wiki, @project)
@wiki = WikiPage.new(@gollum_wiki)
@wiki.title = params[:id]
render 'edit'
end
end
def edit
@wiki = @project.wikis.where(slug: params[:id]).ordered.first
@wiki = Wiki.regenerate_from @wiki
@wiki = @gollum_wiki.find_page(params[:id])
end
def update
@wiki = @gollum_wiki.find_page(params[:id])
return render('empty') unless can?(current_user, :write_wiki, @project)
if @wiki.update(content, format, message)
redirect_to [@project, @wiki], notice: 'Wiki was successfully updated.'
else
render 'edit'
end
end
def create
@wiki = @project.wikis.new(params[:wiki])
@wiki.user = current_user
@wiki = WikiPage.new(@gollum_wiki)
respond_to do |format|
if @wiki.save
format.html { redirect_to [@project, @wiki], notice: 'Wiki was successfully updated.' }
else
format.html { render action: "edit" }
end
if @wiki.create(wiki_params)
redirect_to project_wiki_path(@project, @wiki), notice: 'Wiki was successfully updated.'
else
render action: "edit"
end
end
def history
@wiki_pages = @project.wikis.where(slug: params[:id]).ordered
unless @wiki = @gollum_wiki.find_page(params[:id])
redirect_to project_wiki_path(@project, :home), notice: "Page not found"
end
end
def destroy
@wikis = @project.wikis.where(slug: params[:id]).delete_all
respond_to do |format|
format.html { redirect_to project_wiki_path(@project, :index), notice: "Page was successfully deleted" }
end
@wiki = @gollum_wiki.find_page(params[:id])
@wiki.delete if @wiki
redirect_to project_wiki_path(@project, :home), notice: "Page was successfully deleted"
end
def git_access
end
private
def load_gollum_wiki
@gollum_wiki = GollumWiki.new(@project, current_user)
# Call #wiki to make sure the Wiki Repo is initialized
@gollum_wiki.wiki
rescue GollumWiki::CouldNotCreateWikiError => ex
flash[:notice] = "Could not create Wiki Repository at this time. Please try again later."
redirect_to @project
return false
end
def wiki_params
params[:wiki].slice(:title, :content, :format, :message)
end
def content
params[:wiki][:content]
end
def format
params[:wiki][:format]
end
def message
params[:wiki][:message]
end
end

125
app/models/gollum_wiki.rb Normal file
View File

@ -0,0 +1,125 @@
class GollumWiki
MARKUPS = {
"Markdown" => :markdown,
"Textile" => :textile,
"RDoc" => :rdoc,
"Org-mode" => :org,
"Creole" => :creole,
"reStructuredText" => :rest,
"AsciiDoc" => :asciidoc,
"MediaWiki" => :mediawiki,
"Pod" => :post
}
class CouldNotCreateWikiError < StandardError; end
# Returns a string describing what went wrong after
# an operation fails.
attr_reader :error_message
def initialize(project, user = nil)
@project = project
@user = user
end
def path_with_namespace
@project.path_with_namespace + ".wiki"
end
def url_to_repo
gitlab_shell.url_to_repo(path_with_namespace)
end
def ssh_url_to_repo
url_to_repo
end
def http_url_to_repo
http_url = [Gitlab.config.gitlab.url, "/", path_with_namespace, ".git"].join('')
end
# Returns the Gollum::Wiki object.
def wiki
@wiki ||= begin
Gollum::Wiki.new(path_to_repo)
rescue Grit::NoSuchPathError
create_repo!
end
end
# Returns an Array of Gitlab WikiPage instances or an
# empty Array if this Wiki has no pages.
def pages
wiki.pages.map { |page| WikiPage.new(self, page, true) }
end
# Returns the last 30 Commit objects accross the entire
# repository.
def recent_history
Commit.fresh_commits(wiki.repo, 30)
end
# Finds a page within the repository based on a tile
# or slug.
#
# title - The human readable or parameterized title of
# the page.
#
# Returns an initialized WikiPage instance or nil
def find_page(title, version = nil)
if page = wiki.page(title, version)
WikiPage.new(self, page, true)
else
nil
end
end
def create_page(title, content, format = :markdown, message = nil)
commit = commit_details(:created, message, title)
wiki.write_page(title, format, content, commit)
rescue Gollum::DuplicatePageError => e
@error_message = "Duplicate page: #{e.message}"
return false
end
def update_page(page, content, format = :markdown, message = nil)
commit = commit_details(:updated, message, page.title)
wiki.update_page(page, page.name, format, content, commit)
end
def delete_page(page, message = nil)
wiki.delete_page(page, commit_details(:deleted, message, page.title))
end
private
def create_repo!
if gitlab_shell.add_repository(path_with_namespace)
Gollum::Wiki.new(path_to_repo)
else
raise CouldNotCreateWikiError
end
end
def commit_details(action, message = nil, title = nil)
commit_message = message || default_message(action, title)
{email: @user.email, name: @user.name, message: commit_message}
end
def default_message(action, title)
"#{@user.username} #{action} page: #{title}"
end
def gitlab_shell
@gitlab_shell ||= Gitlab::Shell.new
end
def path_to_repo
@path_to_repo ||= File.join(Gitlab.config.gitlab_shell.repos_path, "#{path_with_namespace}.git")
end
end

181
app/models/wiki_page.rb Normal file
View File

@ -0,0 +1,181 @@
class WikiPage
include ActiveModel::Validations
include ActiveModel::Conversion
include StaticModel
extend ActiveModel::Naming
def self.primary_key
'slug'
end
def self.model_name
ActiveModel::Name.new(self, nil, 'wiki')
end
def to_key
[:slug]
end
validates :title, presence: true
validates :content, presence: true
# The Gitlab GollumWiki instance.
attr_reader :wiki
# The raw Gollum::Page instance.
attr_reader :page
# The attributes Hash used for storing and validating
# new Page values before writing to the Gollum repository.
attr_accessor :attributes
def initialize(wiki, page = nil, persisted = false)
@wiki = wiki
@page = page
@persisted = persisted
@attributes = {}.with_indifferent_access
set_attributes if persisted?
end
# The escaped URL path of this page.
def slug
@attributes[:slug]
end
alias :to_param :slug
# The formatted title of this page.
def title
@attributes[:title] || ""
end
# Sets the title of this page.
def title=(new_title)
@attributes[:title] = new_title
end
# The raw content of this page.
def content
@attributes[:content]
end
# The processed/formatted content of this page.
def formatted_content
@attributes[:formatted_content]
end
# The markup format for the page.
def format
@attributes[:format] || :markdown
end
# The commit message for this page version.
def message
version.try(:message)
end
# The Gitlab Commit instance for this page.
def version
return nil unless persisted?
@version ||= Commit.new(@page.version)
end
# Returns an array of Gitlab Commit instances.
def versions
return [] unless persisted?
@page.versions.map { |v| Commit.new(v) }
end
# Returns the Date that this latest version was
# created on.
def created_at
@page.version.date
end
# Returns boolean True or False if this instance
# is an old version of the page.
def historical?
@page.historical?
end
# Returns boolean True or False if this instance
# has been fully saved to disk or not.
def persisted?
@persisted == true
end
# Creates a new Wiki Page.
#
# attr - Hash of attributes to set on the new page.
# :title - The title for the new page.
# :content - The raw markup content.
# :format - Optional symbol representing the
# content format. Can be any type
# listed in the GollumWiki::MARKUPS
# Hash.
# :message - Optional commit message to set on
# the new page.
#
# Returns the String SHA1 of the newly created page
# or False if the save was unsuccessful.
def create(attr = {})
@attributes.merge!(attr)
save :create_page, title, content, format, message
end
# Updates an existing Wiki Page, creating a new version.
#
# new_content - The raw markup content to replace the existing.
# format - Optional symbol representing the content format.
# See GollumWiki::MARKUPS Hash for available formats.
# message - Optional commit message to set on the new version.
#
# Returns the String SHA1 of the newly created page
# or False if the save was unsuccessful.
def update(new_content = "", format = :markdown, message = nil)
@attributes[:content] = new_content
@attributes[:format] = format
save :update_page, @page, content, format, message
end
# Destroys the WIki Page.
#
# Returns boolean True or False.
def delete
if wiki.delete_page(@page)
true
else
false
end
end
private
def set_attributes
attributes[:slug] = @page.escaped_url_path
attributes[:title] = @page.title
attributes[:content] = @page.raw_data
attributes[:formatted_content] = @page.formatted_data
attributes[:format] = @page.format
end
def save(method, *args)
if valid? && wiki.send(method, *args)
@page = wiki.wiki.paged(title)
set_attributes
@persisted = true
else
errors.add(:base, wiki.error_message) if wiki.error_message
@persisted = false
end
@persisted
end
end

View File

@ -18,6 +18,11 @@ class ProjectObserver < ActiveRecord::Observer
project.path_with_namespace
)
GitlabShellWorker.perform_async(
:remove_repository,
project.path_with_namespace + ".wiki"
)
project.satellite.destroy
log_info("Project \"#{project.name}\" was removed")

View File

@ -41,6 +41,6 @@
- if @project.wiki_enabled
= nav_link(controller: :wikis) do
= link_to 'Wiki', project_wiki_path(@project, :index)
= link_to 'Wiki', project_wiki_path(@project, :home)
.content= yield

View File

@ -8,9 +8,12 @@
.ui-box.ui-box-show
.ui-box-head
= f.label :title
.input= f.text_field :title, class: 'span8'
= f.hidden_field :slug
%h3.page_title
.edit-wiki-header
= @wiki.title.titleize
= f.hidden_field :title, value: @wiki.title
= f.select :format, options_for_select(GollumWiki::MARKUPS, {selected: @wiki.format}), {}, class: "pull-right input-medium"
= f.label :format, class: "pull-right", style: "padding-right: 20px;"
.ui-box-body
.input
%span.cgray
@ -22,6 +25,9 @@
.ui-box-bottom
= f.label :content
.input= f.text_area :content, class: 'span8 js-gfm-input'
.ui-box-bottom
= f.label :commit_message
.input= f.text_field :message, class: 'span8'
.actions
= f.submit 'Save', class: "btn-save btn"
= link_to "Cancel", project_wiki_path(@project, :index), class: "btn btn-cancel"

View File

@ -0,0 +1,16 @@
%span.pull-right
= link_to project_wiki_path(@project, :home), class: "btn btn-small grouped" do
Home
= link_to pages_project_wikis_path(@project), class: "btn btn-small grouped" do
Pages
- if (@wiki && @wiki.persisted?)
= link_to history_project_wiki_path(@project, @wiki), class: "btn btn-small grouped" do
History
- if can?(current_user, :write_wiki, @project)
- if @wiki && @wiki.persisted?
= link_to edit_project_wiki_path(@project, @wiki), class: "btn btn-small grouped" do
%i.icon-edit
Edit
= link_to git_access_project_wikis_path(@project), class: "btn btn-small grouped" do
%i.icon-download-alt
Git Access

View File

@ -1,8 +1,10 @@
%h3.page_title Editing page
%h3.page_title
Editing page
= render partial: 'main_links'
%hr
= render 'form'
.pull-right
- if can? current_user, :admin_wiki, @project
= link_to project_wiki_path(@project, @wiki), confirm: "Are you sure you want to delete this page?", method: :delete, class: "btn btn-small btn-remove" do
Delete this page
= link_to project_wikis_path(@project, @wiki), confirm: "Are you sure you want to delete this page?", method: :delete, class: "btn btn-small btn-remove" do
Delete this page

View File

@ -0,0 +1,36 @@
%h3.page_title
Git Access
%strong= @gollum_wiki.path_with_namespace
= render partial: 'main_links'
%br
.content
.project_clone_panel
.row
.span7
.form-horizontal
.input-prepend.project_clone_holder
%button{class: "btn active", :"data-clone" => @gollum_wiki.ssh_url_to_repo} SSH
%button{class: "btn", :"data-clone" => @gollum_wiki.http_url_to_repo}= Gitlab.config.gitlab.protocol.upcase
= text_field_tag :project_clone, @gollum_wiki.url_to_repo, class: "one_click_select input-xxlarge", readonly: true
.git-empty
%fieldset
%legend Install Gollum:
%pre.dark
:preserve
gem install gollum
%legend Clone Your Wiki:
%pre.dark
:preserve
git clone #{@gollum_wiki.path_with_namespace}.git
cd #{@gollum_wiki.path_with_namespace}
%legend Start Gollum And Edit Locally:
%pre.dark
:preserve
gollum
== Sinatra/1.3.5 has taken the stage on 4567 for development with backup from Thin
>> Thin web server (v1.5.0 codename Knife)
>> Maximum connections set to 1024
>> Listening on 0.0.0.0:4567, CTRL+C to stop

View File

@ -1,23 +1,29 @@
%h3.page_title
%span.cgray History for
= @wiki_pages.first.title
= @wiki.title.titleize
= render partial: 'main_links'
%br
%table
%thead
%tr
%th Page version
%th Author
%th Commit Message
%th Last updated
%th Updated by
%th Format
%tbody
- @wiki_pages.each_with_index do |wiki_page, i|
- @wiki.versions.each do |version|
- commit = CommitDecorator.new(version)
%tr
%td
%strong
= link_to project_wiki_path(@project, wiki_page, version_id: wiki_page.id) do
Version
= @wiki_pages.count - i
= link_to project_wiki_path(@project, @wiki, version_id: commit.id) do
= commit.short_id
%td= commit.author_link avatar: true, size: 24
%td
= wiki_page.created_at.to_s(:short)
(#{time_ago_in_words(wiki_page.created_at)}
ago)
%td= link_to_member(@project, wiki_page.user)
= commit.title
%td
= time_ago_in_words(version.date)
ago
%td
%strong
= @wiki.page.wiki.page(@wiki.page.name, commit.id).try(:format)

View File

@ -1,20 +1,24 @@
%h3.page_title All Pages
%h3.page_title
All Pages
= render partial: 'main_links'
%br
%table
%thead
%tr
%th Title
%th Slug
%th Format
%th Last updated
%th Updated by
%tbody
- @wiki_pages.each do |wiki_page|
%tr
%td
%strong= link_to wiki_page.title, project_wiki_path(@project, wiki_page)
%td= wiki_page.slug
%strong= link_to wiki_page.title.titleize, project_wiki_path(@project, wiki_page)
%td
%strong= wiki_page.format
%td
= wiki_page.created_at.to_s(:short) do
(#{time_ago_in_words(wiki_page.created_at)}
ago)
%td= link_to_member(@project, wiki_page.user)
- commit = CommitDecorator.decorate(wiki_page.version)
%td= commit.author_link avatar: true, size: 24

View File

@ -1,16 +1,8 @@
%h3.page_title
= @wiki.title
%span.pull-right
= link_to pages_project_wikis_path(@project), class: "btn btn-small grouped" do
Pages
- if can? current_user, :write_wiki, @project
= link_to history_project_wiki_path(@project, @wiki), class: "btn btn-small grouped" do
History
= link_to edit_project_wiki_path(@project, @wiki), class: "btn btn-small grouped" do
%i.icon-edit
Edit
= @wiki.title.titleize
= render partial: 'main_links'
%br
- if @wiki != @most_recent_wiki
- if @wiki.historical?
.warning_message
This is an old version of this page.
You can view the #{link_to "most recent version", project_wiki_path(@project, @wiki)} or browse the #{link_to "history", history_project_wiki_path(@project, @wiki)}.
@ -18,6 +10,7 @@
.file_holder
.file_content.wiki
= preserve do
= markdown @wiki.content
= @wiki.formatted_content.html_safe
%p.time Last edited by #{link_to_member @project, @wiki.user}, #{time_ago_in_words @wiki.created_at} ago
- commit = CommitDecorator.new(@wiki.version)
%p.time Last edited by #{commit.author_link(avatar: true, size: 16)} #{time_ago_in_words @wiki.created_at} ago

View File

@ -185,6 +185,8 @@ Gitlab::Application.routes.draw do
resources :wikis, only: [:show, :edit, :destroy, :create] do
collection do
get :pages
put ':id' => 'wikis#update'
get :git_access
end
member do

View File

@ -12,10 +12,18 @@ module Gitlab
# ref - branch name
#
get "/allowed" do
# Check for *.wiki repositories.
# Strip out the .wiki from the pathname before finding the
# project. This applies the correct project permissions to
# the wiki repository as well.
project_path = params[:project]
project_path.gsub!(/\.wiki/,'') if project_path =~ /\.wiki/
key = Key.find(params[:key_id])
project = Project.find_with_namespace(params[:project])
project = Project.find_with_namespace(project_path)
git_cmd = params[:action]
if key.is_deploy_key
project == key.project && git_cmd == 'git-upload-pack'
else

View File

@ -208,24 +208,4 @@ describe "Gitlab Flavored Markdown" do
end
end
describe "for wikis" do
before do
visit project_wiki_path(project, :index)
fill_in "Title", with: "Circumvent ##{issue.id}"
fill_in "Content", with: "# Other pages\n\n* [Foo](foo)\n* [Bar](bar)\n\nAlso look at ##{issue.id} :-)"
click_on "Save"
end
it "should NOT render title in wikis#show" do
within(".content h3") do # page title
page.should have_content("Circumvent ##{issue.id}")
page.should_not have_link("##{issue.id}")
end
end
it "should render content in wikis#show" do
page.should have_link("##{issue.id}")
end
end
end

View File

@ -0,0 +1,196 @@
require "spec_helper"
describe GollumWiki do
def create_temp_repo(path)
FileUtils.mkdir_p path
command = "git init --quiet #{path};"
system(command)
end
def remove_temp_repo(path)
FileUtils.rm_rf path
end
def commit_details
commit = {name: user.name, email: user.email, message: "test commit"}
end
def create_page(name, content)
subject.wiki.write_page(name, :markdown, content, commit_details)
end
def destroy_page(page)
subject.wiki.delete_page(page, commit_details)
end
let(:project) { create(:project) }
let(:repository) { project.repository }
let(:user) { project.owner }
let(:gitlab_shell) { Gitlab::Shell.new }
subject { GollumWiki.new(project, user) }
before do
create_temp_repo(subject.send(:path_to_repo))
end
describe "#path_with_namespace" do
it "returns the project path with namespace with the .wiki extension" do
subject.path_with_namespace.should == project.path_with_namespace + ".wiki"
end
end
describe "#url_to_repo" do
it "returns the correct ssh url to the repo" do
subject.url_to_repo.should == gitlab_shell.url_to_repo(subject.path_with_namespace)
end
end
describe "#ssh_url_to_repo" do
it "equals #url_to_repo" do
subject.ssh_url_to_repo.should == subject.url_to_repo
end
end
describe "#http_url_to_repo" do
it "provides the full http url to the repo" do
gitlab_url = Gitlab.config.gitlab.url
repo_http_url = "#{gitlab_url}/#{subject.path_with_namespace}.git"
subject.http_url_to_repo.should == repo_http_url
end
end
describe "#wiki" do
it "contains a Gollum::Wiki instance" do
subject.wiki.should be_a Gollum::Wiki
end
before do
Gitlab::Shell.any_instance.stub(:add_repository) do
create_temp_repo("#{Rails.root}/tmp/test-git-base-path/non-existant.wiki.git")
end
project.stub(:path_with_namespace).and_return("non-existant")
end
it "creates a new wiki repo if one does not yet exist" do
wiki = GollumWiki.new(project, user)
wiki.create_page("index", "test content").should_not == false
FileUtils.rm_rf wiki.send(:path_to_repo)
end
it "raises CouldNotCreateWikiError if it can't create the wiki repository" do
Gitlab::Shell.any_instance.stub(:add_repository).and_return(false)
expect { GollumWiki.new(project, user).wiki }.to raise_exception(GollumWiki::CouldNotCreateWikiError)
end
end
describe "#pages" do
before do
create_page("index", "This is an awesome new Gollum Wiki")
@pages = subject.pages
end
after do
destroy_page(@pages.first.page)
end
it "returns an array of WikiPage instances" do
@pages.first.should be_a WikiPage
end
it "returns the correct number of pages" do
@pages.count.should == 1
end
end
describe "#find_page" do
before do
create_page("index page", "This is an awesome Gollum Wiki")
end
after do
destroy_page(subject.pages.first.page)
end
it "returns the latest version of the page if it exists" do
page = subject.find_page("index page")
page.title.should == "index page"
end
it "returns nil if the page does not exist" do
subject.find_page("non-existant").should == nil
end
it "can find a page by slug" do
page = subject.find_page("index-page")
page.title.should == "index page"
end
it "returns a WikiPage instance" do
page = subject.find_page("index page")
page.should be_a WikiPage
end
end
describe "#create_page" do
after do
destroy_page(subject.pages.first.page)
end
it "creates a new wiki page" do
subject.create_page("test page", "this is content").should_not == false
subject.pages.count.should == 1
end
it "returns false when a duplicate page exists" do
subject.create_page("test page", "content")
subject.create_page("test page", "content").should == false
end
it "stores an error message when a duplicate page exists" do
2.times { subject.create_page("test page", "content") }
subject.error_message.should =~ /Duplicate page:/
end
it "sets the correct commit message" do
subject.create_page("test page", "some content", :markdown, "commit message")
subject.pages.first.page.version.message.should == "commit message"
end
end
describe "#update_page" do
before do
create_page("update-page", "some content")
@gollum_page = subject.wiki.paged("update-page")
subject.update_page(@gollum_page, "some other content", :markdown, "updated page")
@page = subject.pages.first.page
end
after do
destroy_page(@page)
end
it "updates the content of the page" do
@page.raw_data.should == "some other content"
end
it "sets the correct commit message" do
@page.version.message.should == "updated page"
end
end
describe "#delete_page" do
before do
create_page("index", "some content")
@page = subject.wiki.paged("index")
end
it "deletes the page" do
subject.delete_page(@page)
subject.pages.count.should == 0
end
end
end

View File

@ -0,0 +1,164 @@
require "spec_helper"
describe WikiPage do
def create_temp_repo(path)
FileUtils.mkdir_p path
command = "git init --quiet #{path};"
system(command)
end
def remove_temp_repo(path)
FileUtils.rm_rf path
end
def commit_details
commit = {name: user.name, email: user.email, message: "test commit"}
end
def create_page(name, content)
wiki.wiki.write_page(name, :markdown, content, commit_details)
end
def destroy_page(title)
page = wiki.wiki.paged(title)
wiki.wiki.delete_page(page, commit_details)
end
let(:project) { create(:project) }
let(:repository) { project.repository }
let(:user) { project.owner }
let(:wiki) { GollumWiki.new(project, user) }
subject { WikiPage.new(wiki) }
before do
create_temp_repo(wiki.send(:path_to_repo))
end
describe "#initialize" do
context "when initialized with an existing gollum page" do
before do
create_page("test page", "test content")
@page = wiki.wiki.paged("test page")
@wiki_page = WikiPage.new(wiki, @page, true)
end
it "sets the slug attribute" do
@wiki_page.slug.should == "test-page"
end
it "sets the title attribute" do
@wiki_page.title.should == "test page"
end
it "sets the formatted content attribute" do
@wiki_page.content.should == "test content"
end
it "sets the format attribute" do
@wiki_page.format.should == :markdown
end
it "sets the message attribute" do
@wiki_page.message.should == "test commit"
end
it "sets the version attribute" do
@wiki_page.version.should be_a Commit
end
end
end
describe "validations" do
before do
subject.attributes = {title: 'title', content: 'content'}
end
it "validates presence of title" do
subject.attributes.delete(:title)
subject.valid?.should be_false
end
it "validates presence of content" do
subject.attributes.delete(:content)
subject.valid?.should be_false
end
end
before do
@wiki_attr = {title: "Index", content: "Home Page", format: "markdown"}
end
describe "#create" do
after do
destroy_page("Index")
end
context "with valid attributes" do
it "saves the wiki page" do
subject.create(@wiki_attr)
wiki.find_page("Index").should_not be_nil
end
it "returns true" do
subject.create(@wiki_attr).should == true
end
end
end
describe "#update" do
before do
create_page("Update", "content")
@page = wiki.find_page("Update")
end
after do
destroy_page("Update")
end
context "with valid attributes" do
it "updates the content of the page" do
@page.update("new content")
@page = wiki.find_page("Update")
end
it "returns true" do
@page.update("more content").should be_true
end
end
end
describe "#destroy" do
before do
create_page("Delete Page", "content")
@page = wiki.find_page("Delete Page")
end
it "should delete the page" do
@page.delete
wiki.pages.should be_empty
end
it "should return true" do
@page.delete.should == true
end
end
describe "#versions" do
before do
create_page("Update", "content")
@page = wiki.find_page("Update")
end
after do
destroy_page("Update")
end
it "returns an array of all commits for the page" do
3.times { |i| @page.update("content #{i}") }
@page.versions.count.should == 4
end
end
end