Module: BackupOnTheGo

Defined in:
lib/backup_on_the_go.rb,
lib/backup_on_the_go/version.rb

Overview

:nodoc:#

Defined Under Namespace

Modules: VERSION

Constant Summary collapse

DEFAULT_CONFIG =

:nodoc:#

{
  :backup_fork => false,
  :backup_private => false,
  :git_cmd => 'git',
  :github_repos_max => '200',
  :is_private => true,
  :no_public_forks => true,
  :repo_prefix => 'backup-on-the-go-',
  :verbose => true
}.freeze

Class Method Summary collapse

Class Method Details

.backup(configs = {}) ⇒ Object

Back up GitHub repositories to BitBucket.

Parameters

  • :backup_fork - Optional boolean - true to back up forked repositories, false to skip them. Default is false.

  • :backup_private - Optional boolean - true to back up private repositories, false to NOT back up private repositories. Default is false.

  • :bitbucket_password - Optional string - The password to access the BitBucket account. If not specified, a prompt will show up to ask for the password.

  • :bitbucket_repos_owner - Optional string - Owner of the backup repositories on BitBucket. The owner could be a team. If not specified, :bitbucket_user will be used.

  • :bitbucket_user - Required string if :user is not specified - The user name on BitBucket. If not specified, :user will be used.

  • :git_cmd - Optional string - The git command you want to use. Default is ‘git’.

  • :github_password - Optional string - When backup_private is set to true, this is the password used to access the GitHub account. If not specified, a prompt will show up to ask for the password.

  • :github_repos_max - Optional string - The max number of your GitHub repos, since GitHub API requires to give a repo number upper limit. Usually you don’t need to set up this number unless you have more than 200 repositories. Default is "200".

  • :github_repos_owner - Optional string - The owner of the repositories that need to be backed up. The owner could be an organization. If not specified, :github_user will be used.

  • :github_user - Required string if :user is not specified - The user name on GitHub. If not specified, :user will be used.

  • :is_private - Optional boolean - true to make the backup repositories private even if the corresponding github repositories are public; false to keep the original privacy. Default is true.

  • :no_public_forks - Optional boolean - true to forbid public fork for the backup repositories, false to allow public fork. Only valid for public backup repositories. Default is true.

  • :repo_prefix - Optional string - The prefix you wanna prepend to the backup repository names. In this way, if you have a repository with the same name on BitBucket, it won’t get flushed. Default is "backup-on-the-go-".

  • :user - Required string if :github_user and :bitbucket_user are not both specified - The user name of GitHub and BitBucket (if they are same for you). If you want to use different user names on GitHub and BitBucket, please specify :github_user and :bitbucket_user instead.

  • :verbose - Optional boolean - true to print additional information and false to suppress them. Default is true.

Examples

# Back up personal public repositories only
BackupOnTheGo.backup :github_user => 'github_user_name',
:bitbucket_user => 'bitbucket_user_name',
:is_private => false,    # make backup repositories public
:bitbucket_password => 'bitbucket_password',
:repo_prefix => ''      # don't need any prefix

Examples

# Back up personal public and private repositories
BackupOnTheGo.backup :github_user => 'github_user_name',
:bitbucket_user => 'bitbucket_user_name',
:backup_private => true,   # back up private repositories
:is_private => false,    # make backup repositories public
:github_password => 'github_password',
:bitbucket_password => 'bitbucket_password',
:repo_prefix => ''      # don't need any prefix

Examples

# Back up organization repositories
BackupOnTheGo.backup :github_user => 'github_user_name',
:github_repos_owner => 'organization_name',
:bitbucket_user => 'bitbucket_user_name',
:bitbucket_repos_owner => 'bitbucket_team_name',
:bitbucket_password => 'bitbucket_password',
:repo_prefix => 'our-backup'


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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'lib/backup_on_the_go.rb', line 73

