Last active
June 26, 2022 21:47
-
-
Save CharlyJazz/7b9c4d18f60ffe8022526a936366e171 to your computer and use it in GitHub Desktop.
upload files to gist using ruby
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Struct to save file data | |
FileStruct = Struct.new(:filename, :content) | |
# Resolver content from a file of a folder of files | |
class ContentResolver | |
# Returns whether or not +file+ is a binary file. Note that this is | |
# not guaranteed to be 100% accurate. It performs a "best guess" based | |
# on a simple test of the first +File.blksize+ characters. | |
# | |
# Example: | |
# | |
# File.binary?('somefile.exe') # => true | |
# File.binary?('somefile.txt') # => false | |
#-- | |
# Based on code originally provided by Ryan Davis (which, in turn, is | |
# based on Perl's -B switch). | |
# | |
# https://makandracards.com/makandra/483046-how-to-check-if-a-file-is-a-human-readable-text-file | |
def binary?(file) | |
s = (File.read(file, File.stat(file).blksize) || '').split(//) | |
((s.size - s.grep(' '..'~').size) / s.size.to_f) > 0.30 | |
end | |
# Recursively get the content and the path of text files. | |
# If the path is a folder then create a recursive call | |
# but keeping the reference of list_of_files | |
def get_files_from_folder(initial_path, list_of_files = []) | |
Dir.glob("#{initial_path}/*").each do |filename| | |
if Dir.exist? filename | |
get_files_from_folder(filename, list_of_files) | |
else | |
file_content = File.read(filename) | |
list_of_files.push FileStruct.new(filename, file_content) unless binary?(filename) | |
end | |
end | |
list_of_files | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'uri' | |
require 'json' | |
require_relative './content_resolver' | |
require_relative './http-client' | |
# Error for credentials related issues | |
class GistValidationError < RuntimeError | |
end | |
## Error for gist creation issues | |
class GistCreationError < RuntimeError | |
end | |
# A class to provide the logic to create gist in you github account | |
# using you username and a access_token | |
class Gist | |
attr_accessor :username, :token, :public, :description, :list_of_files, :base_url | |
def initialize(http_client = HTTPProvider) | |
@resolver = ContentResolver.new | |
@list_of_files = [] | |
@base_url = 'https://api.github.com' | |
@http_client = http_client.new | |
end | |
# Call all the functions to create the gist | |
def send_new_gist | |
input_credentials | |
verify_access_token | |
input_description_and_public | |
input_file_content | |
validate_response send_request_to_create_gist | |
end | |
private | |
# Create request, send it and validate status | |
def send_request_to_create_gist | |
uri = URI("#{@base_url}/gists") | |
http = @http_client.http.new(uri.host, uri.port) | |
http.use_ssl = true | |
request = @http_client.http_post.new(uri, header) | |
files = {} | |
@list_of_files.each do |file_struct| | |
# To prevent send a empty content and raise a error | |
next unless file_struct[:content].length > 0 | |
content_sanitized = file_struct[:content] | |
filename_sanitized = file_struct[:filename].delete('/') | |
files[filename_sanitized] = { "content": content_sanitized } | |
end | |
request.body = { | |
"files": files, | |
"description": @description, | |
"public": @public | |
}.to_json | |
http.request(request) | |
end | |
# Helper to get the header to create gist | |
def header | |
{ | |
'Content-Type' => 'application/json', | |
'Authorization' => "token #{@token}", | |
'Accept' => 'application/vnd.github.v3+json', | |
'User-Agent' => @username | |
} | |
end | |
# Validate the create gist response | |
def validate_response(response) | |
case response | |
when @http_client.http_success | |
puts 'Gist created with success' | |
puts "Visit: #{JSON.parse(response.body)['html_url']}" | |
when @http_client.http_redirect | |
puts 'Request redirected, something went wrong' | |
else | |
puts 'Something went wrong' | |
end | |
end | |
# Show message and raise error | |
def wrong_credentials_scenario | |
puts 'Credentials wrong try again' | |
raise GistValidationError | |
end | |
# Save data about the gist | |
def input_description_and_public | |
puts 'Insert description for the gist' | |
@description = gets.strip | |
puts 'Do you want a public gist? [y/n]' | |
@public = gets.strip | |
@public = @public == 'y' | |
end | |
# Save data about the credentials | |
def input_credentials | |
puts 'Insert username' | |
@username = gets.strip | |
puts 'Insert the access token' | |
@token = gets.strip | |
end | |
# Verify access token using a ruby version of the | |
# curl command from the github documentation | |
# curl -u username:token https://api.github.com/user | |
def verify_access_token | |
puts 'Verifing access token' | |
uri = URI("#{@base_url}/user") | |
http = @http_client.http.new(uri.host, uri.port) | |
http.use_ssl = true | |
request = @http_client.http_get.new(uri) | |
request.basic_auth(@username, @token) | |
response = http.request(request) | |
wrong_credentials_scenario if response.code != '200' | |
end | |
# Check if the user enter a folder and then get all the files or just | |
# get a single file | |
def input_file_content | |
puts 'Insert file name' | |
path = gets.strip | |
begin | |
if Dir.exist? path | |
@resolver.get_files_from_folder(path, @list_of_files) | |
else | |
@list_of_files.push(FileStruct.new(path, File.read(path))) | |
end | |
rescue Errno::ENOENT => e | |
wrong_file_scenario | |
end | |
end | |
# Show message and raise error | |
def wrong_file_scenario | |
puts 'File no founded' | |
raise GistCreationError | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'net/https' | |
# Class to provide the HTTP Protocol. | |
# | |
# This class is useful because can be mocked for testing | |
class HTTPProvider | |
# Return Net::HTTP | |
def http | |
Net::HTTP | |
end | |
# Return Net::HTTP::Post | |
def http_post | |
Net::HTTP::Post | |
end | |
# Return Net::HTTP::Get | |
def http_get | |
Net::HTTP::Get | |
end | |
# Return Net::HTTPSuccess | |
def http_success | |
Net::HTTPSuccess | |
end | |
# Return Net::HTTPRedirection | |
def http_redirect | |
Net::HTTPRedirection | |
end | |
end | |
# Class for mock the Net::HTTPSuccess instance | |
class MockHTTPSuccess | |
attr_accessor :body | |
def initialize(body) | |
@body = body | |
end | |
end | |
# Class for mock the Net::HTTPRedirection instance | |
class MockRedirectSuccess end | |
# Simple Stubs of HTTPProvider | |
class HTTPProviderMock | |
# Do nothing (Stub) | |
def http; end | |
# Do nothing (Stub) | |
def http_post; end | |
# Do nothing (Stub) | |
def http_get; end | |
# Return MockRedirectSuccess | |
def http_success | |
MockRedirectSuccess | |
end | |
# Return MockRedirectSuccess | |
def http_redirect | |
MockRedirectSuccess | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment