1// Copyright 2016 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	"fmt"
11)
12
13// Import represents a repository import request.
14type Import struct {
15	// The URL of the originating repository.
16	VCSURL *string `json:"vcs_url,omitempty"`
17	// The originating VCS type. Can be one of 'subversion', 'git',
18	// 'mercurial', or 'tfvc'. Without this parameter, the import job will
19	// take additional time to detect the VCS type before beginning the
20	// import. This detection step will be reflected in the response.
21	VCS *string `json:"vcs,omitempty"`
22	// VCSUsername and VCSPassword are only used for StartImport calls that
23	// are importing a password-protected repository.
24	VCSUsername *string `json:"vcs_username,omitempty"`
25	VCSPassword *string `json:"vcs_password,omitempty"`
26	// For a tfvc import, the name of the project that is being imported.
27	TFVCProject *string `json:"tfvc_project,omitempty"`
28
29	// LFS related fields that may be preset in the Import Progress response
30
31	// Describes whether the import has been opted in or out of using Git
32	// LFS. The value can be 'opt_in', 'opt_out', or 'undecided' if no
33	// action has been taken.
34	UseLFS *string `json:"use_lfs,omitempty"`
35	// Describes whether files larger than 100MB were found during the
36	// importing step.
37	HasLargeFiles *bool `json:"has_large_files,omitempty"`
38	// The total size in gigabytes of files larger than 100MB found in the
39	// originating repository.
40	LargeFilesSize *int `json:"large_files_size,omitempty"`
41	// The total number of files larger than 100MB found in the originating
42	// repository. To see a list of these files, call LargeFiles.
43	LargeFilesCount *int `json:"large_files_count,omitempty"`
44
45	// Identifies the current status of an import. An import that does not
46	// have errors will progress through these steps:
47	//
48	//     detecting - the "detection" step of the import is in progress
49	//         because the request did not include a VCS parameter. The
50	//         import is identifying the type of source control present at
51	//         the URL.
52	//     importing - the "raw" step of the import is in progress. This is
53	//         where commit data is fetched from the original repository.
54	//         The import progress response will include CommitCount (the
55	//         total number of raw commits that will be imported) and
56	//         Percent (0 - 100, the current progress through the import).
57	//     mapping - the "rewrite" step of the import is in progress. This
58	//         is where SVN branches are converted to Git branches, and
59	//         where author updates are applied. The import progress
60	//         response does not include progress information.
61	//     pushing - the "push" step of the import is in progress. This is
62	//         where the importer updates the repository on GitHub. The
63	//         import progress response will include PushPercent, which is
64	//         the percent value reported by git push when it is "Writing
65	//         objects".
66	//     complete - the import is complete, and the repository is ready
67	//         on GitHub.
68	//
69	// If there are problems, you will see one of these in the status field:
70	//
71	//     auth_failed - the import requires authentication in order to
72	//         connect to the original repository. Make an UpdateImport
73	//         request, and include VCSUsername and VCSPassword.
74	//     error - the import encountered an error. The import progress
75	//         response will include the FailedStep and an error message.
76	//         Contact GitHub support for more information.
77	//     detection_needs_auth - the importer requires authentication for
78	//         the originating repository to continue detection. Make an
79	//         UpdatImport request, and include VCSUsername and
80	//         VCSPassword.
81	//     detection_found_nothing - the importer didn't recognize any
82	//         source control at the URL.
83	//     detection_found_multiple - the importer found several projects
84	//         or repositories at the provided URL. When this is the case,
85	//         the Import Progress response will also include a
86	//         ProjectChoices field with the possible project choices as
87	//         values. Make an UpdateImport request, and include VCS and
88	//         (if applicable) TFVCProject.
89	Status        *string `json:"status,omitempty"`
90	CommitCount   *int    `json:"commit_count,omitempty"`
91	StatusText    *string `json:"status_text,omitempty"`
92	AuthorsCount  *int    `json:"authors_count,omitempty"`
93	Percent       *int    `json:"percent,omitempty"`
94	PushPercent   *int    `json:"push_percent,omitempty"`
95	URL           *string `json:"url,omitempty"`
96	HTMLURL       *string `json:"html_url,omitempty"`
97	AuthorsURL    *string `json:"authors_url,omitempty"`
98	RepositoryURL *string `json:"repository_url,omitempty"`
99	Message       *string `json:"message,omitempty"`
100	FailedStep    *string `json:"failed_step,omitempty"`
101
102	// Human readable display name, provided when the Import appears as
103	// part of ProjectChoices.
104	HumanName *string `json:"human_name,omitempty"`
105
106	// When the importer finds several projects or repositories at the
107	// provided URLs, this will identify the available choices. Call
108	// UpdateImport with the selected Import value.
109	ProjectChoices []Import `json:"project_choices,omitempty"`
110}
111
112func (i Import) String() string {
113	return Stringify(i)
114}
115
116// SourceImportAuthor identifies an author imported from a source repository.
117//
118// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#get-commit-authors
119type SourceImportAuthor struct {
120	ID         *int64  `json:"id,omitempty"`
121	RemoteID   *string `json:"remote_id,omitempty"`
122	RemoteName *string `json:"remote_name,omitempty"`
123	Email      *string `json:"email,omitempty"`
124	Name       *string `json:"name,omitempty"`
125	URL        *string `json:"url,omitempty"`
126	ImportURL  *string `json:"import_url,omitempty"`
127}
128
129func (a SourceImportAuthor) String() string {
130	return Stringify(a)
131}
132
133// LargeFile identifies a file larger than 100MB found during a repository import.
134//
135// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#get-large-files
136type LargeFile struct {
137	RefName *string `json:"ref_name,omitempty"`
138	Path    *string `json:"path,omitempty"`
139	OID     *string `json:"oid,omitempty"`
140	Size    *int    `json:"size,omitempty"`
141}
142
143func (f LargeFile) String() string {
144	return Stringify(f)
145}
146
147// StartImport initiates a repository import.
148//
149// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#start-an-import
150func (s *MigrationService) StartImport(ctx context.Context, owner, repo string, in *Import) (*Import, *Response, error) {
151	u := fmt.Sprintf("repos/%v/%v/import", owner, repo)
152	req, err := s.client.NewRequest("PUT", u, in)
153	if err != nil {
154		return nil, nil, err
155	}
156
157	// TODO: remove custom Accept header when this API fully launches
158	req.Header.Set("Accept", mediaTypeImportPreview)
159
160	out := new(Import)
161	resp, err := s.client.Do(ctx, req, out)
162	if err != nil {
163		return nil, resp, err
164	}
165
166	return out, resp, nil
167}
168
169// ImportProgress queries for the status and progress of an ongoing repository import.
170//
171// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#get-import-progress
172func (s *MigrationService) ImportProgress(ctx context.Context, owner, repo string) (*Import, *Response, error) {
173	u := fmt.Sprintf("repos/%v/%v/import", owner, repo)
174	req, err := s.client.NewRequest("GET", u, nil)
175	if err != nil {
176		return nil, nil, err
177	}
178
179	// TODO: remove custom Accept header when this API fully launches
180	req.Header.Set("Accept", mediaTypeImportPreview)
181
182	out := new(Import)
183	resp, err := s.client.Do(ctx, req, out)
184	if err != nil {
185		return nil, resp, err
186	}
187
188	return out, resp, nil
189}
190
191// UpdateImport initiates a repository import.
192//
193// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#update-existing-import
194func (s *MigrationService) UpdateImport(ctx context.Context, owner, repo string, in *Import) (*Import, *Response, error) {
195	u := fmt.Sprintf("repos/%v/%v/import", owner, repo)
196	req, err := s.client.NewRequest("PATCH", u, in)
197	if err != nil {
198		return nil, nil, err
199	}
200
201	// TODO: remove custom Accept header when this API fully launches
202	req.Header.Set("Accept", mediaTypeImportPreview)
203
204	out := new(Import)
205	resp, err := s.client.Do(ctx, req, out)
206	if err != nil {
207		return nil, resp, err
208	}
209
210	return out, resp, nil
211}
212
213// CommitAuthors gets the authors mapped from the original repository.
214//
215// Each type of source control system represents authors in a different way.
216// For example, a Git commit author has a display name and an email address,
217// but a Subversion commit author just has a username. The GitHub Importer will
218// make the author information valid, but the author might not be correct. For
219// example, it will change the bare Subversion username "hubot" into something
220// like "hubot <hubot@12341234-abab-fefe-8787-fedcba987654>".
221//
222// This method and MapCommitAuthor allow you to provide correct Git author
223// information.
224//
225// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#get-commit-authors
226func (s *MigrationService) CommitAuthors(ctx context.Context, owner, repo string) ([]*SourceImportAuthor, *Response, error) {
227	u := fmt.Sprintf("repos/%v/%v/import/authors", owner, repo)
228	req, err := s.client.NewRequest("GET", u, nil)
229	if err != nil {
230		return nil, nil, err
231	}
232
233	// TODO: remove custom Accept header when this API fully launches
234	req.Header.Set("Accept", mediaTypeImportPreview)
235
236	var authors []*SourceImportAuthor
237	resp, err := s.client.Do(ctx, req, &authors)
238	if err != nil {
239		return nil, resp, err
240	}
241
242	return authors, resp, nil
243}
244
245// MapCommitAuthor updates an author's identity for the import. Your
246// application can continue updating authors any time before you push new
247// commits to the repository.
248//
249// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#map-a-commit-author
250func (s *MigrationService) MapCommitAuthor(ctx context.Context, owner, repo string, id int64, author *SourceImportAuthor) (*SourceImportAuthor, *Response, error) {
251	u := fmt.Sprintf("repos/%v/%v/import/authors/%v", owner, repo, id)
252	req, err := s.client.NewRequest("PATCH", u, author)
253	if err != nil {
254		return nil, nil, err
255	}
256
257	// TODO: remove custom Accept header when this API fully launches
258	req.Header.Set("Accept", mediaTypeImportPreview)
259
260	out := new(SourceImportAuthor)
261	resp, err := s.client.Do(ctx, req, out)
262	if err != nil {
263		return nil, resp, err
264	}
265
266	return out, resp, nil
267}
268
269// SetLFSPreference sets whether imported repositories should use Git LFS for
270// files larger than 100MB. Only the UseLFS field on the provided Import is
271// used.
272//
273// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#set-git-lfs-preference
274func (s *MigrationService) SetLFSPreference(ctx context.Context, owner, repo string, in *Import) (*Import, *Response, error) {
275	u := fmt.Sprintf("repos/%v/%v/import/lfs", owner, repo)
276	req, err := s.client.NewRequest("PATCH", u, in)
277	if err != nil {
278		return nil, nil, err
279	}
280
281	// TODO: remove custom Accept header when this API fully launches
282	req.Header.Set("Accept", mediaTypeImportPreview)
283
284	out := new(Import)
285	resp, err := s.client.Do(ctx, req, out)
286	if err != nil {
287		return nil, resp, err
288	}
289
290	return out, resp, nil
291}
292
293// LargeFiles lists files larger than 100MB found during the import.
294//
295// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#get-large-files
296func (s *MigrationService) LargeFiles(ctx context.Context, owner, repo string) ([]*LargeFile, *Response, error) {
297	u := fmt.Sprintf("repos/%v/%v/import/large_files", owner, repo)
298	req, err := s.client.NewRequest("GET", u, nil)
299	if err != nil {
300		return nil, nil, err
301	}
302
303	// TODO: remove custom Accept header when this API fully launches
304	req.Header.Set("Accept", mediaTypeImportPreview)
305
306	var files []*LargeFile
307	resp, err := s.client.Do(ctx, req, &files)
308	if err != nil {
309		return nil, resp, err
310	}
311
312	return files, resp, nil
313}
314
315// CancelImport stops an import for a repository.
316//
317// GitHub API docs: https://developer.github.com/v3/migration/source_imports/#cancel-an-import
318func (s *MigrationService) CancelImport(ctx context.Context, owner, repo string) (*Response, error) {
319	u := fmt.Sprintf("repos/%v/%v/import", owner, repo)
320	req, err := s.client.NewRequest("DELETE", u, nil)
321	if err != nil {
322		return nil, err
323	}
324
325	// TODO: remove custom Accept header when this API fully launches
326	req.Header.Set("Accept", mediaTypeImportPreview)
327
328	return s.client.Do(ctx, req, nil)
329}
330