def self.backup(configs = {})

  config = DEFAULT_CONFIG.merge(configs)

  # either :user or :github_user and :bitbucket_user have to be set
  if config.has_key?(:user)
    config[:github_user] = config[:user] unless config.has_key?(:github_user)
    config[:bitbucket_user] = config[:user] unless config.has_key?(:bitbucket_user)
  end

  unless config.has_key?(:github_user) and config.has_key?(:bitbucket_user)
    raise 'No user name provided.'
  end

  unless config.has_key?(:github_repos_owner) # Owner of the github repos. Could be an organization
    config[:github_repos_owner] = config[:github_user]
  end

  unless config.has_key?(:bitbucket_repos_owner) # Owner of backup repositories. Could be a team.
    config[:bitbucket_repos_owner] = config[:bitbucket_user]
  end

  # Ask for the passwords if they are not specified
  if config[:backup_private] and !config.has_key?(:github_password)
    config[:github_password] = ask("Enter your GitHub password for #{config[:github_user]}: ") { |q| q.echo = false }
  end
  unless config.has_key?(:bitbucket_password)
    config[:bitbucket_password] = ask("Enter your BitBucket password for #{config[:bitbucket_user]}: ") { |q| q.echo = false }
  end

  # print an empty line
  puts

  # log in BitBucket

  bb = BitBucket.new :login => config[:bitbucket_user], :password => config[:bitbucket_password]

  backup_repo_names = Array.new

  bb.repos.list do |repo|
    if repo.owner == config[:bitbucket_repos_owner]
      backup_repo_names.push(repo.slug)
    end
  end

  # handling each GitHub repo, used below
  repo_each_proc = Proc.new do |repo|
    next if repo.fork && !config[:backup_fork]

    is_private = config[:is_private] || repo.private?

    puts "Backing up #{repo.name}..." if config[:verbose]

    backup_repo_name = "#{config[:repo_prefix]}#{repo.name}"

    # Create backup repositories if we don't have them yet
    unless backup_repo_names.include?(backup_repo_name.downcase)
      puts "Creating new repository #{config[:bitbucket_repos_owner]}/#{backup_repo_name}..." if config[:verbose]
      begin
        bb.repos.create :name => backup_repo_name, :owner => config[:bitbucket_repos_owner],
          :scm => 'git', :is_private => is_private,
          :no_public_forks => config[:no_public_forks]
      rescue
        puts_warning "Creation of repository #{config[:bitbucket_repos_owner]}/#{backup_repo_name} failed."
      end
    end

    puts "Backing up resources..." if config[:verbose]

    begin
      bb.repos.edit config[:bitbucket_repos_owner], backup_repo_name,
        :website => repo.homepage,
        :description => repo.description,
        :is_private => is_private,
        :no_public_forks => is_private && config[:no_public_forks]
    rescue Exception => e
      puts_warning "Failed to update information for #{config[:bitbucket_repos_owner]}/#{backup_repo_name}"
      puts e.message
    end

    Dir.mktmpdir do |dir|
      # clone git url
      clone_url = repo.clone_url
      clone_url.sub!(/https:\/\//,
                     "https://#{config[:github_user]}:#{config[:github_password]}@") if config[:backup_private]
      cmd = "#{config[:git_cmd]} clone --mirror '#{clone_url}' #{dir}/tmp-repo"
      puts "Executing [#{config[:git_cmd]} clone --mirror 'https://#{config[:bitbucket_user]}:[email protected]/#{config[:github_repos_owner]}/#{repo.name}.git' #{dir}/tmp-repo]" if config[:verbose]
      unless system(cmd)
        puts_warning "'git clone' failed for #{clone_url}\n"
        break
      end

      # Add bitbucket remote
      cmd = "cd #{dir}/tmp-repo && " +
        "#{config[:git_cmd]} remote add bitbucket 'https://#{config[:bitbucket_user]}:#{config[:bitbucket_password]}@bitbucket.org/#{config[:bitbucket_repos_owner]}/#{backup_repo_name}.git'"
      puts "Executing [#{config[:git_cmd]} remote add bitbucket 'https://#{config[:bitbucket_user]}:[email protected]/#{config[:bitbucket_repos_owner]}/#{backup_repo_name}.git']" if config[:verbose]
      `#{cmd}`
      unless $?.exitstatus
        puts_warning "'git remote add bitbucket ...' failed for #{config[:bitbucket_repos_owner]}/#{backup_repo_name}\n"
        break
      end

      # obtain the main branch (usually master, just in case)
      cmd = "cd #{dir}/tmp-repo && #{config[:git_cmd]} branch"
      puts "Executing #{cmd}" if config[:verbose]
      branches = `#{cmd}`
      unless $?.exitstatus
        puts_warning "''#{config[:git_cmd]} branch' failed for #{config[:github_repos_owner]}/#{repo.name}"
        break
      end
      main_branch = nil
      branches.each_line do |line|
        # This is the main branch we need
        if line.length >= 1 and line[0] == '*'
          main_branch = line[1..-1].strip
        end
      end

      cmd = "cd #{dir}/tmp-repo && "
      if main_branch != nil # push bitbucket #{main_branch} first before push --mirror
        cmd += "#{config[:git_cmd]} push bitbucket #{main_branch} && "
      end
      cmd += "#{config[:git_cmd]} push --mirror bitbucket"
      puts "Executing #{cmd}" if config[:verbose]
      `#{cmd}`
      unless $?.exitstatus
        puts_warning "'#{config[:git_cmd]} push' failed for #{config[:bitbucket_repos_owner]}/#{backup_repo_name}\n"
        break
      end
      puts
    end
  end

  # obtain github repos
  if config[:backup_private]
    gh = Github.new :login => config[:github_user], :password => config[:github_password]
  else
    gh = Github.new
  end

  # private repos
  if config[:backup_private]
    puts "Backing up private repositories...\n".green

    gh_repos = gh.repos.list :per_page => config[:github_repos_max]

    gh_repos.each do |repo|
      # only back up private repositories with the owner specified
      if repo.owner. == config[:github_repos_owner] and repo.private?
        repo_each_proc.call(repo)
      end
    end
  end

  # public repos
  puts "Backing up public repositories...\n".green

  gh_repos = gh.repos.list :user => config[:github_repos_owner],
    :per_page => config[:github_repos_max]

  gh_repos.each do |repo|
    repo_each_proc.call(repo)
  end


end