From 593c8a963e7a2baa80ab74a8a8568b091ff1539d Mon Sep 17 00:00:00 2001 From: zhgchgli Date: Mon, 26 Apr 2021 23:18:44 +0800 Subject: [PATCH] Support GEM --- .cache/.keep | 0 .gitignore | 1 - README.md | 2 + ZReviewsBot.gemspec | 7 +- bin/ZReviewsBot | 220 ++++++++++---------- doc/README_zh_tw.md | 35 ++++ lib/.cache/.iOSLastModified | 1 + lib/AppStore.rb | 4 +- lib/GooglePlay.rb | 10 +- config/config.example.yml => lib/config.yml | 3 +- lib/locales/en.yml | 5 +- lib/locales/zh-tw.yml | 5 +- 12 files changed, 172 insertions(+), 121 deletions(-) delete mode 100644 .cache/.keep create mode 100644 doc/README_zh_tw.md create mode 100644 lib/.cache/.iOSLastModified rename config/config.example.yml => lib/config.yml (91%) diff --git a/.cache/.keep b/.cache/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/.gitignore b/.gitignore index f19a254..d3b03b1 100644 --- a/.gitignore +++ b/.gitignore @@ -39,7 +39,6 @@ build-iPhoneSimulator/ ## Documentation cache and generated files: /.yardoc/ /_yardoc/ -/doc/ /rdoc/ ## Environment normalization: diff --git a/README.md b/README.md index 5619273..a5a656f 100644 --- a/README.md +++ b/README.md @@ -4,3 +4,5 @@ ZReviewsBot help you to monitor App Store and Google Play reviews and posts them ![截圖 2021-04-25 上午12 45 31](https://user-images.githubusercontent.com/33706588/115966452-333cd400-a560-11eb-8be4-39fbb4c43c49.png) +[中文說明](/doc/README_zh_tw.md) + diff --git a/ZReviewsBot.gemspec b/ZReviewsBot.gemspec index 7d66706..1699bc3 100644 --- a/ZReviewsBot.gemspec +++ b/ZReviewsBot.gemspec @@ -2,12 +2,11 @@ Gem::Specification.new do |gem| gem.authors = ['ZhgChgLi'] gem.description = 'ZReviewsBot help you to monitor App Store and Google Play reviews and posts them to Slack.' gem.summary = 'ZReviewsBot help you to monitor App Store and Google Play reviews and posts them to Slack.' - gem.homepage = 'https://github.com/zhgchgli0718/ZReviewsBot' - gem.files = Dir['locales/*'] + gem.homepage = 'https://github.com/ZhgChgLi/ZReviewsBot' + gem.files = Dir['lib/**/*.*'] gem.executables = ['ZReviewsBot'] - gem.test_files = gem.files.grep(%r{^(test|spec|features)/}) gem.name = 'ZReviewsBot' - gem.version = '0.0.1' + gem.version = '1.0.2' gem.license = "MIT" diff --git a/bin/ZReviewsBot b/bin/ZReviewsBot index a95b0bf..8ce2925 100755 --- a/bin/ZReviewsBot +++ b/bin/ZReviewsBot @@ -8,39 +8,15 @@ require "AppStore" require "GooglePlay" require "Developer" require 'I18n' +require 'optparse' +require 'fileutils' -def main() - #Check Config File - I18n.load_path << Dir["#{$lib}/locales/*.yml"] - I18n.default_locale = 'en' - - if ARGV[0] != nil - arg0 = ARGV[0] - else - arg0 = '' - end - - if arg0 == '' - puts 'Parameter Error!' - return - end - - if arg0 == 'clear' - File.delete(File.expand_path(".cache/.iOSLastModified")) if File.exist?(File.expand_path(".cache/.iOSLastModified")) - File.delete(File.expand_path(".cache/.androidLastModified")) if File.exist?(File.expand_path(".cache/.androidLastModified")) - return - end - - configFilePath = arg0 +def loadConfig(configFilePath) if !File.exists?(configFilePath) raise I18n.t('error.config_file_not_found', :path => configFilePath) end config = OpenStruct.new(YAML.load_file(configFilePath)) - if !Dir.exist?(File.expand_path(".cache/")) - raise I18n.t('error.cache_dir_not_exists', :path => File.expand_path(".cache/")) - end - if config.setting == nil raise I18n.t('error.config_parameter_not_found', :path => configFilePath, :parameter => 'setting') end @@ -49,93 +25,121 @@ def main() raise I18n.t('error.config_parameter_not_found', :path => configFilePath, :parameter => 'setting.developerNotifyWebHookUrl') end - developer = Developer.new(config.setting) - - begin - if config.setting['lang'] != nil - if I18n.locale_available?(config.setting['lang']) - I18n.default_locale = config.setting['lang'] - else - raise I18n.t('error.specify_language_unsupport', :lang => config.setting['lang']) - end - end - - if ARGV[1] != nil - platform = ARGV[1].downcase + if config.setting['lang'] != nil + if I18n.locale_available?(config.setting['lang']) + I18n.default_locale = config.setting['lang'] else - platform = '' + raise I18n.t('error.specify_language_unsupport', :lang => config.setting['lang']) end + end - if platform == 'android' - if config.android == nil - raise I18n.t('error.config_parameter_not_found', :path => configFilePath, :parameter => 'android') - end - if config.android['packageName'] == nil - raise I18n.t('error.config_parameter_not_found', :path => configFilePath, :parameter => 'android.packageName') - end - if config.android['jsonKeyFileName'] == nil - raise I18n.t('error.config_parameter_not_found', :path => configFilePath, :parameter => 'android.jsonKeyFileName') - end - if config.android['notifyWebHookUrl'] == nil - raise I18n.t('error.config_parameter_not_found', :path => configFilePath, :parameter => 'android.notifyWebHookUrl') - end - if config.android['iconEmoji'] == nil - raise I18n.t('error.config_parameter_not_found', :path => configFilePath, :parameter => 'android.iconEmoji') - end - if config.android['username'] == nil - raise I18n.t('error.config_parameter_not_found', :path => configFilePath, :parameter => 'android.username') - end - if config.android['ignoreKeywords'] != nil and !config.android['ignoreKeywords'].kind_of?(Array) - raise I18n.t('error.config_parameter_error', :path => configFilePath, :parameter => 'android.ignoreKeywords') - end - - appStore = GooglePlay.new(config.android) - result = appStore.run() + return config +end - if result == 0 - developer.sendWelcomeMessageToSlack('Android') - end - elsif platform == 'ios' - if config.iOS == nil - raise I18n.t('error.config_parameter_not_found', :path => configFilePath, :parameter => 'iOS') - end - if config.iOS['appID'] == nil - raise I18n.t('error.config_parameter_not_found', :path => configFilePath, :parameter => 'iOS.appID') - end - if config.iOS['appleID'] == nil - raise I18n.t('error.config_parameter_not_found', :path => configFilePath, :parameter => 'iOS.appleID') - end - if config.iOS['password'] == nil - raise I18n.t('error.config_parameter_not_found', :path => configFilePath, :parameter => 'iOS.password') - end - if config.iOS['notifyWebHookUrl'] == nil - raise I18n.t('error.config_parameter_not_found', :path => configFilePath, :parameter => 'iOS.notifyWebHookUrl') - end - if config.iOS['iconEmoji'] == nil - raise I18n.t('error.config_parameter_not_found', :path => configFilePath, :parameter => 'iOS.iconEmoji') - end - if config.iOS['username'] == nil - raise I18n.t('error.config_parameter_not_found', :path => configFilePath, :parameter => 'iOS.username') - end - if config.iOS['username'] == nil - raise I18n.t('error.config_parameter_not_found', :path => configFilePath, :parameter => 'iOS.username') - end - if config.iOS['ignoreKeywords'] != nil and !config.iOS['ignoreKeywords'].kind_of?(Array) - raise I18n.t('error.config_parameter_error', :path => configFilePath, :parameter => 'iOS.ignoreKeywords') +def main() + I18n.load_path << Dir["#{$lib}/locales/*.yml"] + I18n.default_locale = 'en' + Dir.mkdir("#{$lib}/.cache") unless File.exists?("#{$lib}/.cache") + + ARGV << '-h' if ARGV.empty? + OptionParser.new do |opts| + opts.banner = "Usage: ZReviewsBot [options]" + opts.on('-iCONFIG_FILE_PATH', '--iOS=CONFIG_FILE_PATH', I18n.t('config.start', :platform => 'iOS')) do |configFilePath| + config = loadConfig(configFilePath) + developer = Developer.new(config.setting) + + begin + if config.iOS == nil + raise I18n.t('error.config_parameter_not_found', :path => configFilePath, :parameter => 'iOS') + end + if config.iOS['appID'] == nil + raise I18n.t('error.config_parameter_not_found', :path => configFilePath, :parameter => 'iOS.appID') + end + if config.iOS['appleID'] == nil + raise I18n.t('error.config_parameter_not_found', :path => configFilePath, :parameter => 'iOS.appleID') + end + if config.iOS['password'] == nil + raise I18n.t('error.config_parameter_not_found', :path => configFilePath, :parameter => 'iOS.password') + end + if config.iOS['notifyWebHookUrl'] == nil + raise I18n.t('error.config_parameter_not_found', :path => configFilePath, :parameter => 'iOS.notifyWebHookUrl') + end + if config.iOS['iconEmoji'] == nil + raise I18n.t('error.config_parameter_not_found', :path => configFilePath, :parameter => 'iOS.iconEmoji') + end + if config.iOS['username'] == nil + raise I18n.t('error.config_parameter_not_found', :path => configFilePath, :parameter => 'iOS.username') + end + if config.iOS['username'] == nil + raise I18n.t('error.config_parameter_not_found', :path => configFilePath, :parameter => 'iOS.username') + end + if config.iOS['ignoreKeywords'] != nil and !config.iOS['ignoreKeywords'].kind_of?(Array) + raise I18n.t('error.config_parameter_error', :path => configFilePath, :parameter => 'iOS.ignoreKeywords') + end + + appStore = AppStore.new(config.iOS) + result = appStore.run() + + if result == 0 + developer.sendWelcomeMessageToSlack('iOS') + end + rescue => error + developer.sendMessagesToSlack(error) end - - appStore = AppStore.new(config.iOS) - result = appStore.run() - - if result == 0 - developer.sendWelcomeMessageToSlack('iOS') + end + opts.on('-aCONFIG_FILE_PATH', '--android=CONFIG_FILE_PATH', I18n.t('config.start', :platform => 'Android')) do |configFilePath| + config = loadConfig(configFilePath) + begin + developer = Developer.new(config.setting) + + if config.android == nil + raise I18n.t('error.config_parameter_not_found', :path => configFilePath, :parameter => 'android') + end + if config.android['packageName'] == nil + raise I18n.t('error.config_parameter_not_found', :path => configFilePath, :parameter => 'android.packageName') + end + if config.android['jsonKeyFilePath'] == nil + raise I18n.t('error.config_parameter_not_found', :path => configFilePath, :parameter => 'android.jsonKeyFilePath') + end + if config.android['notifyWebHookUrl'] == nil + raise I18n.t('error.config_parameter_not_found', :path => configFilePath, :parameter => 'android.notifyWebHookUrl') + end + if config.android['iconEmoji'] == nil + raise I18n.t('error.config_parameter_not_found', :path => configFilePath, :parameter => 'android.iconEmoji') + end + if config.android['username'] == nil + raise I18n.t('error.config_parameter_not_found', :path => configFilePath, :parameter => 'android.username') + end + if config.android['ignoreKeywords'] != nil and !config.android['ignoreKeywords'].kind_of?(Array) + raise I18n.t('error.config_parameter_error', :path => configFilePath, :parameter => 'android.ignoreKeywords') + end + + appStore = GooglePlay.new(config.android) + result = appStore.run() + + if result == 0 + developer.sendWelcomeMessageToSlack('Android') + end + rescue => error + developer.sendMessagesToSlack(error) end - else - raise I18n.t('error.unknow_platform', :platform => platform) end - rescue => error - developer.sendMessagesToSlack(error) - end + opts.on('-c', '--clear', I18n.t('config.clear_cache')) do |config| + File.delete("#{$lib}/.cache/.iOSLastModified") if File.exist?("#{$lib}/.cache/.iOSLastModified") + File.delete("#{$lib}/.cache/.androidLastModified") if File.exist?("#{$lib}/.cache/.androidLastModified") + end + opts.on('-m', '--make', I18n.t('config.make_config')) do |config| + FileUtils.cp("#{$lib}/config.yml", "#{__dir__}/config.yml") + end + opts.on_tail("-h", "--help") do + puts opts + exit + end + end.parse! end -main() \ No newline at end of file +begin + main() +rescue => error + puts error +end \ No newline at end of file diff --git a/doc/README_zh_tw.md b/doc/README_zh_tw.md new file mode 100644 index 0000000..333314e --- /dev/null +++ b/doc/README_zh_tw.md @@ -0,0 +1,35 @@ +# ZReviewsBot + +ZReviewsBot 為免費、開源專案,幫助您自動獲取 App 團隊追蹤 App Store (iOS) 及 Google Play (Android) 平台上 App 的最新評價,並發送到指定 Slack Channel 方便您快速獲取當前 App 評價狀況。 + +## Installation + +### GEM + +- `gem install ZReviewsBot` + +- run `ZReviewsBot [options]` + +### Manually + +- Clone or 下載此專案 + +- Run `./bin/ZReviewsBot [options]` + +## Usage + +### 從範本產生設定檔 + +`ZReviewsBot -make` + +### 執行 iOS App Store 最新評價撈取 + +`ZReviewsBot -i config.yml` + +### 執行 Android Google Play 最新評價撈取 + +`ZReviewsBot -a config.yml` + +### Reset 清除 Cache 從新開始 + +`ZReviewsBot -c` \ No newline at end of file diff --git a/lib/.cache/.iOSLastModified b/lib/.cache/.iOSLastModified new file mode 100644 index 0000000..038366a --- /dev/null +++ b/lib/.cache/.iOSLastModified @@ -0,0 +1 @@ +1619331368000 \ No newline at end of file diff --git a/lib/AppStore.rb b/lib/AppStore.rb index 550d7c4..180bb7e 100644 --- a/lib/AppStore.rb +++ b/lib/AppStore.rb @@ -1,3 +1,5 @@ +$lib = File.expand_path('../lib', File.dirname(__FILE__)) + require "Spaceship" require "SpaceshipExtension.rb" require "Slack.rb" @@ -14,7 +16,7 @@ def initialize(iOS) @iconEmoji = iOS['iconEmoji'] @username = iOS['username'] @ignoreKeywords = iOS['ignoreKeywords'] - @cacheFile = File.expand_path(".cache/.iOSLastModified") + @cacheFile = "#{$lib}/.cache/.iOSLastModified" end def run() diff --git a/lib/GooglePlay.rb b/lib/GooglePlay.rb index 35d970f..eb8c586 100644 --- a/lib/GooglePlay.rb +++ b/lib/GooglePlay.rb @@ -1,25 +1,27 @@ +$lib = File.expand_path('../lib', File.dirname(__FILE__)) + require 'google/apis/androidpublisher_v3' require 'googleauth' require "Slack.rb" require "Developer.rb" class GooglePlay - attr_accessor :packageName, :jsonKeyFileName, :notifyWebHookUrl, :iconEmoji, :username, :cacheFile, :ignoreKeywords + attr_accessor :packageName, :jsonKeyFilePath, :notifyWebHookUrl, :iconEmoji, :username, :cacheFile, :ignoreKeywords def initialize(android) @packageName = android['packageName'] - @jsonKeyFileName = android['jsonKeyFileName'] + @jsonKeyFilePath = android['jsonKeyFilePath'] @notifyWebHookUrl = android['notifyWebHookUrl'] @iconEmoji = android['iconEmoji'] @username = android['username'] @ignoreKeywords = android['ignoreKeywords'] - @cacheFile = File.expand_path(".cache/.androidLastModified") + @cacheFile = "#{$lib}/.cache/.androidLastModified" end def run() app = Google::Apis::AndroidpublisherV3::AndroidPublisherService.new app.authorization = Google::Auth::ServiceAccountCredentials.make_creds( - json_key_io: File.open(File.expand_path(jsonKeyFileName)), + json_key_io: File.open(jsonKeyFilePath), scope: 'https://www.googleapis.com/auth/androidpublisher') lastModified = getLastModified() diff --git a/config/config.example.yml b/lib/config.yml similarity index 91% rename from config/config.example.yml rename to lib/config.yml index 220af21..520eeea 100644 --- a/config/config.example.yml +++ b/lib/config.yml @@ -1,3 +1,4 @@ +# Config Example iOS: appID: 'iOS APP ID' appleID: 'APP Store Connect Apple ID (email)' @@ -10,7 +11,7 @@ iOS: username: 'ZReview Bot' android: packageName: 'Android Package Name' - jsonKeyFileName: 'android_publisher_key.json' + jsonKeyFilePath: 'android_publisher_key.json' notifyWebHookUrl: 'slack webhook url for android new rewview message' ignoreKeywords: #list, Optional - 'Keyword 1' diff --git a/lib/locales/en.yml b/lib/locales/en.yml index 8aa725b..29d66b5 100644 --- a/lib/locales/en.yml +++ b/lib/locales/en.yml @@ -1,9 +1,12 @@ en: + config: + start: "撈取 %{platform} 平台評價, EX: -i /config.yml" + clear_cache: "Reset,清除 Cache" + make_config: "從範例產生 config.yml 檔案" error: config_file_not_found: "在路徑 %{path} 下找不到設定檔。" config_parameter_not_found: "在 %{path} 設定檔下找不到 %{parameter} 參數。" config_parameter_error: "在 %{path} 設定檔下 %{parameter} 參數設定錯誤。" - cache_dir_not_exists: "找不到指定的 Cache 目錄 %{path}。" specify_language_unsupport: "目前尚不支持 %{lang} 語系。" unknow_platform: "平台參數 %{platform} 輸入錯誤,請輸入 iOS 或 Android。" error_catch_footer: "撈取評價時發生錯誤,若是 iOS 平台可能是 請重新登入。" diff --git a/lib/locales/zh-tw.yml b/lib/locales/zh-tw.yml index ec0305a..d98d77a 100644 --- a/lib/locales/zh-tw.yml +++ b/lib/locales/zh-tw.yml @@ -1,9 +1,12 @@ zh-tw: + config: + start: "撈取 %{platform} 平台評價, EX: -i /config.yml" + clear_cache: "Reset,清除 Cache" + make_config: "從範例產生 config.yml 檔案" error: config_file_not_found: "在路徑 %{path} 下找不到設定檔。" config_parameter_not_found: "在 %{path} 設定檔下找不到 %{parameter} 參數。" config_parameter_error: "在 %{path} 設定檔下 %{parameter} 參數設定錯誤。" - cache_dir_not_exists: "找不到指定的 Cache 目錄 %{path}。" specify_language_unsupport: "目前尚不支持 %{lang} 語系。" unknow_platform: "平台參數 %{platform} 輸入錯誤,請輸入 iOS 或 Android。" error_catch_footer: "撈取評價時發生錯誤,若是 iOS 平台可能是 請重新登入。"