mirror of https://github.com/tootsuite/mastodon
Handle CLI failure exit status at the top-level script (#28322)
parent
881e8c113c
commit
0e0a94f483
|
@ -96,12 +96,11 @@ Rails/FilePath:
|
||||||
Rails/HttpStatus:
|
Rails/HttpStatus:
|
||||||
EnforcedStyle: numeric
|
EnforcedStyle: numeric
|
||||||
|
|
||||||
# Reason: Allowed in `tootctl` CLI code and in boot ENV checker
|
# Reason: Allowed in boot ENV checker
|
||||||
# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railsexit
|
# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railsexit
|
||||||
Rails/Exit:
|
Rails/Exit:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'config/boot.rb'
|
- 'config/boot.rb'
|
||||||
- 'lib/mastodon/cli/*.rb'
|
|
||||||
|
|
||||||
# Reason: Conflicts with `Lint/UselessMethodDefinition` for inherited controller actions
|
# Reason: Conflicts with `Lint/UselessMethodDefinition` for inherited controller actions
|
||||||
# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railslexicallyscopedactionfilter
|
# https://docs.rubocop.org/rubocop-rails/cops_rails.html#railslexicallyscopedactionfilter
|
||||||
|
|
|
@ -6,8 +6,13 @@ require_relative '../lib/mastodon/cli/main'
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Chewy.strategy(:mastodon) do
|
Chewy.strategy(:mastodon) do
|
||||||
Mastodon::CLI::Main.start(ARGV)
|
Mastodon::CLI::Main.start(ARGV, debug: true) # Enables the script to rescue `Thor::Error`
|
||||||
end
|
end
|
||||||
|
rescue Thor::Error => e
|
||||||
|
Thor::Shell::Color
|
||||||
|
.new
|
||||||
|
.say_error(e.message, :red)
|
||||||
|
exit(1)
|
||||||
rescue Interrupt
|
rescue Interrupt
|
||||||
exit(130)
|
exit(130)
|
||||||
end
|
end
|
||||||
|
|
|
@ -39,8 +39,7 @@ module Mastodon::CLI
|
||||||
rotate_keys_for_account(Account.find_local(username))
|
rotate_keys_for_account(Account.find_local(username))
|
||||||
say('OK', :green)
|
say('OK', :green)
|
||||||
else
|
else
|
||||||
say('No account(s) given', :red)
|
fail_with_message 'No account(s) given'
|
||||||
exit(1)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -74,10 +73,7 @@ module Mastodon::CLI
|
||||||
if options[:role]
|
if options[:role]
|
||||||
role = UserRole.find_by(name: options[:role])
|
role = UserRole.find_by(name: options[:role])
|
||||||
|
|
||||||
if role.nil?
|
fail_with_message 'Cannot find user role with that name' if role.nil?
|
||||||
say('Cannot find user role with that name', :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
role_id = role.id
|
role_id = role.id
|
||||||
end
|
end
|
||||||
|
@ -114,7 +110,6 @@ module Mastodon::CLI
|
||||||
say("New password: #{password}")
|
say("New password: #{password}")
|
||||||
else
|
else
|
||||||
report_errors(user.errors)
|
report_errors(user.errors)
|
||||||
exit(1)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -152,18 +147,12 @@ module Mastodon::CLI
|
||||||
def modify(username)
|
def modify(username)
|
||||||
user = Account.find_local(username)&.user
|
user = Account.find_local(username)&.user
|
||||||
|
|
||||||
if user.nil?
|
fail_with_message 'No user with such username' if user.nil?
|
||||||
say('No user with such username', :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
if options[:role]
|
if options[:role]
|
||||||
role = UserRole.find_by(name: options[:role])
|
role = UserRole.find_by(name: options[:role])
|
||||||
|
|
||||||
if role.nil?
|
fail_with_message 'Cannot find user role with that name' if role.nil?
|
||||||
say('Cannot find user role with that name', :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
user.role_id = role.id
|
user.role_id = role.id
|
||||||
elsif options[:remove_role]
|
elsif options[:remove_role]
|
||||||
|
@ -185,7 +174,6 @@ module Mastodon::CLI
|
||||||
say("New password: #{password}") if options[:reset_password]
|
say("New password: #{password}") if options[:reset_password]
|
||||||
else
|
else
|
||||||
report_errors(user.errors)
|
report_errors(user.errors)
|
||||||
exit(1)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -200,27 +188,19 @@ module Mastodon::CLI
|
||||||
LONG_DESC
|
LONG_DESC
|
||||||
def delete(username = nil)
|
def delete(username = nil)
|
||||||
if username.present? && options[:email].present?
|
if username.present? && options[:email].present?
|
||||||
say('Use username or --email, not both', :red)
|
fail_with_message 'Use username or --email, not both'
|
||||||
exit(1)
|
|
||||||
elsif username.blank? && options[:email].blank?
|
elsif username.blank? && options[:email].blank?
|
||||||
say('No username provided', :red)
|
fail_with_message 'No username provided'
|
||||||
exit(1)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
account = nil
|
account = nil
|
||||||
|
|
||||||
if username.present?
|
if username.present?
|
||||||
account = Account.find_local(username)
|
account = Account.find_local(username)
|
||||||
if account.nil?
|
fail_with_message 'No user with such username' if account.nil?
|
||||||
say('No user with such username', :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
account = Account.left_joins(:user).find_by(user: { email: options[:email] })
|
account = Account.left_joins(:user).find_by(user: { email: options[:email] })
|
||||||
if account.nil?
|
fail_with_message 'No user with such email' if account.nil?
|
||||||
say('No user with such email', :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
say("Deleting user with #{account.statuses_count} statuses, this might take a while...#{dry_run_mode_suffix}")
|
say("Deleting user with #{account.statuses_count} statuses, this might take a while...#{dry_run_mode_suffix}")
|
||||||
|
@ -243,23 +223,18 @@ module Mastodon::CLI
|
||||||
username, domain = from_acct.split('@')
|
username, domain = from_acct.split('@')
|
||||||
from_account = Account.find_remote(username, domain)
|
from_account = Account.find_remote(username, domain)
|
||||||
|
|
||||||
if from_account.nil? || from_account.local?
|
fail_with_message "No such account (#{from_acct})" if from_account.nil? || from_account.local?
|
||||||
say("No such account (#{from_acct})", :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
username, domain = to_acct.split('@')
|
username, domain = to_acct.split('@')
|
||||||
to_account = Account.find_remote(username, domain)
|
to_account = Account.find_remote(username, domain)
|
||||||
|
|
||||||
if to_account.nil? || to_account.local?
|
fail_with_message "No such account (#{to_acct})" if to_account.nil? || to_account.local?
|
||||||
say("No such account (#{to_acct})", :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
if from_account.public_key != to_account.public_key && !options[:force]
|
if from_account.public_key != to_account.public_key && !options[:force]
|
||||||
say("Accounts don't have the same public key, might not be duplicates!", :red)
|
fail_with_message <<~ERROR
|
||||||
say('Override with --force', :red)
|
Accounts don't have the same public key, might not be duplicates!
|
||||||
exit(1)
|
Override with --force
|
||||||
|
ERROR
|
||||||
end
|
end
|
||||||
|
|
||||||
to_account.merge_with!(from_account)
|
to_account.merge_with!(from_account)
|
||||||
|
@ -298,10 +273,7 @@ module Mastodon::CLI
|
||||||
def backup(username)
|
def backup(username)
|
||||||
account = Account.find_local(username)
|
account = Account.find_local(username)
|
||||||
|
|
||||||
if account.nil?
|
fail_with_message 'No user with such username' if account.nil?
|
||||||
say('No user with such username', :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
backup = account.user.backups.create!
|
backup = account.user.backups.create!
|
||||||
BackupWorker.perform_async(backup.id)
|
BackupWorker.perform_async(backup.id)
|
||||||
|
@ -387,10 +359,7 @@ module Mastodon::CLI
|
||||||
user, domain = user.split('@')
|
user, domain = user.split('@')
|
||||||
account = Account.find_remote(user, domain)
|
account = Account.find_remote(user, domain)
|
||||||
|
|
||||||
if account.nil?
|
fail_with_message 'No such account' if account.nil?
|
||||||
say('No such account', :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
next if dry_run?
|
next if dry_run?
|
||||||
|
|
||||||
|
@ -405,8 +374,7 @@ module Mastodon::CLI
|
||||||
|
|
||||||
say("OK#{dry_run_mode_suffix}", :green)
|
say("OK#{dry_run_mode_suffix}", :green)
|
||||||
else
|
else
|
||||||
say('No account(s) given', :red)
|
fail_with_message 'No account(s) given'
|
||||||
exit(1)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -416,10 +384,7 @@ module Mastodon::CLI
|
||||||
def follow(username)
|
def follow(username)
|
||||||
target_account = Account.find_local(username)
|
target_account = Account.find_local(username)
|
||||||
|
|
||||||
if target_account.nil?
|
fail_with_message 'No such account' if target_account.nil?
|
||||||
say('No such account', :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
processed, = parallelize_with_progress(Account.local.without_suspended) do |account|
|
processed, = parallelize_with_progress(Account.local.without_suspended) do |account|
|
||||||
FollowService.new.call(account, target_account, bypass_limit: true)
|
FollowService.new.call(account, target_account, bypass_limit: true)
|
||||||
|
@ -435,10 +400,7 @@ module Mastodon::CLI
|
||||||
username, domain = acct.split('@')
|
username, domain = acct.split('@')
|
||||||
target_account = Account.find_remote(username, domain)
|
target_account = Account.find_remote(username, domain)
|
||||||
|
|
||||||
if target_account.nil?
|
fail_with_message 'No such account' if target_account.nil?
|
||||||
say('No such account', :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
processed, = parallelize_with_progress(target_account.followers.local) do |account|
|
processed, = parallelize_with_progress(target_account.followers.local) do |account|
|
||||||
UnfollowService.new.call(account, target_account)
|
UnfollowService.new.call(account, target_account)
|
||||||
|
@ -459,17 +421,11 @@ module Mastodon::CLI
|
||||||
With the --followers option, the command removes all followers of the account.
|
With the --followers option, the command removes all followers of the account.
|
||||||
LONG_DESC
|
LONG_DESC
|
||||||
def reset_relationships(username)
|
def reset_relationships(username)
|
||||||
unless options[:follows] || options[:followers]
|
fail_with_message 'Please specify either --follows or --followers, or both' unless options[:follows] || options[:followers]
|
||||||
say('Please specify either --follows or --followers, or both', :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
account = Account.find_local(username)
|
account = Account.find_local(username)
|
||||||
|
|
||||||
if account.nil?
|
fail_with_message 'No such account' if account.nil?
|
||||||
say('No such account', :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
total = 0
|
total = 0
|
||||||
total += account.following.reorder(nil).count if options[:follows]
|
total += account.following.reorder(nil).count if options[:follows]
|
||||||
|
@ -515,6 +471,8 @@ module Mastodon::CLI
|
||||||
account identified by its username.
|
account identified by its username.
|
||||||
LONG_DESC
|
LONG_DESC
|
||||||
def approve(username = nil)
|
def approve(username = nil)
|
||||||
|
fail_with_message 'Number must be positive' if options[:number]&.negative?
|
||||||
|
|
||||||
if options[:all]
|
if options[:all]
|
||||||
User.pending.find_each(&:approve!)
|
User.pending.find_each(&:approve!)
|
||||||
say('OK', :green)
|
say('OK', :green)
|
||||||
|
@ -524,16 +482,10 @@ module Mastodon::CLI
|
||||||
elsif username.present?
|
elsif username.present?
|
||||||
account = Account.find_local(username)
|
account = Account.find_local(username)
|
||||||
|
|
||||||
if account.nil?
|
fail_with_message 'No such account' if account.nil?
|
||||||
say('No such account', :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
account.user&.approve!
|
account.user&.approve!
|
||||||
say('OK', :green)
|
say('OK', :green)
|
||||||
else
|
|
||||||
say('Number must be positive', :red) if options[:number]
|
|
||||||
exit(1)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -587,56 +539,34 @@ module Mastodon::CLI
|
||||||
redirects to a different account that the one specified.
|
redirects to a different account that the one specified.
|
||||||
LONG_DESC
|
LONG_DESC
|
||||||
def migrate(username)
|
def migrate(username)
|
||||||
if options[:replay].present? && options[:target].present?
|
fail_with_message 'Use --replay or --target, not both' if options[:replay].present? && options[:target].present?
|
||||||
say('Use --replay or --target, not both', :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
if options[:replay].blank? && options[:target].blank?
|
fail_with_message 'Use either --replay or --target' if options[:replay].blank? && options[:target].blank?
|
||||||
say('Use either --replay or --target', :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
account = Account.find_local(username)
|
account = Account.find_local(username)
|
||||||
|
|
||||||
if account.nil?
|
fail_with_message "No such account: #{username}" if account.nil?
|
||||||
say("No such account: #{username}", :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
migration = nil
|
migration = nil
|
||||||
|
|
||||||
if options[:replay]
|
if options[:replay]
|
||||||
migration = account.migrations.last
|
migration = account.migrations.last
|
||||||
if migration.nil?
|
fail_with_message 'The specified account has not performed any migration' if migration.nil?
|
||||||
say('The specified account has not performed any migration', :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
unless options[:force] || migration.target_account_id == account.moved_to_account_id
|
fail_with_message 'The specified account is not redirecting to its last migration target. Use --force if you want to replay the migration anyway' unless options[:force] || migration.target_account_id == account.moved_to_account_id
|
||||||
say('The specified account is not redirecting to its last migration target. Use --force if you want to replay the migration anyway', :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if options[:target]
|
if options[:target]
|
||||||
target_account = ResolveAccountService.new.call(options[:target])
|
target_account = ResolveAccountService.new.call(options[:target])
|
||||||
|
|
||||||
if target_account.nil?
|
fail_with_message "The specified target account could not be found: #{options[:target]}" if target_account.nil?
|
||||||
say("The specified target account could not be found: #{options[:target]}", :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
unless options[:force] || account.moved_to_account_id.nil? || account.moved_to_account_id == target_account.id
|
fail_with_message 'The specified account is redirecting to a different target account. Use --force if you want to change the migration target' unless options[:force] || account.moved_to_account_id.nil? || account.moved_to_account_id == target_account.id
|
||||||
say('The specified account is redirecting to a different target account. Use --force if you want to change the migration target', :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
begin
|
begin
|
||||||
migration = account.migrations.create!(acct: target_account.acct)
|
migration = account.migrations.create!(acct: target_account.acct)
|
||||||
rescue ActiveRecord::RecordInvalid => e
|
rescue ActiveRecord::RecordInvalid => e
|
||||||
say("Error: #{e.message}", :red)
|
fail_with_message "Error: #{e.message}"
|
||||||
exit(1)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -648,18 +578,18 @@ module Mastodon::CLI
|
||||||
private
|
private
|
||||||
|
|
||||||
def report_errors(errors)
|
def report_errors(errors)
|
||||||
errors.each do |error|
|
message = errors.map do |error|
|
||||||
say('Failure/Error: ', :red)
|
<<~STRING
|
||||||
say(error.attribute)
|
Failure/Error: #{error.attribute}
|
||||||
say(" #{error.type}", :red)
|
#{error.type}
|
||||||
end
|
STRING
|
||||||
|
end.join
|
||||||
|
|
||||||
|
fail_with_message message
|
||||||
end
|
end
|
||||||
|
|
||||||
def rotate_keys_for_account(account, delay = 0)
|
def rotate_keys_for_account(account, delay = 0)
|
||||||
if account.nil?
|
fail_with_message 'No such account' if account.nil?
|
||||||
say('No such account', :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
old_key = account.private_key
|
old_key = account.private_key
|
||||||
new_key = OpenSSL::PKey::RSA.new(2048)
|
new_key = OpenSSL::PKey::RSA.new(2048)
|
||||||
|
|
|
@ -18,6 +18,10 @@ module Mastodon
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def fail_with_message(message)
|
||||||
|
raise Thor::Error, message
|
||||||
|
end
|
||||||
|
|
||||||
def pastel
|
def pastel
|
||||||
@pastel ||= Pastel.new
|
@pastel ||= Pastel.new
|
||||||
end
|
end
|
||||||
|
|
|
@ -31,8 +31,7 @@ module Mastodon::CLI
|
||||||
recount_status_stats(status)
|
recount_status_stats(status)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
say("Unknown type: #{type}", :red)
|
fail_with_message "Unknown type: #{type}"
|
||||||
exit(1)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
say
|
say
|
||||||
|
|
|
@ -41,11 +41,9 @@ module Mastodon::CLI
|
||||||
|
|
||||||
# Sanity check on command arguments
|
# Sanity check on command arguments
|
||||||
if options[:limited_federation_mode] && !domains.empty?
|
if options[:limited_federation_mode] && !domains.empty?
|
||||||
say('DOMAIN parameter not supported with --limited-federation-mode', :red)
|
fail_with_message 'DOMAIN parameter not supported with --limited-federation-mode'
|
||||||
exit(1)
|
|
||||||
elsif domains.empty? && !options[:limited_federation_mode]
|
elsif domains.empty? && !options[:limited_federation_mode]
|
||||||
say('No domain(s) given', :red)
|
fail_with_message 'No domain(s) given'
|
||||||
exit(1)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Build scopes from command arguments
|
# Build scopes from command arguments
|
||||||
|
|
|
@ -30,10 +30,7 @@ module Mastodon::CLI
|
||||||
it at the root.
|
it at the root.
|
||||||
LONG_DESC
|
LONG_DESC
|
||||||
def add(*domains)
|
def add(*domains)
|
||||||
if domains.empty?
|
fail_with_message 'No domain(s) given' if domains.empty?
|
||||||
say('No domain(s) given', :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
skipped = 0
|
skipped = 0
|
||||||
processed = 0
|
processed = 0
|
||||||
|
@ -76,10 +73,7 @@ module Mastodon::CLI
|
||||||
|
|
||||||
desc 'remove DOMAIN...', 'Remove e-mail domain blocks'
|
desc 'remove DOMAIN...', 'Remove e-mail domain blocks'
|
||||||
def remove(*domains)
|
def remove(*domains)
|
||||||
if domains.empty?
|
fail_with_message 'No domain(s) given' if domains.empty?
|
||||||
say('No domain(s) given', :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
skipped = 0
|
skipped = 0
|
||||||
processed = 0
|
processed = 0
|
||||||
|
|
|
@ -86,14 +86,8 @@ module Mastodon::CLI
|
||||||
category = CustomEmojiCategory.find_by(name: options[:category])
|
category = CustomEmojiCategory.find_by(name: options[:category])
|
||||||
export_file_name = File.join(path, 'export.tar.gz')
|
export_file_name = File.join(path, 'export.tar.gz')
|
||||||
|
|
||||||
if File.file?(export_file_name) && !options[:overwrite]
|
fail_with_message "Archive already exists! Use '--overwrite' to overwrite it!" if File.file?(export_file_name) && !options[:overwrite]
|
||||||
say("Archive already exists! Use '--overwrite' to overwrite it!")
|
fail_with_message "Unable to find category '#{options[:category]}'!" if category.nil? && options[:category]
|
||||||
exit 1
|
|
||||||
end
|
|
||||||
if category.nil? && options[:category]
|
|
||||||
say("Unable to find category '#{options[:category]}'!")
|
|
||||||
exit 1
|
|
||||||
end
|
|
||||||
|
|
||||||
File.open(export_file_name, 'wb') do |file|
|
File.open(export_file_name, 'wb') do |file|
|
||||||
Zlib::GzipWriter.wrap(file) do |gzip|
|
Zlib::GzipWriter.wrap(file) do |gzip|
|
||||||
|
|
|
@ -43,10 +43,10 @@ module Mastodon::CLI
|
||||||
say('Every deletion notice has been sent! You can safely delete all data and decomission your servers!', :green)
|
say('Every deletion notice has been sent! You can safely delete all data and decomission your servers!', :green)
|
||||||
end
|
end
|
||||||
|
|
||||||
exit(0)
|
raise(SystemExit)
|
||||||
end
|
end
|
||||||
|
|
||||||
exit(1) unless ask('Type in the domain of the server to confirm:') == Rails.configuration.x.local_domain
|
fail_with_message 'Domains do not match. Stopping self-destruct initiation.' unless domain_match_confirmed?
|
||||||
|
|
||||||
say(<<~WARNING, :yellow)
|
say(<<~WARNING, :yellow)
|
||||||
This operation WILL NOT be reversible.
|
This operation WILL NOT be reversible.
|
||||||
|
@ -54,19 +54,25 @@ module Mastodon::CLI
|
||||||
The deletion process itself may take a long time, and will be handled by Sidekiq, so do not shut it down until it has finished (you will be able to re-run this command to see the state of the self-destruct process).
|
The deletion process itself may take a long time, and will be handled by Sidekiq, so do not shut it down until it has finished (you will be able to re-run this command to see the state of the self-destruct process).
|
||||||
WARNING
|
WARNING
|
||||||
|
|
||||||
exit(1) if no?('Are you sure you want to proceed?')
|
fail_with_message 'Operation cancelled. Self-destruct will not begin.' if proceed_prompt_negative?
|
||||||
|
|
||||||
say(<<~INSTRUCTIONS, :green)
|
say(<<~INSTRUCTIONS, :green)
|
||||||
To switch Mastodon to self-destruct mode, add the following variable to your evironment (e.g. by adding a line to your `.env.production`) and restart all Mastodon processes:
|
To switch Mastodon to self-destruct mode, add the following variable to your evironment (e.g. by adding a line to your `.env.production`) and restart all Mastodon processes:
|
||||||
SELF_DESTRUCT=#{self_destruct_value}
|
SELF_DESTRUCT=#{self_destruct_value}
|
||||||
You can re-run this command to see the state of the self-destruct process.
|
You can re-run this command to see the state of the self-destruct process.
|
||||||
INSTRUCTIONS
|
INSTRUCTIONS
|
||||||
rescue Interrupt
|
|
||||||
exit(1)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def domain_match_confirmed?
|
||||||
|
ask('Type in the domain of the server to confirm:') == Rails.configuration.x.local_domain
|
||||||
|
end
|
||||||
|
|
||||||
|
def proceed_prompt_negative?
|
||||||
|
no?('Are you sure you want to proceed?')
|
||||||
|
end
|
||||||
|
|
||||||
def self_destruct_value
|
def self_destruct_value
|
||||||
Rails
|
Rails
|
||||||
.application
|
.application
|
||||||
|
|
|
@ -27,17 +27,13 @@ module Mastodon::CLI
|
||||||
elsif username.present?
|
elsif username.present?
|
||||||
account = Account.find_local(username)
|
account = Account.find_local(username)
|
||||||
|
|
||||||
if account.nil?
|
fail_with_message 'No such account' if account.nil?
|
||||||
say('No such account', :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
PrecomputeFeedService.new.call(account) unless dry_run?
|
PrecomputeFeedService.new.call(account) unless dry_run?
|
||||||
|
|
||||||
say("OK #{dry_run_mode_suffix}", :green, true)
|
say("OK #{dry_run_mode_suffix}", :green, true)
|
||||||
else
|
else
|
||||||
say('No account(s) given', :red)
|
fail_with_message 'No account(s) given'
|
||||||
exit(1)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -20,10 +20,7 @@ module Mastodon::CLI
|
||||||
option to overwrite it.
|
option to overwrite it.
|
||||||
LONG_DESC
|
LONG_DESC
|
||||||
def add(*addresses)
|
def add(*addresses)
|
||||||
if addresses.empty?
|
fail_with_message 'No IP(s) given' if addresses.empty?
|
||||||
say('No IP(s) given', :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
skipped = 0
|
skipped = 0
|
||||||
processed = 0
|
processed = 0
|
||||||
|
@ -70,10 +67,7 @@ module Mastodon::CLI
|
||||||
cover the given IP(s).
|
cover the given IP(s).
|
||||||
LONG_DESC
|
LONG_DESC
|
||||||
def remove(*addresses)
|
def remove(*addresses)
|
||||||
if addresses.empty?
|
fail_with_message 'No IP(s) given' if addresses.empty?
|
||||||
say('No IP(s) given', :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
processed = 0
|
processed = 0
|
||||||
skipped = 0
|
skipped = 0
|
||||||
|
|
|
@ -199,26 +199,24 @@ module Mastodon::CLI
|
||||||
|
|
||||||
def verify_schema_version!
|
def verify_schema_version!
|
||||||
if migrator_version < MIN_SUPPORTED_VERSION
|
if migrator_version < MIN_SUPPORTED_VERSION
|
||||||
say 'Your version of the database schema is too old and is not supported by this script.', :red
|
fail_with_message <<~ERROR
|
||||||
say 'Please update to at least Mastodon 3.0.0 before running this script.', :red
|
Your version of the database schema is too old and is not supported by this script.
|
||||||
exit(1)
|
Please update to at least Mastodon 3.0.0 before running this script.
|
||||||
|
ERROR
|
||||||
elsif migrator_version > MAX_SUPPORTED_VERSION
|
elsif migrator_version > MAX_SUPPORTED_VERSION
|
||||||
say 'Your version of the database schema is more recent than this script, this may cause unexpected errors.', :yellow
|
say 'Your version of the database schema is more recent than this script, this may cause unexpected errors.', :yellow
|
||||||
exit(1) unless yes?('Continue anyway? (Yes/No)')
|
fail_with_message 'Stopping maintenance script because data is more recent than script version.' unless yes?('Continue anyway? (Yes/No)')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def verify_sidekiq_not_active!
|
def verify_sidekiq_not_active!
|
||||||
if Sidekiq::ProcessSet.new.any?
|
fail_with_message 'It seems Sidekiq is running. All Mastodon processes need to be stopped when using this script.' if Sidekiq::ProcessSet.new.any?
|
||||||
say 'It seems Sidekiq is running. All Mastodon processes need to be stopped when using this script.', :red
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def verify_backup_warning!
|
def verify_backup_warning!
|
||||||
say 'This task will take a long time to run and is potentially destructive.', :yellow
|
say 'This task will take a long time to run and is potentially destructive.', :yellow
|
||||||
say 'Please make sure to stop Mastodon and have a backup.', :yellow
|
say 'Please make sure to stop Mastodon and have a backup.', :yellow
|
||||||
exit(1) unless yes?('Continue? (Yes/No)')
|
fail_with_message 'Maintenance process stopped.' unless yes?('Continue? (Yes/No)')
|
||||||
end
|
end
|
||||||
|
|
||||||
def deduplicate_accounts!
|
def deduplicate_accounts!
|
||||||
|
|
|
@ -31,15 +31,9 @@ module Mastodon::CLI
|
||||||
following anyone locally are pruned.
|
following anyone locally are pruned.
|
||||||
DESC
|
DESC
|
||||||
def remove
|
def remove
|
||||||
if options[:prune_profiles] && options[:remove_headers]
|
fail_with_message '--prune-profiles and --remove-headers should not be specified simultaneously' if options[:prune_profiles] && options[:remove_headers]
|
||||||
say('--prune-profiles and --remove-headers should not be specified simultaneously', :red, true)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
if options[:include_follows] && !(options[:prune_profiles] || options[:remove_headers])
|
fail_with_message '--include-follows can only be used with --prune-profiles or --remove-headers' if options[:include_follows] && !(options[:prune_profiles] || options[:remove_headers])
|
||||||
say('--include-follows can only be used with --prune-profiles or --remove-headers', :red, true)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
time_ago = options[:days].days.ago
|
time_ago = options[:days].days.ago
|
||||||
|
|
||||||
if options[:prune_profiles] || options[:remove_headers]
|
if options[:prune_profiles] || options[:remove_headers]
|
||||||
|
@ -156,11 +150,9 @@ module Mastodon::CLI
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
when :fog
|
when :fog
|
||||||
say('The fog storage driver is not supported for this operation at this time', :red)
|
fail_with_message 'The fog storage driver is not supported for this operation at this time'
|
||||||
exit(1)
|
|
||||||
when :azure
|
when :azure
|
||||||
say('The azure storage driver is not supported for this operation at this time', :red)
|
fail_with_message 'The azure storage driver is not supported for this operation at this time'
|
||||||
exit(1)
|
|
||||||
when :filesystem
|
when :filesystem
|
||||||
require 'find'
|
require 'find'
|
||||||
|
|
||||||
|
@ -254,10 +246,7 @@ module Mastodon::CLI
|
||||||
username, domain = options[:account].split('@')
|
username, domain = options[:account].split('@')
|
||||||
account = Account.find_remote(username, domain)
|
account = Account.find_remote(username, domain)
|
||||||
|
|
||||||
if account.nil?
|
fail_with_message 'No such account' if account.nil?
|
||||||
say('No such account', :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
scope = MediaAttachment.where(account_id: account.id)
|
scope = MediaAttachment.where(account_id: account.id)
|
||||||
elsif options[:domain]
|
elsif options[:domain]
|
||||||
|
@ -265,8 +254,7 @@ module Mastodon::CLI
|
||||||
elsif options[:days].present?
|
elsif options[:days].present?
|
||||||
scope = MediaAttachment.remote
|
scope = MediaAttachment.remote
|
||||||
else
|
else
|
||||||
say('Specify the source of media attachments', :red)
|
fail_with_message 'Specify the source of media attachments'
|
||||||
exit(1)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
scope = scope.where('media_attachments.id > ?', Mastodon::Snowflake.id_at(options[:days].days.ago, with_random: false)) if options[:days].present?
|
scope = scope.where('media_attachments.id > ?', Mastodon::Snowflake.id_at(options[:days].days.ago, with_random: false)) if options[:days].present?
|
||||||
|
@ -306,38 +294,25 @@ module Mastodon::CLI
|
||||||
path_segments = path.split('/')[2..]
|
path_segments = path.split('/')[2..]
|
||||||
path_segments.delete('cache')
|
path_segments.delete('cache')
|
||||||
|
|
||||||
unless VALID_PATH_SEGMENTS_SIZE.include?(path_segments.size)
|
fail_with_message 'Not a media URL' unless VALID_PATH_SEGMENTS_SIZE.include?(path_segments.size)
|
||||||
say('Not a media URL', :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
model_name = path_segments.first.classify
|
model_name = path_segments.first.classify
|
||||||
record_id = path_segments[2..-2].join.to_i
|
record_id = path_segments[2..-2].join.to_i
|
||||||
|
|
||||||
unless PRELOAD_MODEL_WHITELIST.include?(model_name)
|
fail_with_message "Cannot find corresponding model: #{model_name}" unless PRELOAD_MODEL_WHITELIST.include?(model_name)
|
||||||
say("Cannot find corresponding model: #{model_name}", :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
record = model_name.constantize.find_by(id: record_id)
|
record = model_name.constantize.find_by(id: record_id)
|
||||||
record = record.status if record.respond_to?(:status)
|
record = record.status if record.respond_to?(:status)
|
||||||
|
|
||||||
unless record
|
fail_with_message 'Cannot find corresponding record' unless record
|
||||||
say('Cannot find corresponding record', :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
display_url = ActivityPub::TagManager.instance.url_for(record)
|
display_url = ActivityPub::TagManager.instance.url_for(record)
|
||||||
|
|
||||||
if display_url.blank?
|
fail_with_message 'No public URL for this type of record' if display_url.blank?
|
||||||
say('No public URL for this type of record', :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
say(display_url, :blue)
|
say(display_url, :blue)
|
||||||
rescue Addressable::URI::InvalidURIError
|
rescue Addressable::URI::InvalidURIError
|
||||||
say('Invalid URL', :red)
|
fail_with_message 'Invalid URL'
|
||||||
exit(1)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -25,10 +25,7 @@ module Mastodon::CLI
|
||||||
end
|
end
|
||||||
|
|
||||||
def parallelize_with_progress(scope)
|
def parallelize_with_progress(scope)
|
||||||
if options[:concurrency] < 1
|
fail_with_message 'Cannot run with this concurrency setting, must be at least 1' if options[:concurrency] < 1
|
||||||
say('Cannot run with this concurrency setting, must be at least 1', :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
reset_connection_pools!
|
reset_connection_pools!
|
||||||
|
|
||||||
|
|
|
@ -110,17 +110,11 @@ module Mastodon::CLI
|
||||||
end
|
end
|
||||||
|
|
||||||
def verify_deploy_concurrency!
|
def verify_deploy_concurrency!
|
||||||
return unless options[:concurrency] < 1
|
fail_with_message 'Cannot run with this concurrency setting, must be at least 1' if options[:concurrency] < 1
|
||||||
|
|
||||||
say('Cannot run with this concurrency setting, must be at least 1', :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def verify_deploy_batch_size!
|
def verify_deploy_batch_size!
|
||||||
return unless options[:batch_size] < 1
|
fail_with_message 'Cannot run with this batch_size setting, must be at least 1' if options[:batch_size] < 1
|
||||||
|
|
||||||
say('Cannot run with this batch_size setting, must be at least 1', :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def progress_output_options
|
def progress_output_options
|
||||||
|
|
|
@ -26,10 +26,7 @@ module Mastodon::CLI
|
||||||
indices before commencing, and removes them afterward.
|
indices before commencing, and removes them afterward.
|
||||||
LONG_DESC
|
LONG_DESC
|
||||||
def remove
|
def remove
|
||||||
if options[:batch_size] < 1
|
fail_with_message 'Cannot run with this batch_size setting, must be at least 1' if options[:batch_size] < 1
|
||||||
say('Cannot run with this batch_size setting, must be at least 1', :red)
|
|
||||||
exit(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
remove_statuses
|
remove_statuses
|
||||||
vacuum_and_analyze_statuses
|
vacuum_and_analyze_statuses
|
||||||
|
|
|
@ -103,13 +103,11 @@ module Mastodon::CLI
|
||||||
end
|
end
|
||||||
|
|
||||||
def upgrade_storage_fog(_progress, _attachment, _style)
|
def upgrade_storage_fog(_progress, _attachment, _style)
|
||||||
say('The fog storage driver is not supported for this operation at this time', :red)
|
fail_with_message 'The fog storage driver is not supported for this operation at this time'
|
||||||
exit(1)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def upgrade_storage_azure(_progress, _attachment, _style)
|
def upgrade_storage_azure(_progress, _attachment, _style)
|
||||||
say('The azure storage driver is not supported for this operation at this time', :red)
|
fail_with_message 'The azure storage driver is not supported for this operation at this time'
|
||||||
exit(1)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def upgrade_storage_filesystem(progress, attachment, style)
|
def upgrade_storage_filesystem(progress, attachment, style)
|
||||||
|
|
|
@ -65,8 +65,7 @@ describe Mastodon::CLI::Accounts do
|
||||||
|
|
||||||
it 'exits with an error message' do
|
it 'exits with an error message' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('Failure/Error: email')
|
.to raise_error(Thor::Error, %r{Failure/Error: email})
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -127,8 +126,7 @@ describe Mastodon::CLI::Accounts do
|
||||||
|
|
||||||
it 'exits with an error message indicating the role name was not found' do
|
it 'exits with an error message indicating the role name was not found' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('Cannot find user role with that name')
|
.to raise_error(Thor::Error, 'Cannot find user role with that name')
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -191,8 +189,7 @@ describe Mastodon::CLI::Accounts do
|
||||||
|
|
||||||
it 'exits with an error message indicating the user was not found' do
|
it 'exits with an error message indicating the user was not found' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('No user with such username')
|
.to raise_error(Thor::Error, 'No user with such username')
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -214,8 +211,7 @@ describe Mastodon::CLI::Accounts do
|
||||||
|
|
||||||
it 'exits with an error message indicating the role was not found' do
|
it 'exits with an error message indicating the role was not found' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('Cannot find user role with that name')
|
.to raise_error(Thor::Error, 'Cannot find user role with that name')
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -364,8 +360,7 @@ describe Mastodon::CLI::Accounts do
|
||||||
|
|
||||||
it 'exits with an error message' do
|
it 'exits with an error message' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('Failure/Error: email')
|
.to raise_error(Thor::Error, %r{Failure/Error: email})
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -387,16 +382,14 @@ describe Mastodon::CLI::Accounts do
|
||||||
|
|
||||||
it 'exits with an error message indicating that only one should be used' do
|
it 'exits with an error message indicating that only one should be used' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('Use username or --email, not both')
|
.to raise_error(Thor::Error, 'Use username or --email, not both')
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when neither username nor --email are provided' do
|
context 'when neither username nor --email are provided' do
|
||||||
it 'exits with an error message indicating that no username was provided' do
|
it 'exits with an error message indicating that no username was provided' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('No username provided')
|
.to raise_error(Thor::Error, 'No username provided')
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -425,8 +418,7 @@ describe Mastodon::CLI::Accounts do
|
||||||
|
|
||||||
it 'exits with an error message indicating that no user was found' do
|
it 'exits with an error message indicating that no user was found' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('No user with such username')
|
.to raise_error(Thor::Error, 'No user with such username')
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -458,8 +450,7 @@ describe Mastodon::CLI::Accounts do
|
||||||
|
|
||||||
it 'exits with an error message indicating that no user was found' do
|
it 'exits with an error message indicating that no user was found' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('No user with such email')
|
.to raise_error(Thor::Error, 'No user with such email')
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -511,8 +502,7 @@ describe Mastodon::CLI::Accounts do
|
||||||
|
|
||||||
it 'exits with an error message indicating that the number must be positive' do
|
it 'exits with an error message indicating that the number must be positive' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('Number must be positive')
|
.to raise_error(Thor::Error, 'Number must be positive')
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -545,8 +535,7 @@ describe Mastodon::CLI::Accounts do
|
||||||
|
|
||||||
it 'exits with an error message indicating that no such account was found' do
|
it 'exits with an error message indicating that no such account was found' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('No such account')
|
.to raise_error(Thor::Error, 'No such account')
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -560,8 +549,7 @@ describe Mastodon::CLI::Accounts do
|
||||||
|
|
||||||
it 'exits with an error message indicating that no account with the given username was found' do
|
it 'exits with an error message indicating that no account with the given username was found' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('No such account')
|
.to raise_error(Thor::Error, 'No such account')
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -596,8 +584,7 @@ describe Mastodon::CLI::Accounts do
|
||||||
|
|
||||||
it 'exits with an error message indicating that no account with the given username was found' do
|
it 'exits with an error message indicating that no account with the given username was found' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('No such account')
|
.to raise_error(Thor::Error, 'No such account')
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -634,8 +621,7 @@ describe Mastodon::CLI::Accounts do
|
||||||
|
|
||||||
it 'exits with an error message indicating that there is no such account' do
|
it 'exits with an error message indicating that there is no such account' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('No user with such username')
|
.to raise_error(Thor::Error, 'No user with such username')
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -795,8 +781,7 @@ describe Mastodon::CLI::Accounts do
|
||||||
allow(Account).to receive(:find_remote).with(account_example_com_b.username, account_example_com_b.domain).and_return(nil)
|
allow(Account).to receive(:find_remote).with(account_example_com_b.username, account_example_com_b.domain).and_return(nil)
|
||||||
|
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('No such account')
|
.to raise_error(Thor::Error, 'No such account')
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -892,8 +877,7 @@ describe Mastodon::CLI::Accounts do
|
||||||
context 'when neither a list of accts nor options are provided' do
|
context 'when neither a list of accts nor options are provided' do
|
||||||
it 'exits with an error message' do
|
it 'exits with an error message' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('No account(s) given')
|
.to raise_error(Thor::Error, 'No account(s) given')
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -904,8 +888,7 @@ describe Mastodon::CLI::Accounts do
|
||||||
context 'when neither username nor --all option are given' do
|
context 'when neither username nor --all option are given' do
|
||||||
it 'exits with an error message' do
|
it 'exits with an error message' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('No account(s) given')
|
.to raise_error(Thor::Error, 'No account(s) given')
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -940,8 +923,7 @@ describe Mastodon::CLI::Accounts do
|
||||||
|
|
||||||
it 'exits with an error message when the specified username is not found' do
|
it 'exits with an error message when the specified username is not found' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('No such account')
|
.to raise_error(Thor::Error, 'No such account')
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -980,8 +962,7 @@ describe Mastodon::CLI::Accounts do
|
||||||
shared_examples 'an account not found' do |acct|
|
shared_examples 'an account not found' do |acct|
|
||||||
it 'exits with an error message indicating that there is no such account' do
|
it 'exits with an error message indicating that there is no such account' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results("No such account (#{acct})")
|
.to raise_error(Thor::Error, "No such account (#{acct})")
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1031,8 +1012,7 @@ describe Mastodon::CLI::Accounts do
|
||||||
|
|
||||||
it 'exits with an error message indicating that the accounts do not have the same pub key' do
|
it 'exits with an error message indicating that the accounts do not have the same pub key' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results("Accounts don't have the same public key, might not be duplicates!\nOverride with --force")
|
.to raise_error(Thor::Error, "Accounts don't have the same public key, might not be duplicates!\nOverride with --force\n")
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with --force option' do
|
context 'with --force option' do
|
||||||
|
@ -1200,8 +1180,7 @@ describe Mastodon::CLI::Accounts do
|
||||||
context 'when no option is given' do
|
context 'when no option is given' do
|
||||||
it 'exits with an error message indicating that at least one option is required' do
|
it 'exits with an error message indicating that at least one option is required' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('Please specify either --follows or --followers, or both')
|
.to raise_error(Thor::Error, 'Please specify either --follows or --followers, or both')
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1211,8 +1190,7 @@ describe Mastodon::CLI::Accounts do
|
||||||
|
|
||||||
it 'exits with an error message indicating that there is no such account' do
|
it 'exits with an error message indicating that there is no such account' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('No such account')
|
.to raise_error(Thor::Error, 'No such account')
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1368,16 +1346,14 @@ describe Mastodon::CLI::Accounts do
|
||||||
|
|
||||||
it 'exits with an error message indicating that using both options is not possible' do
|
it 'exits with an error message indicating that using both options is not possible' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('Use --replay or --target, not both')
|
.to raise_error(Thor::Error, 'Use --replay or --target, not both')
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when no option is given' do
|
context 'when no option is given' do
|
||||||
it 'exits with an error message indicating that at least one option must be used' do
|
it 'exits with an error message indicating that at least one option must be used' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('Use either --replay or --target')
|
.to raise_error(Thor::Error, 'Use either --replay or --target')
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1387,8 +1363,7 @@ describe Mastodon::CLI::Accounts do
|
||||||
|
|
||||||
it 'exits with an error message indicating that there is no such account' do
|
it 'exits with an error message indicating that there is no such account' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results("No such account: #{arguments.first}")
|
.to raise_error(Thor::Error, "No such account: #{arguments.first}")
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1398,8 +1373,7 @@ describe Mastodon::CLI::Accounts do
|
||||||
context 'when the specified account has no previous migrations' do
|
context 'when the specified account has no previous migrations' do
|
||||||
it 'exits with an error message indicating that the given account has no previous migrations' do
|
it 'exits with an error message indicating that the given account has no previous migrations' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('The specified account has not performed any migration')
|
.to raise_error(Thor::Error, 'The specified account has not performed any migration')
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1421,8 +1395,7 @@ describe Mastodon::CLI::Accounts do
|
||||||
|
|
||||||
it 'exits with an error message' do
|
it 'exits with an error message' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('The specified account is not redirecting to its last migration target. Use --force if you want to replay the migration anyway')
|
.to raise_error(Thor::Error, 'The specified account is not redirecting to its last migration target. Use --force if you want to replay the migration anyway')
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1449,8 +1422,7 @@ describe Mastodon::CLI::Accounts do
|
||||||
|
|
||||||
it 'exits with an error message indicating that there is no such account' do
|
it 'exits with an error message indicating that there is no such account' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results("The specified target account could not be found: #{options[:target]}")
|
.to raise_error(Thor::Error, "The specified target account could not be found: #{options[:target]}")
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1474,8 +1446,7 @@ describe Mastodon::CLI::Accounts do
|
||||||
context 'when the migration record is invalid' do
|
context 'when the migration record is invalid' do
|
||||||
it 'exits with an error indicating that the validation failed' do
|
it 'exits with an error indicating that the validation failed' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('Error: Validation failed')
|
.to raise_error(Thor::Error, /Error: Validation failed/)
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1486,8 +1457,7 @@ describe Mastodon::CLI::Accounts do
|
||||||
|
|
||||||
it 'exits with an error message' do
|
it 'exits with an error message' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('The specified account is redirecting to a different target account. Use --force if you want to change the migration target')
|
.to raise_error(Thor::Error, 'The specified account is redirecting to a different target account. Use --force if you want to change the migration target')
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -64,8 +64,7 @@ describe Mastodon::CLI::Cache do
|
||||||
|
|
||||||
it 'Exits with an error message' do
|
it 'Exits with an error message' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('Unknown')
|
.to raise_error(Thor::Error, /Unknown/)
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -35,8 +35,7 @@ describe Mastodon::CLI::EmailDomainBlocks do
|
||||||
context 'without any options' do
|
context 'without any options' do
|
||||||
it 'warns about usage and exits' do
|
it 'warns about usage and exits' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('No domain(s) given')
|
.to raise_error(Thor::Error, 'No domain(s) given')
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -72,8 +71,7 @@ describe Mastodon::CLI::EmailDomainBlocks do
|
||||||
context 'without any options' do
|
context 'without any options' do
|
||||||
it 'warns about usage and exits' do
|
it 'warns about usage and exits' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('No domain(s) given')
|
.to raise_error(Thor::Error, 'No domain(s) given')
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -42,8 +42,7 @@ describe Mastodon::CLI::Feeds do
|
||||||
|
|
||||||
it 'displays an error and exits' do
|
it 'displays an error and exits' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('No such account')
|
.to raise_error(Thor::Error, 'No such account')
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -144,8 +144,7 @@ describe Mastodon::CLI::IpBlocks do
|
||||||
|
|
||||||
it 'exits with an error message' do
|
it 'exits with an error message' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('No IP(s) given')
|
.to raise_error(Thor::Error, 'No IP(s) given')
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -235,8 +234,7 @@ describe Mastodon::CLI::IpBlocks do
|
||||||
context 'when no IP address is provided' do
|
context 'when no IP address is provided' do
|
||||||
it 'exits with an error message' do
|
it 'exits with an error message' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('No IP(s) given')
|
.to raise_error(Thor::Error, 'No IP(s) given')
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -104,9 +104,9 @@ describe Mastodon::CLI::Main do
|
||||||
answer_hostname_incorrectly
|
answer_hostname_incorrectly
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'exits silently' do
|
it 'exits with mismatch error message' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to raise_error(SystemExit)
|
.to raise_error(Thor::Error, /Domains do not match/)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ describe Mastodon::CLI::Main do
|
||||||
it 'passes first step but stops before instructions' do
|
it 'passes first step but stops before instructions' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('operation WILL NOT')
|
.to output_results('operation WILL NOT')
|
||||||
.and raise_error(SystemExit)
|
.and raise_error(Thor::Error, /Self-destruct will not begin/)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -22,8 +22,7 @@ describe Mastodon::CLI::Maintenance do
|
||||||
|
|
||||||
it 'Exits with error message' do
|
it 'Exits with error message' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('is too old')
|
.to raise_error(Thor::Error, /is too old/)
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -36,7 +35,7 @@ describe Mastodon::CLI::Maintenance do
|
||||||
it 'Exits with error message' do
|
it 'Exits with error message' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('more recent')
|
.to output_results('more recent')
|
||||||
.and raise_error(SystemExit)
|
.and raise_error(Thor::Error, /more recent/)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -48,8 +47,7 @@ describe Mastodon::CLI::Maintenance do
|
||||||
|
|
||||||
it 'Exits with error message' do
|
it 'Exits with error message' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('Sidekiq is running')
|
.to raise_error(Thor::Error, /Sidekiq is running/)
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,7 @@ describe Mastodon::CLI::Media do
|
||||||
|
|
||||||
it 'warns about usage and exits' do
|
it 'warns about usage and exits' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('--prune-profiles and --remove-headers should not be specified simultaneously')
|
.to raise_error(Thor::Error, '--prune-profiles and --remove-headers should not be specified simultaneously')
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -30,8 +29,7 @@ describe Mastodon::CLI::Media do
|
||||||
|
|
||||||
it 'warns about usage and exits' do
|
it 'warns about usage and exits' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('--include-follows can only be used with --prune-profiles or --remove-headers')
|
.to raise_error(Thor::Error, '--include-follows can only be used with --prune-profiles or --remove-headers')
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -98,8 +96,7 @@ describe Mastodon::CLI::Media do
|
||||||
|
|
||||||
it 'warns about url and exits' do
|
it 'warns about url and exits' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('Not a media URL')
|
.to raise_error(Thor::Error, 'Not a media URL')
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -121,8 +118,7 @@ describe Mastodon::CLI::Media do
|
||||||
context 'without any options' do
|
context 'without any options' do
|
||||||
it 'warns about usage and exits' do
|
it 'warns about usage and exits' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('Specify the source')
|
.to raise_error(Thor::Error, /Specify the source/)
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -147,8 +143,7 @@ describe Mastodon::CLI::Media do
|
||||||
|
|
||||||
it 'warns about usage and exits' do
|
it 'warns about usage and exits' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('No such account')
|
.to raise_error(Thor::Error, 'No such account')
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -221,8 +216,7 @@ describe Mastodon::CLI::Media do
|
||||||
|
|
||||||
it 'warns about usage and exits' do
|
it 'warns about usage and exits' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('azure storage driver is not supported')
|
.to raise_error(Thor::Error, /azure storage driver is not supported/)
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -233,8 +227,7 @@ describe Mastodon::CLI::Media do
|
||||||
|
|
||||||
it 'warns about usage and exits' do
|
it 'warns about usage and exits' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('fog storage driver is not supported')
|
.to raise_error(Thor::Error, /fog storage driver is not supported/)
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,7 @@ describe Mastodon::CLI::Search do
|
||||||
|
|
||||||
it 'Exits with error message' do
|
it 'Exits with error message' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('this concurrency setting')
|
.to raise_error(Thor::Error, /this concurrency setting/)
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -30,8 +29,7 @@ describe Mastodon::CLI::Search do
|
||||||
|
|
||||||
it 'Exits with error message' do
|
it 'Exits with error message' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('this batch_size setting')
|
.to raise_error(Thor::Error, /this batch_size setting/)
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,7 @@ describe Mastodon::CLI::Statuses do
|
||||||
|
|
||||||
it 'exits with error message' do
|
it 'exits with error message' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results('Cannot run')
|
.to raise_error(Thor::Error, /Cannot run/)
|
||||||
.and raise_error(SystemExit)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue