Skip to content

Commit 55c7f11

Browse files
committed
Add RepositoryFileCreate / RepositoryFileUpdate for repository files API
Replace the use of RepositoryFile (response shape) as input for create/update endpoints with dedicated input classes that match the official GitLab docs: - RepositoryFileCreate: input for POST /projects/:id/repository/files/:file_path - RepositoryFileUpdate extends RepositoryFileCreate, adding last_commit_id for PUT /projects/:id/repository/files/:file_path New overloads createFile(..., RepositoryFileCreate, ...) and updateFile(..., RepositoryFileUpdate, ...) added to RepositoryFileApi. The existing overloads taking RepositoryFile are now @deprecated and delegate to the new ones via internal converters, preserving backward compatibility. Also exposes start_branch and execute_filemode, which were not available before. Removes RepositoryFileRequest (introduced earlier in this branch), superseded by RepositoryFileCreate.
1 parent 0155424 commit 55c7f11

8 files changed

Lines changed: 312 additions & 85 deletions

File tree

gitlab4j-api/src/main/java/org/gitlab4j/api/RepositoryFileApi.java

Lines changed: 110 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@
1515

1616
import org.gitlab4j.api.models.Blame;
1717
import org.gitlab4j.api.models.RepositoryFile;
18-
import org.gitlab4j.api.models.RepositoryFileRequest;
18+
import org.gitlab4j.api.models.RepositoryFileCreate;
1919
import org.gitlab4j.api.models.RepositoryFileResponse;
20+
import org.gitlab4j.api.models.RepositoryFileUpdate;
2021
import org.gitlab4j.models.Constants;
2122

