sqlui 0.1.71 → 0.1.72

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8367a239699e11c5f2e0156e954babfc90ca40a984fa8738a3649c5bbb90ab99
4
- data.tar.gz: 7353908da8d6d1bcbd694a3b5fed268d631219f6e48fe2dfab24459cd9fdd4c7
3
+ metadata.gz: d93fb898461c1843f631c16ba879898e54e12374c89bdc49f702420e06d7789e
4
+ data.tar.gz: 875364afb309801a644900301051cdbe96939d12aa3980eb2e1460668e032b24
5
5
  SHA512:
6
- metadata.gz: 70fe8390ec20a1907b384ba98f607df311e5ed21ae28421399d8c478f0e4ffc8bf4f9cecb621ad03aaca15371cee25b8e2d2ce7cc495d86a8a8c8cc9870519e4
7
- data.tar.gz: cef2ed4e6d4ff35abf6b457a97cd6eeae50906966ea4ca0c606fe7aa5720c891912830bff464845d3e0eaf71d39b3bd16baadbd2aa71b70695ed31f3118f2e94
6
+ metadata.gz: 3868ba4eac83d9584e6da037ee34e475010b47e0ff4dcdb791837f81125a77f4090c38fd60360f1a12f4fd2f3c5402092b4a936c5eb670c15ab1518583c04b3e
7
+ data.tar.gz: f9c9c07fdb3016aec05fb2f99c5d307eafc95b2fa9d4d693afb83af71a521d5fa32c9b03137c1f30293218186f432a2eff1a28490290f974b25163126c399fea
data/.release-version CHANGED
@@ -1 +1 @@
1
- 0.1.71
1
+ 0.1.72
data/app/github/cache.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'logger'
4
+
3
5
  require_relative '../checks'
4
6
 
5
7
  module Github
@@ -26,8 +28,6 @@ module Github
26
28
  end
27
29
 
28
30
  def [](key)
29
- check_non_empty_string(key: key)
30
-
31
31
  @mutex.synchronize do
32
32
  evict
33
33
  if (value = @hash[key])
@@ -41,7 +41,6 @@ module Github
41
41
  end
42
42
 
43
43
  def []=(key, value)
44
- check_non_empty_string(key: key)
45
44
  check_is_a(value: [Entry, value])
46
45
 
47
46
  @mutex.synchronize do
@@ -32,5 +32,9 @@ module Github
32
32
  check_non_empty_string(url: url)
33
33
  @client.get(url)
34
34
  end
35
+
36
+ def post(url, request)
37
+ @client.post(url, request)
38
+ end
35
39
  end
36
40
  end
data/app/github/client.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'base64'
3
4
  require 'json'
4
5
  require 'logger'
5
6
  require 'rest-client'
@@ -28,9 +29,35 @@ module Github
28
29
  'X-GitHub-Api-Version' => '2022-11-28'
29
30
  }
30
31
  )
31
- raise "get #{url} failed: #{response}" unless response.code == 200
32
+
33
+ raise "GET #{url} returned #{response.code}, expected 200: #{response}" unless response.code == 200
34
+
35
+ JSON.parse(response)
36
+ rescue RestClient::RequestFailed => e
37
+ @logger.error("#{self.class} GET #{url} failed: #{e.response.code} #{e.response}")
38
+ raise e
39
+ end
40
+
41
+ def post(url, request)
42
+ check_non_empty_string(url: url)
43
+ check_is_a(request: [Hash, request])
44
+
45
+ @logger.info "#{self.class} POST #{url}"
46
+ response = RestClient.post(
47
+ url,
48
+ request.to_json,
49
+ {
50
+ 'Accept' => 'application/vnd.github+json',
51
+ 'Authorization' => "Bearer #{@access_token}",
52
+ 'X-GitHub-Api-Version' => '2022-11-28'
53
+ }
54
+ )
55
+ raise "POST #{url} failed: #{response.code} #{response}" unless response.code == 201
32
56
 
33
57
  JSON.parse(response)
58
+ rescue RestClient::RequestFailed => e
59
+ @logger.error("#{self.class} POST #{url} failed: #{e.response.code} #{e.response}")
60
+ raise e
34
61
  end
35
62
  end
36
63
  end
data/app/github/file.rb CHANGED
@@ -7,13 +7,24 @@ module Github
7
7
  class File
8
8
  include Checks
9
9
 
10
- attr_reader :display_path, :content, :github_url
10
+ attr_reader :full_path, :path, :tree_sha, :content, :github_url
11
11
 
12
- def initialize(owner:, repo:, branch:, path:, content:)
13
- check_non_empty_string(owner: owner, repo: repo, branch: branch, path: path)
12
+ def initialize(owner:, repo:, ref:, tree_sha:, path:, content:)
13
+ check_non_empty_string(owner: owner, repo: repo, ref: ref, path: path, tree_sha: tree_sha)
14
+ @full_path = "#{owner}/#{repo}/#{ref}/#{path}"
15
+ @path = path
16
+ @tree_sha = tree_sha
14
17
  @content = check_is_a(content: [String, content])
15
- @display_path = "#{owner}/#{repo}/#{branch}/#{path}"
16
- @github_url = "https://github.com/#{owner}/#{repo}/blob/#{branch}/#{path}"
18
+ @github_url = "https://github.com/#{owner}/#{repo}/blob/#{ref}/#{path}"
19
+ end
20
+
21
+ def ==(other)
22
+ self.class == other.class &&
23
+ @full_path == other.full_path &&
24
+ @path == other.path &&
25
+ @tree_sha == other.tree_sha &&
26
+ @content == other.content &&
27
+ @github_url == other.github_url
17
28
  end
18
29
  end
19
30
  end
data/app/github/paths.rb CHANGED
@@ -1,21 +1,27 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative '../checks'
4
+
3
5
  module Github
4
6
  # Methods for dealing with GitHub paths.
5
7
  class Paths
6
- # "<owner>/<repo>/<ref>/<some_path>"
7
- PATH_PATTERN = %r{^(?:[^/]+/){3}.*[^/]$}
8
- private_constant :PATH_PATTERN
8
+ class << self
9
+ include Checks
10
+
11
+ # "<owner>/<repo>/<ref>/<some_path>"
12
+ PATH_PATTERN = %r{^(?:[^/]+/){3}.*[^/]$}
13
+ private_constant :PATH_PATTERN
9
14
 
10
- # Parses a path like "<owner>/<repo>/<ref>/<some_path>" into owner, repo, ref, path.
11
- def self.parse_file_path(path)
12
- check_non_empty_string(path: path)
13
- raise "invalid path: #{path}" unless PATH_PATTERN.match?(path)
15
+ # Parses a path like "<owner>/<repo>/<ref>/<some_path>" into owner, repo, ref, path.
16
+ def parse_file_path(path)
17
+ check_non_empty_string(path: path)
18
+ raise "invalid path: #{path}" unless PATH_PATTERN.match?(path)
14
19
 
15
- owner, repo, ref, *path = path.split('/')
16
- path = path.join('/')
20
+ owner, repo, ref, *path = path.split('/')
21
+ path = path.join('/')
17
22
 
18
- [owner, repo, ref, path]
23
+ [owner, repo, ref, path]
24
+ end
19
25
  end
20
26
  end
21
27
  end
data/app/github/tree.rb CHANGED
@@ -9,9 +9,12 @@ module Github
9
9
  include Checks
10
10
  include Enumerable
11
11
 
12
- attr_reader :truncated
12
+ attr_reader :owner, :repo, :ref, :truncated, :files
13
13
 
14
- def initialize(files:, truncated: false)
14
+ def initialize(owner:, repo:, ref:, files:, truncated: false)
15
+ @owner = check_non_empty_string(owner: owner)
16
+ @repo = check_non_empty_string(repo: repo)
17
+ @ref = check_non_empty_string(ref: ref)
15
18
  @files = check_enumerable_of(files, File)
16
19
  @truncated = check_boolean(truncated: truncated)
17
20
  end
@@ -19,22 +22,45 @@ module Github
19
22
  class << self
20
23
  include Checks
21
24
 
22
- def for(owner:, repo:, branch:, tree_response:)
23
- check_non_empty_string(owner: owner, repo: repo, branch: branch)
25
+ def for(owner:, repo:, ref:, tree_response:)
26
+ check_non_empty_string(owner: owner, repo: repo, ref: ref)
24
27
  check_is_a(tree_response: [Hash, tree_response])
25
28
 
26
29
  truncated = check_boolean(truncated: tree_response['truncated'])
27
30
  tree = check_is_a(tree: [Array, tree_response['tree']])
28
31
  files = tree.map do |blob|
29
- File.new(owner: owner, repo: repo, branch: branch, path: blob['path'], content: blob['content'])
32
+ File.new(
33
+ owner: owner,
34
+ repo: repo,
35
+ ref: ref,
36
+ tree_sha: tree_response['sha'],
37
+ path: blob['path'],
38
+ content: blob['content']
39
+ )
30
40
  end
31
41
 
32
- Tree.new(files: files, truncated: truncated)
42
+ Tree.new(owner: owner, repo: repo, ref: ref, files: files, truncated: truncated)
33
43
  end
34
44
  end
35
45
 
46
+ def [](path)
47
+ @files.find { |f| f.path == path }
48
+ end
49
+
36
50
  def each(&block)
37
51
  @files.each(&block)
38
52
  end
53
+
54
+ def ==(other)
55
+ self.class == other.class &&
56
+ @files == other.files &&
57
+ @truncated == other.truncated
58
+ end
59
+
60
+ def <<(file)
61
+ check_is_a(file: [File, file])
62
+
63
+ @files << file unless @files.include?(file)
64
+ end
39
65
  end
40
66
  end
@@ -4,8 +4,11 @@ require 'base64'
4
4
  require 'concurrent/executor/fixed_thread_pool'
5
5
  require 'json'
6
6
  require 'logger'
7
+ require 'rest-client'
7
8
 
8
9
  require_relative 'caching_client'
10
+ require_relative 'client'
11
+ require_relative 'paths'
9
12
  require_relative 'tree'
10
13
  require_relative '../checks'
11
14
  require_relative '../count_down_latch'
@@ -22,10 +25,7 @@ module Github
22
25
  end
23
26
 
24
27
  DEFAULT_MAX_TREE_CACHE_AGE_SECONDS = 60 * 5 # 5 minutes
25
- private_constant :DEFAULT_MAX_TREE_CACHE_AGE_SECONDS
26
-
27
28
  DEFAULT_MAX_FILE_CACHE_AGE_SECONDS = 60 * 60 * 24 * 7 # 1 week
28
- private_constant :DEFAULT_MAX_FILE_CACHE_AGE_SECONDS
29
29
 
30
30
  MAX_TREE_SIZE = 50
31
31
  private_constant :MAX_TREE_SIZE
@@ -38,14 +38,18 @@ module Github
38
38
  @logger = check_non_nil(logger: logger)
39
39
  end
40
40
 
41
- def get_tree(owner:, repo:, branch:, regex:)
42
- check_non_empty_string(owner: owner, repo: repo, branch: branch)
41
+ def get_tree(owner:, repo:, ref:, regex:, cache: true)
42
+ check_non_empty_string(owner: owner, repo: repo, ref: ref)
43
43
  check_is_a(regex: [Regexp, regex])
44
44
 
45
- response = @client.get_with_caching(
46
- "https://api.github.com/repos/#{owner}/#{repo}/git/trees/#{branch}?recursive=true",
47
- cache_for: DEFAULT_MAX_TREE_CACHE_AGE_SECONDS
48
- )
45
+ response = if cache
46
+ @client.get_with_caching(
47
+ "https://api.github.com/repos/#{owner}/#{repo}/git/trees/#{ref}?recursive=true",
48
+ cache_for: DEFAULT_MAX_TREE_CACHE_AGE_SECONDS
49
+ )
50
+ else
51
+ @client.get_without_caching("https://api.github.com/repos/#{owner}/#{repo}/git/trees/#{ref}?recursive=true")
52
+ end
49
53
 
50
54
  response['tree'] = response['tree'].select { |blob| regex.match?(blob['path']) }
51
55
  raise "trees with more than #{MAX_TREE_SIZE} blobs not supported" if response['tree'].size > MAX_TREE_SIZE
@@ -63,7 +67,72 @@ module Github
63
67
  latch.await(timeout: 10)
64
68
  raise 'failed to load saved files' unless response['tree'].all? { |blob| blob['content'] }
65
69
 
66
- Tree.for(owner: owner, repo: repo, branch: branch, tree_response: response)
70
+ Tree.for(owner: owner, repo: repo, ref: ref, tree_response: response)
71
+ end
72
+
73
+ def create_commit_with_file(owner:, repo:, base_sha:, branch:, path:, content:, author_name:, author_email:)
74
+ check_non_empty_string(
75
+ owner: owner,
76
+ repo: repo,
77
+ base_sha: base_sha,
78
+ branch: branch,
79
+ path: path,
80
+ content: content,
81
+ author_name: author_name,
82
+ author_email: author_email
83
+ )
84
+
85
+ begin
86
+ @client.get_without_caching("https://api.github.com/repos/#{owner}/#{repo}/git/ref/#{branch}")
87
+ raise "branch already exists: #{owner}/#{repo}/#{branch}"
88
+ rescue RestClient::NotFound
89
+ # ignored
90
+ end
91
+
92
+ blob_response = @client.post(
93
+ "https://api.github.com/repos/#{owner}/#{repo}/git/blobs",
94
+ {
95
+ content: Base64.encode64(content),
96
+ encoding: 'base64'
97
+ }
98
+ )
99
+ tree_response = @client.post(
100
+ "https://api.github.com/repos/#{owner}/#{repo}/git/trees",
101
+ {
102
+ base_tree: base_sha,
103
+ tree: [
104
+ {
105
+ path: path,
106
+ mode: '100644',
107
+ type: 'blob',
108
+ sha: check_non_empty_string(sha: blob_response['sha'])
109
+ }
110
+ ]
111
+ }
112
+ )
113
+ message = path.size > 43 ? "Update [...]#{path[-38..]}" : "Update #{path}"
114
+ commit_response = @client.post(
115
+ "https://api.github.com/repos/#{owner}/#{repo}/git/commits",
116
+ {
117
+ message: message,
118
+ author: {
119
+ name: 'SQLUI',
120
+ email: 'nicholasdower+sqlui@gmail.com',
121
+ date: Time.now.iso8601
122
+ },
123
+ parents: [
124
+ base_sha
125
+ ],
126
+ tree: check_non_empty_string(sha: tree_response['sha'])
127
+ }
128
+ )
129
+ @client.post(
130
+ "https://api.github.com/repos/#{owner}/#{repo}/git/refs",
131
+ {
132
+ ref: "refs/heads/#{branch}",
133
+ sha: check_non_empty_string(sha: commit_response['sha'])
134
+ }
135
+ )
67
136
  end
68
137
 
69
138
  private
@@ -78,16 +147,5 @@ module Github
78
147
  )
79
148
  Base64.decode64(response['content'])
80
149
  end
81
-
82
- # Returns the contents of the file at the specified path. Uses the cache.
83
- def get_file_content_without_caching(owner:, repo:, path:, ref:)
84
- check_non_empty_string(owner: owner, repo: repo, sha: ref, path: path)
85
-
86
- response = @client.get_without_caching(
87
- "https://api.github.com/repos/#{owner}/#{repo}/contents/#{path}?ref=#{ref}"
88
- )
89
-
90
- Base64.decode64(response['content'])
91
- end
92
150
  end
93
151
  end
