Class: Match::Storage::GoogleCloudStorage

Inherits:
Interface
  • Object
show all
Defined in:
match/lib/match/storage/google_cloud_storage.rb

Overview

Store the code signing identities in on Google Cloud Storage

Constant Summary collapse

DEFAULT_KEYS_FILE_NAME =
"gc_keys.json"

Constants inherited from Interface

Interface::MATCH_VERSION_FILE_NAME

Instance Attribute Summary collapse

Attributes inherited from Interface

#working_directory

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Interface

#clear_changes, #configure, #save_changes!

Constructor Details

#initialize(type: nil, platform: nil, google_cloud_bucket_name: nil, google_cloud_keys_file: nil, google_cloud_project_id: nil, readonly: nil, username: nil, team_id: nil, team_name: nil) ⇒ GoogleCloudStorage

Returns a new instance of GoogleCloudStorage.



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'match/lib/match/storage/google_cloud_storage.rb', line 51

def initialize(type: nil,
               platform: nil,
               google_cloud_bucket_name: nil,
               google_cloud_keys_file: nil,
               google_cloud_project_id: nil,
               readonly: nil,
               username: nil,
               team_id: nil,
               team_name: nil)
  @type = type if type
  @platform = platform if platform
  @google_cloud_project_id = google_cloud_project_id if google_cloud_project_id
  @bucket_name = google_cloud_bucket_name

  @readonly = readonly
  @username = username
  @team_id = team_id
  @team_name = team_name

  @google_cloud_keys_file = ensure_keys_file_exists(google_cloud_keys_file, google_cloud_project_id)

  if self.google_cloud_keys_file.to_s.length > 0
    # Extract the Project ID from the `JSON` file
    # so the user doesn't have to provide it manually
    keys_file_content = JSON.parse(File.read(self.google_cloud_keys_file))
    if google_cloud_project_id.to_s.length > 0 && google_cloud_project_id != keys_file_content["project_id"]
      UI.important("The google_cloud_keys_file's project ID ('#{keys_file_content['project_id']}') doesn't match the google_cloud_project_id ('#{google_cloud_project_id}'). This may be the wrong keys file.")
    end
    @google_cloud_project_id = keys_file_content["project_id"]
    if self.google_cloud_project_id.to_s.length == 0
      UI.user_error!("Provided keys file on path #{File.expand_path(self.google_cloud_keys_file)} doesn't include required value for `project_id`")
    end
  end

  # Create the Google Cloud Storage client
  # If the JSON auth file is invalid, this line will
  # raise an exception
  begin
    self.gc_storage = Google::Cloud::Storage.new(
      credentials: self.google_cloud_keys_file,
      project_id: self.google_cloud_project_id
    )
  rescue => ex
    UI.error(ex)
    UI.verbose(ex.backtrace.join("\n"))
    UI.user_error!("Couldn't log into your Google Cloud account using the provided JSON file at path '#{File.expand_path(self.google_cloud_keys_file)}'")
  end

  ensure_bucket_is_selected
  check_bucket_permissions
end

Instance Attribute Details

#bucket_nameObject (readonly)

Returns the value of attribute bucket_name.



19
20
21
# File 'match/lib/match/storage/google_cloud_storage.rb', line 19

def bucket_name
  @bucket_name
end

#gc_storageObject

Managed values



28
29
30
# File 'match/lib/match/storage/google_cloud_storage.rb', line 28

def gc_storage
  @gc_storage
end

#google_cloud_keys_fileObject (readonly)

Returns the value of attribute google_cloud_keys_file.



20
21
22
# File 'match/lib/match/storage/google_cloud_storage.rb', line 20

def google_cloud_keys_file
  @google_cloud_keys_file
end

#google_cloud_project_idObject (readonly)

Returns the value of attribute google_cloud_project_id.



21
22
23
# File 'match/lib/match/storage/google_cloud_storage.rb', line 21

def google_cloud_project_id
  @google_cloud_project_id
end

#platformObject (readonly)

Returns the value of attribute platform.



18
19
20
# File 'match/lib/match/storage/google_cloud_storage.rb', line 18

def platform
  @platform
end

#readonlyObject (readonly)

Returns the value of attribute readonly.



22
23
24
# File 'match/lib/match/storage/google_cloud_storage.rb', line 22

def readonly
  @readonly
end

#team_idObject (readonly)

Returns the value of attribute team_id.



24
25
26
# File 'match/lib/match/storage/google_cloud_storage.rb', line 24

def team_id
  @team_id
end

#team_nameObject (readonly)

Returns the value of attribute team_name.



25
26
27
# File 'match/lib/match/storage/google_cloud_storage.rb', line 25

def team_name
  @team_name
end

#typeObject (readonly)

User provided values



17
18
19
# File 'match/lib/match/storage/google_cloud_storage.rb', line 17

def type
  @type
end

#usernameObject (readonly)

Returns the value of attribute username.



23
24
25
# File 'match/lib/match/storage/google_cloud_storage.rb', line 23

def username
  @username
end

Class Method Details

.configure(params) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'match/lib/match/storage/google_cloud_storage.rb', line 30

