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