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://docs.github.com/en/free-pro-team@latest/rest/reference/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://docs.github.com/en/free-pro-team@latest/rest/reference/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://docs.github.com/en/free-pro-team@latest/rest/reference/migrations/#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	out := new(Import)
158	resp, err := s.client.Do(ctx, req, out)
159	if err != nil {
160		return nil, resp, err
161	}
162
163	return out, resp, nil
164}
165
166// ImportProgress queries for the status and progress of an ongoing repository import.
167//
168// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/migrations/#get-an-import-status
169func (s *MigrationService) ImportProgress(ctx context.Context, owner, repo string) (*Import, *Response, error) {
170	u := fmt.Sprintf("repos/%v/%v/import", owner, repo)
171	req, err := s.client.NewRequest("GET", u, nil)
172	if err != nil {
173		return nil, nil, err
174	}
175
176	out := new(Import)
177	resp, err := s.client.Do(ctx, req, out)
178	if err != nil {
179		return nil, resp, err
180	}
181
182	return out, resp, nil
183}
184
185// UpdateImport initiates a repository import.
186//
187// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/migrations/#update-an-import
188func (s *MigrationService) UpdateImport(ctx context.Context, owner, repo string, in *Import) (*Import, *Response, error) {
189	u := fmt.Sprintf("repos/%v/%v/import", owner, repo)
190	req, err := s.client.NewRequest("PATCH", u, in)
191	if err != nil {
192		return nil, nil, err
193	}
194
195	out := new(Import)
196	resp, err := s.client.Do(ctx, req, out)
197	if err != nil {
198		return nil, resp, err
199	}
200
201	return out, resp, nil
202}
203
204// CommitAuthors gets the authors mapped from the original repository.
205//
206// Each type of source control system represents authors in a different way.
207// For example, a Git commit author has a display name and an email address,
208// but a Subversion commit author just has a username. The GitHub Importer will
209// make the author information valid, but the author might not be correct. For
210// example, it will change the bare Subversion username "hubot" into something
211// like "hubot <hubot@12341234-abab-fefe-8787-fedcba987654>".
212//
213// This method and MapCommitAuthor allow you to provide correct Git author
214// information.
215//
216// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/migrations/#get-commit-authors
217func (s *MigrationService) CommitAuthors(ctx context.Context, owner, repo string) ([]*SourceImportAuthor, *Response, error) {
218	u := fmt.Sprintf("repos/%v/%v/import/authors", owner, repo)
219	req, err := s.client.NewRequest("GET", u, nil)
220	if err != nil {
221		return nil, nil, err
222	}
223
224	var authors []*SourceImportAuthor
225	resp, err := s.client.Do(ctx, req, &authors)
226	if err != nil {
227		return nil, resp, err
228	}
229
230	return authors, resp, nil
231}
232
233// MapCommitAuthor updates an author's identity for the import. Your
234// application can continue updating authors any time before you push new
235// commits to the repository.
236//
237// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/migrations/#map-a-commit-author
238func (s *MigrationService) MapCommitAuthor(ctx context.Context, owner, repo string, id int64, author *SourceImportAuthor) (*SourceImportAuthor, *Response, error) {
239	u := fmt.Sprintf("repos/%v/%v/import/authors/%v", owner, repo, id)
240	req, err := s.client.NewRequest("PATCH", u, author)
241	if err != nil {
242		return nil, nil, err
243	}
244
245	out := new(SourceImportAuthor)
246	resp, err := s.client.Do(ctx, req, out)
247	if err != nil {
248		return nil, resp, err
249	}
250
251	return out, resp, nil
252}
253
254// SetLFSPreference sets whether imported repositories should use Git LFS for
255// files larger than 100MB. Only the UseLFS field on the provided Import is
256// used.
257//
258// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/migrations/#update-git-lfs-preference
259func (s *MigrationService) SetLFSPreference(ctx context.Context, owner, repo string, in *Import) (*Import, *Response, error) {
260	u := fmt.Sprintf("repos/%v/%v/import/lfs", owner, repo)
261	req, err := s.client.NewRequest("PATCH", u, in)
262	if err != nil {
263		return nil, nil, err
264	}
265
266	out := new(Import)
267	resp, err := s.client.Do(ctx, req, out)
268	if err != nil {
269		return nil, resp, err
270	}
271
272	return out, resp, nil
273}
274
275// LargeFiles lists files larger than 100MB found during the import.
276//
277// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/migrations/#get-large-files
278func (s *MigrationService) LargeFiles(ctx context.Context, owner, repo string) ([]*LargeFile, *Response, error) {
279	u := fmt.Sprintf("repos/%v/%v/import/large_files", owner, repo)
280	req, err := s.client.NewRequest("GET", u, nil)
281	if err != nil {
282		return nil, nil, err
283	}
284
285	var files []*LargeFile
286	resp, err := s.client.Do(ctx, req, &files)
287	if err != nil {
288		return nil, resp, err
289	}
290
291	return files, resp, nil
292}
293
294// CancelImport stops an import for a repository.
295//
296// GitHub API docs: https://docs.github.com/en/free-pro-team@latest/rest/reference/migrations/#cancel-an-import
297func (s *MigrationService) CancelImport(ctx context.Context, owner, repo string) (*Response, error) {
298	u := fmt.Sprintf("repos/%v/%v/import", owner, repo)
299	req, err := s.client.NewRequest("DELETE", u, nil)
300	if err != nil {
301		return nil, err
302	}
303
304	return s.client.Do(ctx, req, nil)
305}
306