2223
/**
@@ -184,7 +185,7 @@ public RepositoryFile getFile(Object projectIdOrPath, String filePath, String re
184185
}
185186

186187
/**
187-
* Create new file in repository
188+
* Create new file in repository.
188189
*
189190
* <pre><code>GitLab Endpoint: POST /projects/:id/repository/files</code></pre>
190191
*
@@ -195,15 +196,44 @@ public RepositoryFile getFile(Object projectIdOrPath, String filePath, String re
195196
* commit_message (required) - Commit message
196197
*
197198
* @param projectIdOrPath the id, path of the project, or a Project instance holding the project ID or path
198-
* @param file a ReposityoryFile instance with info for the file to create
199+
* @param file a RepositoryFile instance with info for the file to create
199200
* @param branchName the name of branch
200201
* @param commitMessage the commit message
201-
* @return a RepositoryFile instance with the created file info
202+
* @return a RepositoryFileResponse instance with the created file info
202203
* @throws GitLabApiException if any exception occurs
204+
* @deprecated Use {@link #createFile(Object, RepositoryFileCreate, String, String)} instead.
205+
* {@link RepositoryFile} mixes read-only response fields with write input fields;
206+
* {@link RepositoryFileCreate} exposes only the parameters accepted by the endpoint and adds support
207+
* for {@code start_branch}, {@code execute_filemode}, {@code author_email} and {@code author_name}.
203208
*/
209+
@Deprecated
204210
public RepositoryFileResponse createFile(
205211
Object projectIdOrPath, RepositoryFile file, String branchName, String commitMessage)
206212
throws GitLabApiException {
213+
return createFile(projectIdOrPath, toCreate(file), branchName, commitMessage);
214+
}
215+
216+
/**
217+
* Create new file in repository.
218+
*
219+
* <pre><code>GitLab Endpoint: POST /projects/:id/repository/files/:file_path</code></pre>
220+
*
221+
* file_path (required) - Full path to new file. Ex. lib/class.rb
222+
* branch_name (required) - The name of branch
223+
* encoding (optional) - 'text' or 'base64'. Text is default.
224+
* content (required) - File content
225+
* commit_message (required) - Commit message
226+
*
227+
* @param projectIdOrPath the id, path of the project, or a Project instance holding the project ID or path
228+
* @param file a RepositoryFileCreate instance with the input parameters for the file to create
229+
* @param branchName the name of branch
230+
* @param commitMessage the commit message
231+
* @return a RepositoryFileResponse instance with the created file info (path and branch)
232+
* @throws GitLabApiException if any exception occurs
233+
*/
234+
public RepositoryFileResponse createFile(
235+
Object projectIdOrPath, RepositoryFileCreate file, String branchName, String commitMessage)
236+
throws GitLabApiException {
207237

208238
Form formData = createForm(file, branchName, commitMessage);
209239
Response response = post(
@@ -218,7 +248,7 @@ public RepositoryFileResponse createFile(
218248
}
219249

220250
/**
221-
* Create new file in repository
251+
* Create new file in repository.
222252
*
223253
* <pre><code>GitLab Endpoint: POST /projects/:id/repository/files</code></pre>
224254
*
@@ -228,13 +258,13 @@ public RepositoryFileResponse createFile(
228258
* content (required) - File content
229259
* commit_message (required) - Commit message
230260
*
231-
* @param file a ReposityoryFile instance with info for the file to create
261+
* @param file a RepositoryFile instance with info for the file to create
232262
* @param projectId the project ID
233263
* @param branchName the name of branch
234264
* @param commitMessage the commit message
235-
* @return a RepositoryFile instance with the created file info
265+
* @return a RepositoryFileResponse instance with the created file info
236266
* @throws GitLabApiException if any exception occurs
237-
* @deprecated Will be removed in version 6.0, replaced by {@link #createFile(Object, RepositoryFile, String, String)}
267+
* @deprecated Use {@link #createFile(Object, RepositoryFileCreate, String, String)} instead.
238268
*/
239269
@Deprecated
240270
public RepositoryFileResponse createFile(
@@ -243,7 +273,7 @@ public RepositoryFileResponse createFile(
243273
}
244274

245275
/**
246-
* Update existing file in repository
276+
* Update existing file in repository.
247277
*
248278
* <pre><code>GitLab Endpoint: PUT /projects/:id/repository/files</code></pre>
249279
*
@@ -254,15 +284,45 @@ public RepositoryFileResponse createFile(
254284
* commit_message (required) - Commit message
255285
*
256286
* @param projectIdOrPath the id, path of the project, or a Project instance holding the project ID or path
257-
* @param file a ReposityoryFile instance with info for the file to update
287+
* @param file a RepositoryFile instance with info for the file to update
258288
* @param branchName the name of branch
259289
* @param commitMessage the commit message
260-
* @return a RepositoryFile instance with the updated file info
290+
* @return a RepositoryFileResponse instance with the updated file info
261291
* @throws GitLabApiException if any exception occurs
292+
* @deprecated Use {@link #updateFile(Object, RepositoryFileUpdate, String, String)} instead.
293+
* {@link RepositoryFile} mixes read-only response fields with write input fields;
294+
* {@link RepositoryFileUpdate} exposes only the parameters accepted by the endpoint and adds support
295+
* for {@code start_branch}, {@code execute_filemode}, {@code last_commit_id}, {@code author_email}
296+
* and {@code author_name}.
262297
*/
298+
@Deprecated
263299
public RepositoryFileResponse updateFile(
264300
Object projectIdOrPath, RepositoryFile file, String branchName, String commitMessage)
265301
throws GitLabApiException {
302+
return updateFile(projectIdOrPath, toUpdate(file), branchName, commitMessage);
303+
}
304+
305+
/**
306+
* Update existing file in repository.
307+
*
308+
* <pre><code>GitLab Endpoint: PUT /projects/:id/repository/files/:file_path</code></pre>
309+
*
310+
* file_path (required) - Full path to new file. Ex. lib/class.rb
311+
* branch_name (required) - The name of branch
312+
* encoding (optional) - 'text' or 'base64'. Text is default.
313+
* content (required) - File content
314+
* commit_message (required) - Commit message
315+
*
316+
* @param projectIdOrPath the id, path of the project, or a Project instance holding the project ID or path
317+
* @param file a RepositoryFileUpdate instance with the input parameters for the file to update
318+
* @param branchName the name of branch
319+
* @param commitMessage the commit message
320+
* @return a RepositoryFileResponse instance with the updated file info (path and branch)
321+
* @throws GitLabApiException if any exception occurs
322+
*/
323+
public RepositoryFileResponse updateFile(
324+
Object projectIdOrPath, RepositoryFileUpdate file, String branchName, String commitMessage)
325+
throws GitLabApiException {
266326

267327
Form formData = createForm(file, branchName, commitMessage);
268328
Response response = put(
@@ -277,23 +337,17 @@ public RepositoryFileResponse updateFile(
277337
}
278338

279339
/**
280-
* Update existing file in repository
340+
* Update existing file in repository.
281341
*
282342
* <pre><code>GitLab Endpoint: PUT /projects/:id/repository/files</code></pre>
283343
*
284-
* file_path (required) - Full path to new file. Ex. lib/class.rb
285-
* branch_name (required) - The name of branch
286-
* encoding (optional) - 'text' or 'base64'. Text is default.
287-
* content (required) - File content
288-
* commit_message (required) - Commit message
289-
*
290-
* @param file a ReposityoryFile instance with info for the file to update
344+
* @param file a RepositoryFile instance with info for the file to update
291345
* @param projectId the project ID
292346
* @param branchName the name of branch
293347
* @param commitMessage the commit message
294-
* @return a RepositoryFile instance with the updated file info
348+
* @return a RepositoryFileResponse instance with the updated file info
295349
* @throws GitLabApiException if any exception occurs
296-
* @deprecated Will be removed in version 6.0, replaced by {@link #updateFile(Object, RepositoryFile, String, String)}
350+
* @deprecated Use {@link #updateFile(Object, RepositoryFileUpdate, String, String)} instead.
297351
*/
298352
@Deprecated
299353
public RepositoryFileResponse updateFile(
@@ -434,18 +488,21 @@ public InputStream getRawFile(Object projectIdOrPath, String ref, String filepat
434488
}
435489

436490
/**
437-
* Gets the query params based on the API version.
491+
* Builds the form payload sent on create/update requests.
438492
*
439-
* @param file the RepositoryFile instance with the info for the query params
493+
* @param file the RepositoryFileCreate (or RepositoryFileUpdate) instance with the input parameters
440494
* @param branchName the branch name
441495
* @param commitMessage the commit message
442496
* @return a Form instance with the correct query params.
443497
*/
444-
protected Form createForm(RepositoryFile file, String branchName, String commitMessage) {
498+
private Form createForm(RepositoryFileCreate file, String branchName, String commitMessage) {
445499

446500
Form form = new Form();
447501
addFormParam(form, "branch", branchName, true);
502+
addFormParam(form, "start_branch", file.getStartBranch(), false);
448503
addFormParam(form, "encoding", file.getEncoding(), false);
504+
addFormParam(form, "author_email", file.getAuthorEmail(), false);
505+
addFormParam(form, "author_name", file.getAuthorName(), false);
449506

450507
// Cannot use addFormParam() as it does not accept an empty or whitespace only string
451508
String content = file.getContent();
@@ -455,16 +512,41 @@ protected Form createForm(RepositoryFile file, String branchName, String commitM
455512
form.param("content", content);
456513

457514
addFormParam(form, "commit_message", commitMessage, true);
515+
addFormParam(form, "execute_filemode", file.getExecuteFilemode(), false);
458516

459-
if (file instanceof RepositoryFileRequest) {
460-
RepositoryFileRequest fileRequest = (RepositoryFileRequest) file;
461-
addFormParam(form, "author_email", fileRequest.getAuthorEmail(), false);
462-
addFormParam(form, "author_name", fileRequest.getAuthorName(), false);
517+
if (file instanceof RepositoryFileUpdate) {
518+
addFormParam(form, "last_commit_id", ((RepositoryFileUpdate) file).getLastCommitId(), false);
463519
}
464520

465521
return (form);
466522
}
467523

524+
/**
525+
* Copies the input fields of a {@link RepositoryFile} into a new {@link RepositoryFileCreate}.
526+
* Used by the deprecated {@code createFile(Object, RepositoryFile, ...)} overload.
527+
*/
528+
private RepositoryFileCreate toCreate(RepositoryFile file) {
529+
RepositoryFileCreate create = new RepositoryFileCreate();
530+
create.setFilePath(file.getFilePath());
531+
create.setContent(file.getContent());
532+
create.setEncoding(file.getEncoding());
533+
return create;
534+
}
535+
536+
/**
537+
* Copies the input fields of a {@link RepositoryFile} into a new {@link RepositoryFileUpdate},
538+
* preserving {@code lastCommitId} as the optimistic-locking hint.
539+
* Used by the deprecated {@code updateFile(Object, RepositoryFile, ...)} overload.
540+
*/
541+
private RepositoryFileUpdate toUpdate(RepositoryFile file) {
542+
RepositoryFileUpdate update = new RepositoryFileUpdate();
543+
update.setFilePath(file.getFilePath());
544+
update.setContent(file.getContent());
545+
update.setEncoding(file.getEncoding());
546+
update.setLastCommitId(file.getLastCommitId());
547+
return update;
548+
}
549+
468550
/**
469551
* Get a List of file blame from repository. Allows you to receive blame information.
470552
* Each blame range contains lines and corresponding commit information.
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
package org.gitlab4j.api.models;
2+
3+
import java.io.Serializable;
4+
import java.util.Base64;
5+
6+
import org.gitlab4j.models.Constants.Encoding;
7+
import org.gitlab4j.models.utils.JacksonJson;
8+
9+
import com.fasterxml.jackson.annotation.JsonIgnore;
10+
11+
/**
12+
* This class is used as input when creating a file in a repository.
13+
*
14+
* @see <a href="https://docs.gitlab.com/api/repository_files/#create-a-file-in-a-repository">Create a file in a repository</a>
15+
*/
16+
public class RepositoryFileCreate implements Serializable {
17+
private static final long serialVersionUID = 1L;
18+
19+
private String filePath;
20+
private String startBranch;
21+
private Encoding encoding;
22+
private String authorEmail;
23+
private String authorName;
24+
private String content;
25+
private Boolean executeFilemode;
26+
27+
public String getFilePath() {
28+
return filePath;
29+
}
30+
31+
public void setFilePath(String filePath) {
32+
this.filePath = filePath;
33+
}
34+
35+
public RepositoryFileCreate withFilePath(String filePath) {
36+
this.filePath = filePath;
37+
return this;
38+
}
39+
40+
public String getStartBranch() {
41+
return startBranch;
42+
}
43+
44+
public void setStartBranch(String startBranch) {
45+
this.startBranch = startBranch;
46+
}
47+
48+
public RepositoryFileCreate withStartBranch(String startBranch) {
49+
this.startBranch = startBranch;
50+
return this;
51+
}
52+
53+
public Encoding getEncoding() {
54+
return encoding;
55+
}
56+
57+
public void setEncoding(Encoding encoding) {
58+
this.encoding = encoding;
59+
}
60+
61+
public RepositoryFileCreate withEncoding(Encoding encoding) {
62+
this.encoding = encoding;
63+
return this;
64+
}
65+
66+
public String getAuthorEmail() {
67+
return authorEmail;
68+
}
69+
70+
public void setAuthorEmail(String authorEmail) {
71+
this.authorEmail = authorEmail;
72+
}
73+
74+
public RepositoryFileCreate withAuthorEmail(String authorEmail) {
75+
this.authorEmail = authorEmail;
76+
return this;
77+
}
78+
79+
public String getAuthorName() {
80+
return authorName;
81+
}
82+
83+
public void setAuthorName(String authorName) {
84+
this.authorName = authorName;
85+
}
86+
87+
public RepositoryFileCreate withAuthorName(String authorName) {
88+
this.authorName = authorName;
89+
return this;
90+
}
91+
92+
public String getContent() {
93+
return content;
94+
}
95+
96+
public void setContent(String content) {
97+
this.content = content;
98+
}
99+
100+
public RepositoryFileCreate withContent(String content) {
101+
this.content = content;
102+
return this;
103+
}
104+
105+
public Boolean getExecuteFilemode() {
106+
return executeFilemode;
107+
}
108+
109+
public void setExecuteFilemode(Boolean executeFilemode) {
110+
this.executeFilemode = executeFilemode;
111+
}
112+
113+
public RepositoryFileCreate withExecuteFilemode(Boolean executeFilemode) {
114+
this.executeFilemode = executeFilemode;
115+
return this;
116+
}
117+
118+
/**
119+
* Encodes the provided String using Base64 and sets it as the content.
120+
* The encoding property of this instance will be set to base64.
121+
*
122+
* @param content the String content to encode and set as the base64 encoded String content
123+
*/
124+
@JsonIgnore
125+
public void encodeAndSetContent(String content) {
126+
encodeAndSetContent(content != null ? content.getBytes() : null);
127+
}
128+
129+
/**
130+
* Encodes the provided byte array using Base64 and sets it as the content.
131+
* The encoding property of this instance will be set to base64.
132+
*
133+
* @param byteContent the byte[] content to encode and set as the base64 encoded String content
134+
*/
135+
@JsonIgnore
136+
public void encodeAndSetContent(byte[] byteContent) {
137+
if (byteContent == null) {
138+
this.content = null;
139+
return;
140+
}
141+
this.content = Base64.getEncoder().encodeToString(byteContent);
142+
this.encoding = Encoding.BASE64;
143+
}
144+
145+
@Override
146+
public String toString() {
147+
return (JacksonJson.toJsonString(this));
148+
}
149+
}

0 commit comments

Comments
 (0)