1// Copyright 2018 The go-github AUTHORS. All rights reserved. 2// 3// Use of this source code is governed by a BSD-style 4// license that can be found in the LICENSE file. 5 6package github 7 8import ( 9 "context" 10 "errors" 11 "fmt" 12 "net/http" 13) 14 15// UserMigration represents a GitHub migration (archival). 16type UserMigration struct { 17 ID *int64 `json:"id,omitempty"` 18 GUID *string `json:"guid,omitempty"` 19 // State is the current state of a migration. 20 // Possible values are: 21 // "pending" which means the migration hasn't started yet, 22 // "exporting" which means the migration is in progress, 23 // "exported" which means the migration finished successfully, or 24 // "failed" which means the migration failed. 25 State *string `json:"state,omitempty"` 26 // LockRepositories indicates whether repositories are locked (to prevent 27 // manipulation) while migrating data. 28 LockRepositories *bool `json:"lock_repositories,omitempty"` 29 // ExcludeAttachments indicates whether attachments should be excluded from 30 // the migration (to reduce migration archive file size). 31 ExcludeAttachments *bool `json:"exclude_attachments,omitempty"` 32 URL *string `json:"url,omitempty"` 33 CreatedAt *string `json:"created_at,omitempty"` 34 UpdatedAt *string `json:"updated_at,omitempty"` 35 Repositories []*Repository `json:"repositories,omitempty"` 36} 37 38func (m UserMigration) String() string { 39 return Stringify(m) 40} 41 42// UserMigrationOptions specifies the optional parameters to Migration methods. 43type UserMigrationOptions struct { 44 // LockRepositories indicates whether repositories should be locked (to prevent 45 // manipulation) while migrating data. 46 LockRepositories bool 47 48 // ExcludeAttachments indicates whether attachments should be excluded from 49 // the migration (to reduce migration archive file size). 50 ExcludeAttachments bool 51} 52 53// startUserMigration represents the body of a StartMigration request. 54type startUserMigration struct { 55 // Repositories is a slice of repository names to migrate. 56 Repositories []string `json:"repositories,omitempty"` 57 58 // LockRepositories indicates whether repositories should be locked (to prevent 59 // manipulation) while migrating data. 60 LockRepositories *bool `json:"lock_repositories,omitempty"` 61 62 // ExcludeAttachments indicates whether attachments should be excluded from 63 // the migration (to reduce migration archive file size). 64 ExcludeAttachments *bool `json:"exclude_attachments,omitempty"` 65} 66 67// StartUserMigration starts the generation of a migration archive. 68// repos is a slice of repository names to migrate. 69// 70// GitHub API docs: https://developer.github.com/v3/migrations/users/#start-a-user-migration 71func (s *MigrationService) StartUserMigration(ctx context.Context, repos []string, opt *UserMigrationOptions) (*UserMigration, *Response, error) { 72 u := "user/migrations" 73 74 body := &startUserMigration{Repositories: repos} 75 if opt != nil { 76 body.LockRepositories = Bool(opt.LockRepositories) 77 body.ExcludeAttachments = Bool(opt.ExcludeAttachments) 78 } 79 80 req, err := s.client.NewRequest("POST", u, body) 81 if err != nil { 82 return nil, nil, err 83 } 84 85 // TODO: remove custom Accept header when this API fully launches. 86 req.Header.Set("Accept", mediaTypeMigrationsPreview) 87 88 m := &UserMigration{} 89 resp, err := s.client.Do(ctx, req, m) 90 if err != nil { 91 return nil, resp, err 92 } 93 94 return m, resp, nil 95} 96 97// ListUserMigrations lists the most recent migrations. 98// 99// GitHub API docs: https://developer.github.com/v3/migrations/users/#get-a-list-of-user-migrations 100func (s *MigrationService) ListUserMigrations(ctx context.Context) ([]*UserMigration, *Response, error) { 101 u := "user/migrations" 102 103 req, err := s.client.NewRequest("GET", u, nil) 104 if err != nil { 105 return nil, nil, err 106 } 107 108 // TODO: remove custom Accept header when this API fully launches. 109 req.Header.Set("Accept", mediaTypeMigrationsPreview) 110 111 var m []*UserMigration 112 resp, err := s.client.Do(ctx, req, &m) 113 if err != nil { 114 return nil, resp, err 115 } 116 117 return m, resp, nil 118} 119 120// UserMigrationStatus gets the status of a specific migration archive. 121// id is the migration ID. 122// 123// GitHub API docs: https://developer.github.com/v3/migrations/users/#get-the-status-of-a-user-migration 124func (s *MigrationService) UserMigrationStatus(ctx context.Context, id int64) (*UserMigration, *Response, error) { 125 u := fmt.Sprintf("user/migrations/%v", id) 126 127 req, err := s.client.NewRequest("GET", u, nil) 128 if err != nil { 129 return nil, nil, err 130 } 131 132 // TODO: remove custom Accept header when this API fully launches. 133 req.Header.Set("Accept", mediaTypeMigrationsPreview) 134 135 m := &UserMigration{} 136 resp, err := s.client.Do(ctx, req, m) 137 if err != nil { 138 return nil, resp, err 139 } 140 141 return m, resp, nil 142} 143 144// UserMigrationArchiveURL gets the URL for a specific migration archive. 145// id is the migration ID. 146// 147// GitHub API docs: https://developer.github.com/v3/migrations/users/#download-a-user-migration-archive 148func (s *MigrationService) UserMigrationArchiveURL(ctx context.Context, id int64) (string, error) { 149 url := fmt.Sprintf("user/migrations/%v/archive", id) 150 151 req, err := s.client.NewRequest("GET", url, nil) 152 if err != nil { 153 return "", err 154 } 155 156 // TODO: remove custom Accept header when this API fully launches. 157 req.Header.Set("Accept", mediaTypeMigrationsPreview) 158 159 m := &UserMigration{} 160 161 var loc string 162 originalRedirect := s.client.client.CheckRedirect 163 s.client.client.CheckRedirect = func(req *http.Request, via []*http.Request) error { 164 loc = req.URL.String() 165 return http.ErrUseLastResponse 166 } 167 defer func() { 168 s.client.client.CheckRedirect = originalRedirect 169 }() 170 resp, err := s.client.Do(ctx, req, m) 171 if err == nil { 172 return "", errors.New("expected redirect, none provided") 173 } 174 loc = resp.Header.Get("Location") 175 return loc, nil 176} 177 178// DeleteUserMigration will delete a previous migration archive. 179// id is the migration ID. 180// 181// GitHub API docs: https://developer.github.com/v3/migrations/users/#delete-a-user-migration-archive 182func (s *MigrationService) DeleteUserMigration(ctx context.Context, id int64) (*Response, error) { 183 url := fmt.Sprintf("user/migrations/%v/archive", id) 184 185 req, err := s.client.NewRequest("DELETE", url, nil) 186 if err != nil { 187 return nil, err 188 } 189 190 // TODO: remove custom Accept header when this API fully launches. 191 req.Header.Set("Accept", mediaTypeMigrationsPreview) 192 193 return s.client.Do(ctx, req, nil) 194} 195 196// UnlockUserRepository will unlock a repo that was locked for migration. 197// id is migration ID. 198// You should unlock each migrated repository and delete them when the migration 199// is complete and you no longer need the source data. 200// 201// GitHub API docs: https://developer.github.com/v3/migrations/users/#unlock-a-user-repository 202func (s *MigrationService) UnlockUserRepo(ctx context.Context, id int64, repo string) (*Response, error) { 203 url := fmt.Sprintf("user/migrations/%v/repos/%v/lock", id, repo) 204 205 req, err := s.client.NewRequest("DELETE", url, nil) 206 if err != nil { 207 return nil, err 208 } 209 210 // TODO: remove custom Accept header when this API fully launches. 211 req.Header.Set("Accept", mediaTypeMigrationsPreview) 212 213 return s.client.Do(ctx, req, nil) 214} 215