def self.configure(params)
  if params[:git_url].to_s.length > 0
    UI.important("Looks like you still define a `git_url` somewhere, even though")
    UI.important("you use Google Cloud Storage. You can remove the `git_url`")
    UI.important("from your Matchfile and Fastfile")
    UI.message("The above is just a warning, fastlane will continue as usual now...")
  end

  return self.new(
    type: params[:type].to_s,
    platform: params[:platform].to_s,
    google_cloud_bucket_name: params[:google_cloud_bucket_name],
    google_cloud_keys_file: params[:google_cloud_keys_file],
    google_cloud_project_id: params[:google_cloud_project_id],
    readonly: params[:readonly],
    username: params[:username],
    team_id: params[:team_id],
    team_name: params[:team_name]
  )
end

Instance Method Details

#currently_used_team_idObject



103
104
105
106
107
108
109
110
111
112
# File 'match/lib/match/storage/google_cloud_storage.rb', line 103

def currently_used_team_id
  if self.readonly
    # In readonly mode, we still want to see if the user provided a team_id
    # see `prefixed_working_directory` comments for more details
    return self.team_id
  else
    spaceship = SpaceshipEnsure.new(self.username, self.team_id, self.team_name)
    return spaceship.team_id
  end
end

#delete_files(files_to_delete: [], custom_message: nil) ⇒ Object



147
148
149
150
151
152
153
154
# File 'match/lib/match/storage/google_cloud_storage.rb', line 147

def delete_files(files_to_delete: [], custom_message: nil)
  files_to_delete.each do |current_file|
    target_path = current_file.gsub(self.working_directory + "/", "")
    file = bucket.file(target_path)
    UI.message("Deleting '#{target_path}' from Google Cloud Storage bucket '#{self.bucket_name}'...")
    file.delete
  end
end

#downloadObject



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'match/lib/match/storage/google_cloud_storage.rb', line 129

def download
  # Check if we already have a functional working_directory
  return if @working_directory

  # No existing working directory, creating a new one now
  self.working_directory = Dir.mktmpdir

  bucket.files.each do |current_file|
    file_path = current_file.name # e.g. "N8X438SEU2/certs/distribution/XD9G7QCACF.cer"
    download_path = File.join(self.working_directory, file_path)

    FileUtils.mkdir_p(File.expand_path("..", download_path))
    UI.verbose("Downloading file from Google Cloud Storage '#{file_path}' on bucket #{self.bucket_name}")
    current_file.download(download_path)
  end
  UI.verbose("Successfully downloaded files from GCS to #{self.working_directory}")
end

#generate_matchfile_contentObject



187
188
189
# File 'match/lib/match/storage/google_cloud_storage.rb', line 187

def generate_matchfile_content
  return "google_cloud_bucket_name(\"#{self.bucket_name}\")"
end

#human_readable_descriptionObject



156
157
158
# File 'match/lib/match/storage/google_cloud_storage.rb', line 156

def human_readable_description
  "Google Cloud Bucket [#{self.google_cloud_project_id}/#{self.bucket_name}]"
end

#list_files(file_name: "", file_ext: "") ⇒ Object



183
184
185
# File 'match/lib/match/storage/google_cloud_storage.rb', line 183

def list_files(file_name: "", file_ext: "")
  Dir[File.join(working_directory, self.team_id, "**", file_name, "*.#{file_ext}")]
end

#prefixed_working_directoryObject



114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'match/lib/match/storage/google_cloud_storage.rb', line 114

def prefixed_working_directory
  # We fall back to "*", which means certificates and profiles
  # from all teams that use this bucket would be installed. This is not ideal, but
  # unless the user provides a `team_id`, we can't know which one to use
  # This only happens if `readonly` is activated, and no `team_id` was provided
  @_folder_prefix ||= currently_used_team_id
  if @_folder_prefix.nil?
    # We use a `@_folder_prefix` variable, to keep state between multiple calls of this
    # method, as the value won't change. This way the warning is only printed once
    UI.important("Looks like you run `match` in `readonly` mode, and didn't provide a `team_id`. This will still work, however it is recommended to provide a `team_id` in your Appfile or Matchfile")
    @_folder_prefix = "*"
  end
  return File.join(working_directory, @_folder_prefix)
end

#skip_docsObject



179
180
181
# File 'match/lib/match/storage/google_cloud_storage.rb', line 179

def skip_docs
  false
end

#upload_files(files_to_upload: [], custom_message: nil) ⇒ Object



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'match/lib/match/storage/google_cloud_storage.rb', line 160

def upload_files(files_to_upload: [], custom_message: nil)
  # `files_to_upload` is an array of files that need to be uploaded to Google Cloud
  # Those doesn't mean they're new, it might just be they're changed
  # Either way, we'll upload them using the same technique

  files_to_upload.each do |current_file|
    # Go from
    #   "/var/folders/px/bz2kts9n69g8crgv4jpjh6b40000gn/T/d20181026-96528-1av4gge/profiles/development/Development_me.mobileprovision"
    # to
    #   "profiles/development/Development_me.mobileprovision"
    #

    # We also have to remove the trailing `/` as Google Cloud doesn't handle it nicely
    target_path = current_file.gsub(self.working_directory + "/", "")
    UI.verbose("Uploading '#{target_path}' to Google Cloud Storage...")
    bucket.create_file(current_file, target_path)
  end
end