txgh 5.3.4 → 5.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/lib/txgh/resource_deleter.rb +50 -0
  3. data/lib/txgh/version.rb +1 -1
  4. data/lib/txgh.rb +1 -6
  5. data/spec/resource_deleter_spec.rb +48 -0
  6. data/spec/spec_helper.rb +0 -8
  7. data/txgh.gemspec +1 -5
  8. metadata +6 -113
  9. data/lib/ext/zipline/output_stream.rb +0 -62
  10. data/lib/txgh/app.rb +0 -140
  11. data/lib/txgh/github_request_auth.rb +0 -28
  12. data/lib/txgh/handlers/download_handler.rb +0 -87
  13. data/lib/txgh/handlers/github/delete_handler.rb +0 -65
  14. data/lib/txgh/handlers/github/handler.rb +0 -20
  15. data/lib/txgh/handlers/github/ping_handler.rb +0 -18
  16. data/lib/txgh/handlers/github/push_handler.rb +0 -124
  17. data/lib/txgh/handlers/github/request_handler.rb +0 -113
  18. data/lib/txgh/handlers/github.rb +0 -11
  19. data/lib/txgh/handlers/response.rb +0 -17
  20. data/lib/txgh/handlers/stream_response.rb +0 -39
  21. data/lib/txgh/handlers/tgz_stream_response.rb +0 -41
  22. data/lib/txgh/handlers/transifex/hook_handler.rb +0 -94
  23. data/lib/txgh/handlers/transifex/request_handler.rb +0 -78
  24. data/lib/txgh/handlers/transifex.rb +0 -8
  25. data/lib/txgh/handlers/triggers/handler.rb +0 -52
  26. data/lib/txgh/handlers/triggers/pull_handler.rb +0 -20
  27. data/lib/txgh/handlers/triggers/push_handler.rb +0 -20
  28. data/lib/txgh/handlers/triggers.rb +0 -9
  29. data/lib/txgh/handlers/zip_stream_response.rb +0 -21
  30. data/lib/txgh/handlers.rb +0 -12
  31. data/lib/txgh/transifex_request_auth.rb +0 -53
  32. data/spec/app_spec.rb +0 -347
  33. data/spec/github_request_auth_spec.rb +0 -39
  34. data/spec/handlers/download_handler_spec.rb +0 -91
  35. data/spec/handlers/github/delete_handler_spec.rb +0 -71
  36. data/spec/handlers/github/ping_handler_spec.rb +0 -16
  37. data/spec/handlers/github/push_handler_spec.rb +0 -106
  38. data/spec/handlers/tgz_stream_response_spec.rb +0 -59
  39. data/spec/handlers/transifex/hook_handler_spec.rb +0 -136
  40. data/spec/handlers/zip_stream_response_spec.rb +0 -58
  41. data/spec/helpers/github_payload_builder.rb +0 -141
  42. data/spec/helpers/integration_setup.rb +0 -47
  43. data/spec/integration/cassettes/github_l10n_hook_endpoint.yml +0 -536
  44. data/spec/integration/cassettes/pull.yml +0 -47
  45. data/spec/integration/cassettes/push.yml +0 -544
  46. data/spec/integration/cassettes/transifex_hook_endpoint.yml +0 -221
  47. data/spec/integration/config/tx.config +0 -10
  48. data/spec/integration/hooks_spec.rb +0 -159
  49. data/spec/integration/payloads/github_postbody.json +0 -161
  50. data/spec/integration/payloads/github_postbody_l10n.json +0 -136
  51. data/spec/integration/payloads/github_postbody_release.json +0 -136
  52. data/spec/integration/triggers_spec.rb +0 -45
  53. data/spec/transifex_request_auth_spec.rb +0 -39
