Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c8f0999035 | ||
|
|
46faec7857 | ||
|
|
e35d3fe6ba | ||
|
|
ba620e0f7f | ||
|
|
5700f55dc3 | ||
|
|
2c92010093 | ||
|
|
03490531d8 | ||
|
|
7bd9759e81 | ||
|
|
a808f56caf | ||
|
|
b7e2b45e69 | ||
|
|
63c45d7c3a | ||
|
|
096067ac62 | ||
|
|
8d6bf4c0c5 | ||
|
|
882b862780 | ||
|
|
e06a5d6300 | ||
|
|
7451e8c739 | ||
|
|
f034f773c5 | ||
|
|
681fd98dc3 | ||
|
|
e57b139e32 | ||
|
|
b64bfe2bb6 | ||
|
|
ee04b5788a | ||
|
|
2e8d431ab5 | ||
|
|
3465c37c0e | ||
|
|
bf6894e313 | ||
|
|
77e3f7f479 | ||
|
|
753f5027b0 | ||
|
|
23c012a527 | ||
|
|
895543641b |
@@ -1,3 +1,12 @@
|
|||||||
|
#1.1.2
|
||||||
|
* Added '--force' option to the rc command to bypass confirmation checks when running a .homesickrc file
|
||||||
|
* Added a check to make sure that a minimum of Git 1.8.0 is installed. This stops Homesick failing silently if Git is not installed.
|
||||||
|
* Code refactoring and fixes.
|
||||||
|
|
||||||
|
#1.1.0
|
||||||
|
* Added exec and exec_all commands to run commands inside one or all clones castles.
|
||||||
|
* Code refactoring.
|
||||||
|
|
||||||
#1.0.0
|
#1.0.0
|
||||||
* Removed support for Ruby 1.8.7
|
* Removed support for Ruby 1.8.7
|
||||||
* Added a version command
|
* Added a version command
|
||||||
|
|||||||
3
Gemfile
3
Gemfile
@@ -8,12 +8,11 @@ gem "thor", ">= 0.14.0"
|
|||||||
# Include everything needed to run rake, tests, features, etc.
|
# Include everything needed to run rake, tests, features, etc.
|
||||||
group :development do
|
group :development do
|
||||||
gem "rake", ">= 0.8.7"
|
gem "rake", ">= 0.8.7"
|
||||||
gem "rspec", "~> 2.10"
|
gem "rspec", "~> 3.1.0"
|
||||||
gem "guard"
|
gem "guard"
|
||||||
gem "guard-rspec"
|
gem "guard-rspec"
|
||||||
gem "rb-readline", "~> 0.5.0"
|
gem "rb-readline", "~> 0.5.0"
|
||||||
gem "jeweler", ">= 1.6.2"
|
gem "jeweler", ">= 1.6.2"
|
||||||
#gem "simplecov"
|
|
||||||
gem 'coveralls', require: false
|
gem 'coveralls', require: false
|
||||||
gem "test_construct"
|
gem "test_construct"
|
||||||
gem "capture-output", "~> 1.0.0"
|
gem "capture-output", "~> 1.0.0"
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
# homesick
|
# homesick
|
||||||
|
|
||||||
[](http://badge.fury.io/rb/homesick)
|
[](http://badge.fury.io/rb/homesick)
|
||||||
[](https://travis-ci.org/technicalpickles/homesick)
|
[](https://travis-ci.org/technicalpickles/homesick)
|
||||||
[](https://gemnasium.com/technicalpickles/homesick)
|
[](https://gemnasium.com/technicalpickles/homesick)
|
||||||
[](https://coveralls.io/r/technicalpickles/homesick)
|
[](https://coveralls.io/r/technicalpickles/homesick)
|
||||||
[](https://codeclimate.com/github/technicalpickles/homesick)
|
[](https://codeclimate.com/github/technicalpickles/homesick)
|
||||||
[](https://gitter.im/technicalpickles/homesick)
|
[](https://gitter.im/technicalpickles/homesick)
|
||||||
|
|
||||||
Your home directory is your castle. Don't leave your dotfiles behind.
|
Your home directory is your castle. Don't leave your dotfiles behind.
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ If you need to add further configuration steps you can add these in a file calle
|
|||||||
|
|
||||||
homesick rc CASTLE
|
homesick rc CASTLE
|
||||||
|
|
||||||
The contents of the .homesickrc file must be valid Ruby code as the file will be executed with Ruby's eval construct. The .homesickrc is also passed the current homesick object during its execution and this is available within the .homesickrc file as the 'self' variable.
|
The contents of the .homesickrc file must be valid Ruby code as the file will be executed with Ruby's eval construct. The .homesickrc is also passed the current homesick object during its execution and this is available within the .homesickrc file as the 'self' variable. As the rc operation can be destructive the command normally asks for confirmation before proceeding. You can bypass this by passing the '--force' option, for example `homesick rc --force CASTLE`.
|
||||||
|
|
||||||
If you're not sure what castles you have around, you can easily list them:
|
If you're not sure what castles you have around, you can easily list them:
|
||||||
|
|
||||||
|
|||||||
@@ -2,16 +2,16 @@
|
|||||||
# DO NOT EDIT THIS FILE DIRECTLY
|
# DO NOT EDIT THIS FILE DIRECTLY
|
||||||
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
||||||
# -*- encoding: utf-8 -*-
|
# -*- encoding: utf-8 -*-
|
||||||
# stub: homesick 1.1.0 ruby lib
|
# stub: homesick 1.1.2 ruby lib
|
||||||
|
|
||||||
Gem::Specification.new do |s|
|
Gem::Specification.new do |s|
|
||||||
s.name = "homesick"
|
s.name = "homesick"
|
||||||
s.version = "1.1.0"
|
s.version = "1.1.2"
|
||||||
|
|
||||||
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
||||||
s.require_paths = ["lib"]
|
s.require_paths = ["lib"]
|
||||||
s.authors = ["Joshua Nichols", "Yusuke Murata"]
|
s.authors = ["Joshua Nichols", "Yusuke Murata"]
|
||||||
s.date = "2014-04-28"
|
s.date = "2015-01-02"
|
||||||
s.description = "\n Your home directory is your castle. Don't leave your dotfiles behind.\n \n\n Homesick is sorta like rip, but for dotfiles. It uses git to clone a repository containing dotfiles, and saves them in ~/.homesick. It then allows you to symlink all the dotfiles into place with a single command. \n\n "
|
s.description = "\n Your home directory is your castle. Don't leave your dotfiles behind.\n \n\n Homesick is sorta like rip, but for dotfiles. It uses git to clone a repository containing dotfiles, and saves them in ~/.homesick. It then allows you to symlink all the dotfiles into place with a single command. \n\n "
|
||||||
s.email = ["josh@technicalpickles.com", "info@muratayusuke.com"]
|
s.email = ["josh@technicalpickles.com", "info@muratayusuke.com"]
|
||||||
s.executables = ["homesick"]
|
s.executables = ["homesick"]
|
||||||
@@ -37,7 +37,6 @@ Gem::Specification.new do |s|
|
|||||||
"lib/homesick/actions/file_actions.rb",
|
"lib/homesick/actions/file_actions.rb",
|
||||||
"lib/homesick/actions/git_actions.rb",
|
"lib/homesick/actions/git_actions.rb",
|
||||||
"lib/homesick/cli.rb",
|
"lib/homesick/cli.rb",
|
||||||
"lib/homesick/shell.rb",
|
|
||||||
"lib/homesick/utils.rb",
|
"lib/homesick/utils.rb",
|
||||||
"lib/homesick/version.rb",
|
"lib/homesick/version.rb",
|
||||||
"spec/homesick_cli_spec.rb",
|
"spec/homesick_cli_spec.rb",
|
||||||
@@ -55,7 +54,7 @@ Gem::Specification.new do |s|
|
|||||||
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
||||||
s.add_runtime_dependency(%q<thor>, [">= 0.14.0"])
|
s.add_runtime_dependency(%q<thor>, [">= 0.14.0"])
|
||||||
s.add_development_dependency(%q<rake>, [">= 0.8.7"])
|
s.add_development_dependency(%q<rake>, [">= 0.8.7"])
|
||||||
s.add_development_dependency(%q<rspec>, ["~> 2.10"])
|
s.add_development_dependency(%q<rspec>, ["~> 3.1.0"])
|
||||||
s.add_development_dependency(%q<guard>, [">= 0"])
|
s.add_development_dependency(%q<guard>, [">= 0"])
|
||||||
s.add_development_dependency(%q<guard-rspec>, [">= 0"])
|
s.add_development_dependency(%q<guard-rspec>, [">= 0"])
|
||||||
s.add_development_dependency(%q<rb-readline>, ["~> 0.5.0"])
|
s.add_development_dependency(%q<rb-readline>, ["~> 0.5.0"])
|
||||||
@@ -67,7 +66,7 @@ Gem::Specification.new do |s|
|
|||||||
else
|
else
|
||||||
s.add_dependency(%q<thor>, [">= 0.14.0"])
|
s.add_dependency(%q<thor>, [">= 0.14.0"])
|
||||||
s.add_dependency(%q<rake>, [">= 0.8.7"])
|
s.add_dependency(%q<rake>, [">= 0.8.7"])
|
||||||
s.add_dependency(%q<rspec>, ["~> 2.10"])
|
s.add_dependency(%q<rspec>, ["~> 3.1.0"])
|
||||||
s.add_dependency(%q<guard>, [">= 0"])
|
s.add_dependency(%q<guard>, [">= 0"])
|
||||||
s.add_dependency(%q<guard-rspec>, [">= 0"])
|
s.add_dependency(%q<guard-rspec>, [">= 0"])
|
||||||
s.add_dependency(%q<rb-readline>, ["~> 0.5.0"])
|
s.add_dependency(%q<rb-readline>, ["~> 0.5.0"])
|
||||||
@@ -80,7 +79,7 @@ Gem::Specification.new do |s|
|
|||||||
else
|
else
|
||||||
s.add_dependency(%q<thor>, [">= 0.14.0"])
|
s.add_dependency(%q<thor>, [">= 0.14.0"])
|
||||||
s.add_dependency(%q<rake>, [">= 0.8.7"])
|
s.add_dependency(%q<rake>, [">= 0.8.7"])
|
||||||
s.add_dependency(%q<rspec>, ["~> 2.10"])
|
s.add_dependency(%q<rspec>, ["~> 3.1.0"])
|
||||||
s.add_dependency(%q<guard>, [">= 0"])
|
s.add_dependency(%q<guard>, [">= 0"])
|
||||||
s.add_dependency(%q<guard-rspec>, [">= 0"])
|
s.add_dependency(%q<guard-rspec>, [">= 0"])
|
||||||
s.add_dependency(%q<rb-readline>, ["~> 0.5.0"])
|
s.add_dependency(%q<rb-readline>, ["~> 0.5.0"])
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
# -*- encoding : utf-8 -*-
|
# -*- encoding : utf-8 -*-
|
||||||
require 'homesick/shell'
|
|
||||||
require 'homesick/actions/file_actions'
|
require 'homesick/actions/file_actions'
|
||||||
require 'homesick/actions/git_actions'
|
require 'homesick/actions/git_actions'
|
||||||
require 'homesick/version'
|
require 'homesick/version'
|
||||||
|
|||||||
@@ -3,6 +3,25 @@ module Homesick
|
|||||||
module Actions
|
module Actions
|
||||||
# Git-related helper methods for Homesick
|
# Git-related helper methods for Homesick
|
||||||
module GitActions
|
module GitActions
|
||||||
|
# Information on the minimum git version required for Homesick
|
||||||
|
MIN_VERSION = {
|
||||||
|
major: 1,
|
||||||
|
minor: 8,
|
||||||
|
patch: 0
|
||||||
|
}
|
||||||
|
STRING = MIN_VERSION.values.join('.')
|
||||||
|
|
||||||
|
def git_version_correct?
|
||||||
|
info = `git --version`.scan(/(\d+)\.(\d+)\.(\d+)/).flatten.map(&:to_i)
|
||||||
|
return false unless info.count == 3
|
||||||
|
current_version = Hash[ [:major, :minor, :patch].zip(info) ]
|
||||||
|
return true if current_version.eql?(MIN_VERSION)
|
||||||
|
return true if current_version[:major] > MIN_VERSION[:major]
|
||||||
|
return true if current_version[:major] == MIN_VERSION[:major] && current_version[:minor] > MIN_VERSION[:minor]
|
||||||
|
return true if current_version[:major] == MIN_VERSION[:major] && current_version[:minor] == MIN_VERSION[:minor] && current_version[:patch] >= MIN_VERSION[:patch]
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
# TODO: move this to be more like thor's template, empty_directory, etc
|
# TODO: move this to be more like thor's template, empty_directory, etc
|
||||||
def git_clone(repo, config = {})
|
def git_clone(repo, config = {})
|
||||||
config ||= {}
|
config ||= {}
|
||||||
|
|||||||
@@ -19,7 +19,24 @@ module Homesick
|
|||||||
|
|
||||||
def initialize(args = [], options = {}, config = {})
|
def initialize(args = [], options = {}, config = {})
|
||||||
super
|
super
|
||||||
self.shell = Homesick::Shell.new
|
# Check if git is installed
|
||||||
|
unless git_version_correct?
|
||||||
|
say_status :error, "Git version >= #{Homesick::Actions::GitActions::STRING} must be installed to use Homesick", :red
|
||||||
|
exit(1)
|
||||||
|
end
|
||||||
|
# Hack in support for diffing symlinks
|
||||||
|
self.shell = Thor::Shell::Color.new
|
||||||
|
class << shell
|
||||||
|
def show_diff(destination, content)
|
||||||
|
destination = Pathname.new(destination)
|
||||||
|
if destination.symlink?
|
||||||
|
say "- #{destination.readlink}", :red, true
|
||||||
|
say "+ #{content.expand_path}", :green, true
|
||||||
|
else
|
||||||
|
super
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
desc 'clone URI', 'Clone +uri+ as a castle for homesick'
|
desc 'clone URI', 'Clone +uri+ as a castle for homesick'
|
||||||
@@ -49,12 +66,15 @@ module Homesick
|
|||||||
end
|
end
|
||||||
|
|
||||||
desc 'rc CASTLE', 'Run the .homesickrc for the specified castle'
|
desc 'rc CASTLE', 'Run the .homesickrc for the specified castle'
|
||||||
|
method_option :force,
|
||||||
|
default: false,
|
||||||
|
desc: 'Evaluate .homesickrc without prompting.'
|
||||||
def rc(name = DEFAULT_CASTLE_NAME)
|
def rc(name = DEFAULT_CASTLE_NAME)
|
||||||
inside repos_dir do
|
inside repos_dir do
|
||||||
destination = Pathname.new(name)
|
destination = Pathname.new(name)
|
||||||
homesickrc = destination.join('.homesickrc').expand_path
|
homesickrc = destination.join('.homesickrc').expand_path
|
||||||
if homesickrc.exist?
|
if homesickrc.exist?
|
||||||
proceed = shell.yes?("#{name} has a .homesickrc. Proceed with evaling it? (This could be destructive)")
|
proceed = options[:force] || shell.yes?("#{name} has a .homesickrc. Proceed with evaling it? (This could be destructive)")
|
||||||
if proceed
|
if proceed
|
||||||
say_status 'eval', homesickrc
|
say_status 'eval', homesickrc
|
||||||
inside destination do
|
inside destination do
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
require 'thor'
|
|
||||||
|
|
||||||
module Homesick
|
|
||||||
# Hack in support for diffing symlinks
|
|
||||||
class Shell < Thor::Shell::Color
|
|
||||||
def show_diff(destination, content)
|
|
||||||
destination = Pathname.new(destination)
|
|
||||||
|
|
||||||
if destination.symlink?
|
|
||||||
say "- #{destination.readlink}", :red, true
|
|
||||||
say "+ #{content.expand_path}", :green, true
|
|
||||||
else
|
|
||||||
super
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -21,7 +21,7 @@ module Homesick
|
|||||||
protected
|
protected
|
||||||
|
|
||||||
def home_dir
|
def home_dir
|
||||||
@home_dir ||= Pathname.new(ENV['HOME'] || '~').expand_path
|
@home_dir ||= Pathname.new(ENV['HOME'] || '~').realpath
|
||||||
end
|
end
|
||||||
|
|
||||||
def repos_dir
|
def repos_dir
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ module Homesick
|
|||||||
module Version
|
module Version
|
||||||
MAJOR = 1
|
MAJOR = 1
|
||||||
MINOR = 1
|
MINOR = 1
|
||||||
PATCH = 0
|
PATCH = 2
|
||||||
|
|
||||||
STRING = [MAJOR, MINOR, PATCH].compact.join('.')
|
STRING = [MAJOR, MINOR, PATCH].compact.join('.')
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
# -*- encoding : utf-8 -*-
|
# -*- encoding : utf-8 -*-
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
require 'capture-output'
|
require 'capture-output'
|
||||||
|
require 'pathname'
|
||||||
|
|
||||||
describe Homesick::CLI do
|
describe Homesick::CLI do
|
||||||
let(:home) { create_construct }
|
let(:home) { create_construct }
|
||||||
@@ -12,6 +13,49 @@ describe Homesick::CLI do
|
|||||||
|
|
||||||
before { allow(homesick).to receive(:repos_dir).and_return(castles) }
|
before { allow(homesick).to receive(:repos_dir).and_return(castles) }
|
||||||
|
|
||||||
|
describe 'smoke tests' do
|
||||||
|
context 'when running bin/homesick' do
|
||||||
|
before do
|
||||||
|
bin_path = Pathname.new(__FILE__).parent.parent
|
||||||
|
@output = `#{bin_path.expand_path}/bin/homesick`
|
||||||
|
end
|
||||||
|
it 'should output some text when bin/homesick is called' do
|
||||||
|
expect(@output.length).to be > 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when a git version that doesn\'t meet the minimum required is installed' do
|
||||||
|
before do
|
||||||
|
expect_any_instance_of(Homesick::Actions::GitActions).to receive(:`).and_return("git version 1.7.6")
|
||||||
|
end
|
||||||
|
it 'should raise an exception' do
|
||||||
|
output = Capture.stdout{ expect{Homesick::CLI.new}.to raise_error SystemExit }
|
||||||
|
expect(output.chomp).to include(Homesick::Actions::GitActions::STRING)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when a git version that is the same as the minimum required is installed' do
|
||||||
|
before do
|
||||||
|
expect_any_instance_of(Homesick::Actions::GitActions).to receive(:`).at_least(:once).and_return("git version #{Homesick::Actions::GitActions::STRING}")
|
||||||
|
end
|
||||||
|
it 'should not raise an exception' do
|
||||||
|
output = Capture.stdout{ expect{Homesick::CLI.new}.not_to raise_error }
|
||||||
|
expect(output.chomp).not_to include(Homesick::Actions::GitActions::STRING)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when a git version that is greater than the minimum required is installed' do
|
||||||
|
before do
|
||||||
|
expect_any_instance_of(Homesick::Actions::GitActions).to receive(:`).at_least(:once).and_return("git version 3.9.8")
|
||||||
|
end
|
||||||
|
it 'should not raise an exception' do
|
||||||
|
output = Capture.stdout{ expect{Homesick::CLI.new}.not_to raise_error }
|
||||||
|
expect(output.chomp).not_to include(Homesick::Actions::GitActions::STRING)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe 'clone' do
|
describe 'clone' do
|
||||||
context 'has a .homesickrc' do
|
context 'has a .homesickrc' do
|
||||||
it 'runs the .homesickrc' do
|
it 'runs the .homesickrc' do
|
||||||
@@ -63,7 +107,7 @@ describe Homesick::CLI do
|
|||||||
homesick.clone "file://#{bare_repo}"
|
homesick.clone "file://#{bare_repo}"
|
||||||
end
|
end
|
||||||
expect(File.directory?(File.join(home.to_s, '.homesick/repos/dotfiles')))
|
expect(File.directory?(File.join(home.to_s, '.homesick/repos/dotfiles')))
|
||||||
.to be_true
|
.to be_truthy
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'clones git repo like git://host/path/to.git' do
|
it 'clones git repo like git://host/path/to.git' do
|
||||||
@@ -136,6 +180,26 @@ describe Homesick::CLI do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when options[:force] == true' do
|
||||||
|
let(:homesick) { Homesick::CLI.new [], force: true }
|
||||||
|
before do
|
||||||
|
expect_any_instance_of(Thor::Shell::Basic).to_not receive(:yes?)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'executes the .homesickrc' do
|
||||||
|
castle.file('.homesickrc') do |file|
|
||||||
|
file << "File.open(Dir.pwd + '/testing', 'w') do |f|
|
||||||
|
f.print 'testing'
|
||||||
|
end"
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(homesick).to receive(:say_status).with('eval', kind_of(Pathname))
|
||||||
|
homesick.rc castle
|
||||||
|
|
||||||
|
expect(castle.join('testing')).to exist
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'when told not to do so' do
|
context 'when told not to do so' do
|
||||||
before do
|
before do
|
||||||
expect_any_instance_of(Thor::Shell::Basic).to receive(:yes?).with(be_a(String)).and_return(false)
|
expect_any_instance_of(Thor::Shell::Basic).to receive(:yes?).with(be_a(String)).and_return(false)
|
||||||
@@ -671,7 +735,7 @@ describe Homesick::CLI do
|
|||||||
describe 'version' do
|
describe 'version' do
|
||||||
it 'prints the current version of homesick' do
|
it 'prints the current version of homesick' do
|
||||||
text = Capture.stdout { homesick.version }
|
text = Capture.stdout { homesick.version }
|
||||||
expect(text.chomp).to match(/\d+\.\d+\.\d+/)
|
expect(text.chomp).to match(/#{Regexp.escape(Homesick::Version::STRING)}/)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
|
|||||||
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
||||||
require 'homesick'
|
require 'homesick'
|
||||||
require 'rspec'
|
require 'rspec'
|
||||||
require 'rspec/autorun'
|
|
||||||
require 'test_construct'
|
require 'test_construct'
|
||||||
require 'tempfile'
|
require 'tempfile'
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user