data/app/pigs.rb ADDED
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ # You know, pig stuff.
4
+ class Pigs
5
+ NAMES = %w[
6
+ babe misery piglet snowball squealer wilbur napoleon porky miss-piggy petunia betina
7
+ belinda pumbaa hamm peppa-pig fifer fiddler practical-pig hampton-j piggy orson pua
8
+ huxley gub-gub olivia piggy-bank arnold boss-hog
9
+ ].freeze
10
+ private_constant :NAMES
11
+
12
+ POSSESSIVE_NAMES = NAMES.map { |name| "#{name}s" }
13
+ private_constant :POSSESSIVE_NAMES
14
+
15
+ NOUNS = %w[snout ear ears tail hoof hooves foot feet].freeze
16
+ private_constant :NOUNS
17
+
18
+ ADJECTIVES = %w[pink hairy plump round cute dirty smelly tiny adorable slimy dainty big cunning sneaky].freeze
19
+ private_constant :ADJECTIVES
20
+
21
+ GERUND_VERBS = %w[oinking squealing grunting rooting sniffing snorting wallowing trotting rolling].freeze
22
+ private_constant :GERUND_VERBS
23
+
24
+ VERBS = %w[oinks squeals grunts roots sniffs snorts wallows trots rolls swallows].freeze
25
+ private_constant :VERBS
26
+
27
+ ADVERBS = %w[hungrily loudly greedily angrily coyly playfully lazily noisily happily].freeze
28
+ private_constant :ADVERBS
29
+
30
+ FOOD_NOUNS = %w[trotter loin cutlet hock skin jowl cheek rump belly ham bacon back shoulder ear ears tail rib
31
+ tenderloin pork-chop roast sausage fatback fat tongue].freeze
32
+ private_constant :FOOD_NOUNS
33
+
34
+ PLURAL_FOOD_NOUNS = %w[ears trotters cutlets hocks jowls cheeks ribs spareribs pork-chops sausages steaks].freeze
35
+ private_constant :PLURAL_FOOD_NOUNS
36
+
37
+ FOOD_ADJECTIVES = %w[tasty meaty greasy chewy salty smoky juicy delicious crunchy fatty salted spicy savory succulent
38
+ moist flavorful tender sweet].freeze
39
+ private_constant :FOOD_ADJECTIVES
40
+
41
+ PIG_ON_PIG_VERBS = %w[snuggles cuddles chases sniffs watches smells cuddles oinks-at squeals-at grunts-at snorts-at
42
+ wallows-with roots-with trots-with rolls-with grins-at].freeze
43
+ private_constant :PIG_ON_PIG_VERBS
44
+
45
+ COMBOS = [
46
+ [NAMES],
47
+ [NAMES, %w[and], NAMES],
48
+ [NAMES, %w[and], NAMES, %w[are], ADJECTIVES],
49
+ [NAMES, PIG_ON_PIG_VERBS, NAMES],
50
+ [GERUND_VERBS, NAMES],
51
+ [NAMES, GERUND_VERBS],
52
+ [NAMES, GERUND_VERBS, ADVERBS],
53
+ [GERUND_VERBS, NAMES, %w[and], NAMES],
54
+ [NAMES, %w[and], NAMES, GERUND_VERBS],
55
+ [NAMES, %w[and], NAMES, GERUND_VERBS, ADVERBS],
56
+ [NAMES, VERBS],
57
+ [ADJECTIVES, NAMES],
58
+ [NAMES, %w[is], ADJECTIVES],
59
+ [ADJECTIVES, %w[and], ADJECTIVES, NAMES],
60
+ [NAMES, VERBS, ADVERBS],
61
+ [POSSESSIVE_NAMES, NOUNS],
62
+ [POSSESSIVE_NAMES, ADJECTIVES, NOUNS],
63
+ [POSSESSIVE_NAMES, ADJECTIVES, %w[and], ADJECTIVES, NOUNS],
64
+ [ADJECTIVES, NOUNS],
65
+ [POSSESSIVE_NAMES, FOOD_ADJECTIVES, FOOD_NOUNS],
66
+ [POSSESSIVE_NAMES, FOOD_ADJECTIVES, PLURAL_FOOD_NOUNS],
67
+ [NAMES, %w[has-a], FOOD_ADJECTIVES, FOOD_NOUNS],
68
+ [NAMES, %w[has], FOOD_ADJECTIVES, PLURAL_FOOD_NOUNS],
69
+ [FOOD_NOUNS],
70
+ [FOOD_ADJECTIVES, FOOD_NOUNS],
71
+ [FOOD_ADJECTIVES, FOOD_ADJECTIVES, FOOD_NOUNS],
72
+ [%w[a one], FOOD_ADJECTIVES, FOOD_NOUNS],
73
+ [%w[a one], FOOD_ADJECTIVES, FOOD_ADJECTIVES, FOOD_NOUNS],
74
+ [PLURAL_FOOD_NOUNS],
75
+ [FOOD_ADJECTIVES, PLURAL_FOOD_NOUNS],
76
+ [FOOD_ADJECTIVES, FOOD_ADJECTIVES, PLURAL_FOOD_NOUNS],
77
+ [%w[some two three four five six seven eight nine ten a-dozen a-plate-of a-bucket-of a-barrel-of],
78
+ PLURAL_FOOD_NOUNS],
79
+ [%w[some two three four five six seven eight nine ten a-dozen a-plate-of a-bucket-of a-barrel-of], FOOD_ADJECTIVES,
80
+ PLURAL_FOOD_NOUNS],
81
+ [%w[some two three four five six seven eight nine ten a-dozen a-plate-of a-bucket-of a-barrel-of], FOOD_ADJECTIVES,
82
+ FOOD_ADJECTIVES, PLURAL_FOOD_NOUNS]
83
+ ].freeze
84
+ private_constant :COMBOS
85
+
86
+ COMBO_COUNTS = COMBOS.map do |combo|
87
+ size = 1
88
+ used = []
89
+ combo.each do |list|
90
+ size *= list.size - used.count(list)
91
+ used << list
92
+ end
93
+ size
94
+ end
95
+ private_constant :COMBO_COUNTS
96
+
97
+ TOTAL_COMBOS = COMBO_COUNTS.sum
98
+ private_constant :TOTAL_COMBOS
99
+
100
+ COMBO_SUM = COMBO_COUNTS.each_with_object([0]).map do |i, j|
101
+ j[0] = j[0] + i
102
+ end
103
+ private_constant :COMBO_SUM
104
+
105
+ def self.total_combos
106
+ TOTAL_COMBOS
107
+ end
108
+
109
+ def self.generate_phrase
110
+ rand = rand(TOTAL_COMBOS)
111
+ COMBOS.each_with_index do |combo, i|
112
+ next unless rand < COMBO_SUM[i]
113
+
114
+ used = []
115
+ parts = []
116
+ combo.each do |list|
117
+ list -= used
118
+ used << list.sample
119
+ parts << used.last
120
+ end
121
+ return parts.join('-')
122
+ end
123
+ end
124
+ end
data/app/saved_config.rb CHANGED
@@ -4,7 +4,7 @@ require_relative 'args'
4
4
 
5
5
  # Config for saved files.
6
6
  class SavedConfig
7
- attr_reader :token, :owner, :repo, :branch, :regex
7
+ attr_reader :token, :owner, :repo, :branch, :regex, :author_name, :author_email
8
8
 
9
9
  def initialize(hash)
10
10
  @token = Args.fetch_non_empty_string(hash, :token).strip
@@ -12,5 +12,8 @@ class SavedConfig
12
12
  @repo = Args.fetch_non_empty_string(hash, :repo).strip
13
13
  @branch = Args.fetch_non_empty_string(hash, :branch).strip
14
14
  @regex = Regexp.new(Args.fetch_non_empty_string(hash, :regex))
15
+ author = Args.fetch_non_empty_hash(hash, :author)
16
+ @author_name = Args.fetch_non_empty_string(author, :name).strip
17
+ @author_email = Args.fetch_non_empty_string(author, :email).strip
15
18
  end
16
19
  end