@@ -1,87 +0,0 @@
1
- module Txgh
2
- module Handlers
3
- class DownloadHandler
4
- DEFAULT_FORMAT = '.zip'
5
-
6
- # includes response helpers in both the class and the singleton class
7
- include ResponseHelpers
8
-
9
- class << self
10
- def handle_request(request, logger = nil)
11
- handle_safely do
12
- config = config_from(request)
13
- project, repo = [config.transifex_project, config.github_repo]
14
- params = params_from(request)
15
- handler = new(project, repo, params, logger)
16
- handler.execute
17
- end
18
- end
19
-
20
- private
21
-
22
- def config_from(request)
23
- Txgh::Config::KeyManager.config_from_project(
24
- request.params.fetch('project_slug')
25
- )
26
- end
27
-
28
- def params_from(request)
29
- request.params.merge(
30
- 'format' => format_from(request)
31
- )
32
- end
33
-
34
- def format_from(request)
35
- # sinatra is dumb and doesn't include any of the URL captures in the
36
- # request params or env hash
37
- File.extname(request.env['REQUEST_PATH'])
38
- end
39
-
40
- def handle_safely
41
- yield
42
- rescue => e
43
- respond_with_error(500, "Internal server error: #{e.message}", e)
44
- end
45
- end
46
-
47
- attr_reader :project, :repo, :params, :logger
48
-
49
- def initialize(project, repo, params, logger)
50
- @project = project
51
- @repo = repo
52
- @params = params
53
- @logger = logger
54
- end
55
-
56
- def execute
57
- downloader = ResourceDownloader.new(
58
- project, repo, params['branch'], languages: project.languages
59
- )
60
-
61
- response_class.new(attachment, downloader.each)
62
- end
63
-
64
- private
65
-
66
- def attachment
67
- project.name
68
- end
69
-
70
- def format
71
- params.fetch('format', DEFAULT_FORMAT)
72
- end
73
-
74
- def response_class
75
- case format
76
- when '.zip'
77
- ZipStreamResponse
78
- when '.tgz'
79
- TgzStreamResponse
80
- else
81
- raise TxghInternalError,
82
- "'#{format}' is not a valid download format"
83
- end
84
- end
85
- end
86
- end
87
- end
@@ -1,65 +0,0 @@
1
- module Txgh
2
- module Handlers
3
- module Github
4
- class DeleteHandler < Handler
5
-
6
- include CategorySupport
7
-
8
- def execute
9
- delete_resources if should_handle_request?
10
- respond_with(200, true)
11
- end
12
-
13
- private
14
-
15
- def delete_resources
16
- tx_resources.each do |tx_resource|
17
- logger.info("Deleting #{tx_resource.resource_slug}")
18
- project.api.delete_resource(tx_resource)
19
- end
20
- end
21
-
22
- def tx_resources
23
- project.api.get_resources(project.name).map do |resource_hash|
24
- categories = deserialize_categories(resource_hash['categories'])
25
- resource_branch = Utils.absolute_branch(categories['branch'])
26
-
27
- if resource_branch == branch
28
- tx_branch_resource_from(resource_hash, branch)
29
- end
30
- end.compact
31
- end
32
-
33
- def tx_branch_resource_from(resource_hash, branch)
34
- TxBranchResource.new(
35
- tx_resource_from(resource_hash, branch), branch
36
- )
37
- end
38
-
39
- # project_slug, resource_slug, type, source_lang, source_file, lang_map, translation_file
40
- def tx_resource_from(resource_hash, branch)
41
- TxResource.new(
42
- project.name,
43
- TxBranchResource.deslugify(resource_hash['slug'], branch),
44
- resource_hash['i18n_type'],
45
- resource_hash['source_language_code'],
46
- resource_hash['name'],
47
- '', nil
48
- )
49
- end
50
-
51
- def should_handle_request?
52
- # ref_type can be either 'branch' or 'tag' - we only care about branches
53
- payload['ref_type'] == 'branch' &&
54
- repo.should_process_ref?(branch) &&
55
- project.auto_delete_resources?
56
- end
57
-
58
- def branch
59
- Utils.absolute_branch(payload['ref'].sub(/^refs\//, ''))
60
- end
61
-
62
- end
63
- end
64
- end
65
- end
@@ -1,20 +0,0 @@
1
- require 'logger'
2
-
3
- module Txgh
4
- module Handlers
5
- module Github
6
- class Handler
7
- include ResponseHelpers
8
-
9
- attr_reader :project, :repo, :payload, :logger
10
-
11
- def initialize(options = {})
12
- @project = options.fetch(:project)
13
- @repo = options.fetch(:repo)
14
- @payload = options.fetch(:payload)
15
- @logger = options.fetch(:logger) { Logger.new(STDOUT) }
16
- end
17
- end
18
- end
19
- end
20
- end
@@ -1,18 +0,0 @@
1
- module Txgh
2
- module Handlers
3
- module Github
4
- # Handles github's ping event, which is a test event fired whenever a new
5
- # webhook is set up.
6
- class PingHandler
7
- include ResponseHelpers
8
-
9
- def initialize(options = {})
10
- end
11
-
12
- def execute
13
- respond_with(200, {})
14
- end
15
- end
16
- end
17
- end
18
- end
@@ -1,124 +0,0 @@
1
- require 'base64'
2
- require 'set'
3
-
4
- module Txgh
5
- module Handlers
6
- module Github
7
- class PushHandler < Handler
8
-
9
- def execute
10
- # Check if the branch in the hook data is the configured branch we want
11
- logger.info("request github branch: #{branch}")
12
- logger.info("config github branch: #{repo.github_config_branch}")
13
-
14
- if should_process?
15
- logger.info('found branch in github request')
16
-
17
- tx_resources = tx_resources_for(branch)
18
-
19
- modified_resources = added_and_modified_resources_for(tx_resources)
20
- modified_resources += l10n_resources_for(tx_resources)
21
-
22
- if repo.github_config_branch.include?('tags/')
23
- modified_resources += tag_resources_for(tx_resources)
24
- end
25
-
26
- # Handle DBZ 'L10N' special case
27
- if branch.include?("L10N")
28
- logger.info('processing L10N tag')
29
-
30
- # Create a new branch off tag commit
31
- if branch.include?('tags/L10N')
32
- repo.api.create_ref(repo.name, 'heads/L10N', payload['head_commit']['id'])
33
- end
34
- end
35
-
36
- updater = ResourceUpdater.new(project, repo, logger)
37
- categories = { 'author' => payload['head_commit']['committer']['name'] }
38
- ref = repo.api.get_ref(repo.name, branch)
39
-
40
- modified_resources.each do |resource|
41
- updater.update_resource(resource, ref[:object][:sha], categories)
42
- end
43
- end
44
-
45
- respond_with(200, true)
46
- end
47
-
48
- private
49
-
50
- def tag_resources_for(tx_resources)
51
- payload['head_commit']['modified'].each_with_object(Set.new) do |modified, ret|
52
- logger.info("processing modified file: #{modified}")
53
-
54
- if tx_resources.include?(modified)
55
- ret << tx_resources[modified]
56
- end
57
- end
58
- end
59
-
60
- def l10n_resources_for(tx_resources)
61
- payload['head_commit']['modified'].each_with_object(Set.new) do |modified, ret|
62
- if tx_resources.include?(modified)
63
- logger.info("setting new resource: #{tx_resources[modified].L10N_resource_slug}")
64
- ret << tx_resources[modified]
65
- end
66
- end
67
- end
68
-
69
- # finds the resources that were updated in each commit
70
- def added_and_modified_resources_for(tx_resources)
71
- payload['commits'].each_with_object(Set.new) do |commit, ret|
72
- logger.info('processing commit')
73
-
74
- (commit['modified'] + commit['added']).each do |file|
75
- logger.info("processing added/modified file: #{file}")
76
-
77
- if tx_resources.include?(file)
78
- ret << tx_resources[file]
79
- end
80
- end
81
- end
82
- end
83
-
84
- # Build an index of known Tx resources, by source file
85
- def tx_resources_for(branch)
86
- tx_config.resources.each_with_object({}) do |resource, ret|
87
- logger.info('processing resource')
88
-
89
- # If we're processing by branch, create a branch resource. Otherwise,
90
- # use the original resource.
91
- ret[resource.source_file] = if repo.process_all_branches?
92
- TxBranchResource.new(resource, branch) # maybe find instead?
93
- else
94
- resource
95
- end
96
- end
97
- end
98
-
99
- def tx_config
100
- @tx_config ||= Txgh::Config::TxManager.tx_config(project, repo, branch)
101
- end
102
-
103
- def branch
104
- @ref ||= payload['ref'].sub(/^refs\//, '')
105
- end
106
-
107
- def should_process?
108
- should_process_branch? && should_process_commit?
109
- end
110
-
111
- def should_process_branch?
112
- repo.should_process_ref?(branch)
113
- end
114
-
115
- def should_process_commit?
116
- # return false if 'after' commit sha is all zeroes (indicates branch
117
- # has been deleted)
118
- !(payload.fetch('after', '') =~ /\A0+\z/)
119
- end
120
-
121
- end
122
- end
123
- end
124
- end
@@ -1,113 +0,0 @@
1
- require 'json'
2
-
3
- module Txgh
4
- module Handlers
5
- module Github
6
- class RequestHandler
7
- class << self
8
-
9
- include ResponseHelpers
10
-
11
- def handle_request(request, logger)
12
- case request.env['HTTP_X_GITHUB_EVENT']
13
- when 'push'
14
- handle_push(request, logger)
15
- when 'delete'
16
- handle_delete(request, logger)
17
- when 'ping'
18
- handle_ping(request, logger)
19
- else
20
- handle_unexpected
21
- end
22
- end
23
-
24
- private
25
-
26
- def handle_push(request, logger)
27
- klass = Txgh::Handlers::Github::PushHandler
28
- new(request, logger).handle(klass)
29
- end
30
-
31
- def handle_delete(request, logger)
32
- klass = Txgh::Handlers::Github::DeleteHandler
33
- new(request, logger).handle(klass)
34
- end
35
-
36
- def handle_ping(request, logger)
37
- klass = Txgh::Handlers::Github::PingHandler
38
- new(request, logger).handle(klass)
39
- end
40
-
41
- def handle_unexpected
42
- respond_with_error(400, 'Unexpected event type')
43
- end
44
-
45
- end
46
-
47
- include ResponseHelpers
48
-
49
- attr_reader :request, :logger
50
-
51
- def initialize(request, logger)
52
- @request = request
53
- @logger = logger
54
- end
55
-
56
- def handle(klass)
57
- handle_safely do
58
- handler = klass.new(
59
- project: config.transifex_project,
60
- repo: config.github_repo,
61
- payload: payload,
62
- logger: logger
63
- )
64
-
65
- handler.execute
66
- end
67
- end
68
-
69
- private
70
-
71
- def handle_safely
72
- if authentic_request?
73
- yield
74
- else
75
- respond_with_error(401, 'Unauthorized')
76
- end
77
- rescue => e
78
- respond_with_error(500, "Internal server error: #{e.message}", e)
79
- end
80
-
81
- def payload
82
- @payload ||= if request.params[:payload]
83
- JSON.parse(request.params[:payload])
84
- else
85
- JSON.parse(request.body.read)
86
- end
87
- end
88
-
89
- def github_repo_name
90
- payload['repository']['full_name']
91
- end
92
-
93
- def config
94
- @config ||= Txgh::Config::KeyManager.config_from_repo(github_repo_name)
95
- end
96
-
97
- def repo
98
- config.github_repo
99
- end
100
-
101
- def authentic_request?
102
- if repo.webhook_protected?
103
- GithubRequestAuth.authentic_request?(
104
- request, repo.webhook_secret
105
- )
106
- else
107
- true
108
- end
109
- end
110
- end
111
- end
112
- end
113
- end
@@ -1,11 +0,0 @@
1
- module Txgh
2
- module Handlers
3
- module Github
4
- autoload :DeleteHandler, 'txgh/handlers/github/delete_handler'
5
- autoload :Handler, 'txgh/handlers/github/handler'
6
- autoload :PingHandler, 'txgh/handlers/github/ping_handler'
7
- autoload :PushHandler, 'txgh/handlers/github/push_handler'
8
- autoload :RequestHandler, 'txgh/handlers/github/request_handler'
9
- end
10
- end
11
- end
@@ -1,17 +0,0 @@
1
- module Txgh
2
- module Handlers
3
- class Response
4
- attr_reader :status, :body, :error
5
-
6
- def initialize(status, body, error = nil)
7
- @status = status
8
- @body = body
9
- @error = error
10
- end
11
-
12
- def streaming?
13
- false
14
- end
15
- end
16
- end
17
- end
@@ -1,39 +0,0 @@
1
- require 'mime/types'
2
-
3
- module Txgh
4
- module Handlers
5
- class StreamResponse
6
- attr_reader :attachment, :enum
7
-
8
- def initialize(attachment, enum)
9
- @attachment = attachment
10
- @enum = enum
11
- end
12
-
13
- def write_to(stream)
14
- raise NotImplementedError,
15
- "please implement #{__method__} in derived classes"
16
- end
17
-
18
- def file_extension
19
- raise NotImplementedError,
20
- "please implement #{__method__} in derived classes"
21
- end
22
-
23
- def headers
24
- @headers ||= {
25
- 'Content-Disposition' => "attachment; filename=\"#{attachment}#{file_extension}\"",
26
- 'Content-Type' => MIME::Types.type_for(file_extension).first.content_type
27
- }
28
- end
29
-
30
- def streaming?
31
- true
32
- end
33
-
34
- def error
35
- nil
36
- end
37
- end
38
- end
39
- end
@@ -1,41 +0,0 @@
1
- require 'rubygems/package'
2
- require 'stringio'
3
- require 'zlib'
4
-
5
- module Txgh
6
- module Handlers
7
- class TgzStreamResponse < StreamResponse
8
- PERMISSIONS = 0644
9
-
10
- def write_to(stream)
11
- Zlib::GzipWriter.wrap(stream) do |gz|
12
- pipe = StringIO.new('', 'wb')
13
- tar = Gem::Package::TarWriter.new(pipe)
14
-
15
- enum.each do |file_name, contents|
16
- tar.add_file(file_name, PERMISSIONS) do |f|
17
- f.write(contents)
18
- end
19
-
20
- flush(tar, pipe, gz)
21
- stream.flush
22
- end
23
-
24
- flush(tar, pipe, gz)
25
- end
26
- end
27
-
28
- def file_extension
29
- '.tgz'
30
- end
31
-
32
- private
33
-
34
- def flush(tar, pipe, gz)
35
- tar.flush
36
- gz.write(pipe.string)
37
- pipe.reopen('')
38
- end
39
- end
40
- end
41
- end
@@ -1,94 +0,0 @@
1
- require 'logger'
2
-
3
- module Txgh
4
- module Handlers
5
- module Transifex
6
- class HookHandler
7
- include CategorySupport
8
- include ResponseHelpers
9
-
10
- attr_reader :project, :repo, :resource_slug, :language, :logger
11
-
12
- def initialize(options = {})
13
- @project = options.fetch(:project)
14
- @repo = options.fetch(:repo)
15
- @resource_slug = options.fetch(:resource_slug)
16
- @language = options.fetch(:language)
17
- @logger = options.fetch(:logger) { Logger.new(STDOUT) }
18
- end
19
-
20
- def execute
21
- logger.info(resource_slug)
22
-
23
- check_error_response || begin
24
- committer = ResourceCommitter.new(project, repo, logger)
25
- committer.commit_resource(tx_resource, branch, language)
26
- respond_with(200, true)
27
- end
28
- end
29
-
30
- private
31
-
32
- def check_error_response
33
- check_supported_language || check_tx_config || check_tx_resource
34
- end
35
-
36
- def check_supported_language
37
- respond_with(304, true) unless supported_language?
38
- end
39
-
40
- def check_tx_config
41
- unless tx_config
42
- respond_with_error(
43
- 404, "Could not find configuration for branch '#{branch}'"
44
- )
45
- end
46
- end
47
-
48
- def check_tx_resource
49
- unless tx_resource
50
- respond_with_error(
51
- 404, "Could not find resource '#{resource_slug}' in config"
52
- )
53
- end
54
- end
55
-
56
- def tx_config
57
- @tx_config ||= Txgh::Config::TxManager.tx_config(project, repo, branch)
58
- rescue ConfigNotFoundError, TxghError
59
- nil
60
- end
61
-
62
- def branch
63
- @branch ||= begin
64
- branch_candidate = if process_all_branches?
65
- resource = project.api.get_resource(project.name, resource_slug)
66
- categories = deserialize_categories(Array(resource['categories']))
67
- categories['branch']
68
- else
69
- repo.branch || 'master'
70
- end
71
-
72
- Utils.absolute_branch(branch_candidate)
73
- end
74
- end
75
-
76
- def tx_resource
77
- @tx_resource ||= if process_all_branches?
78
- tx_config.resource(resource_slug, branch)
79
- else
80
- tx_config.resource(resource_slug)
81
- end
82
- end
83
-
84
- def process_all_branches?
85
- repo.process_all_branches?
86
- end
87
-
88
- def supported_language?
89
- project.supported_language?(language)
90
- end
91
- end
92
- end
93
- end
94
- end