1
2
3
4
5
6
7
8
9
10 package org.eclipse.jgit.api;
11
12 import java.io.IOException;
13 import java.text.MessageFormat;
14
15 import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
16 import org.eclipse.jgit.api.errors.GitAPIException;
17 import org.eclipse.jgit.api.errors.InvalidTagNameException;
18 import org.eclipse.jgit.api.errors.JGitInternalException;
19 import org.eclipse.jgit.api.errors.NoHeadException;
20 import org.eclipse.jgit.api.errors.RefAlreadyExistsException;
21 import org.eclipse.jgit.api.errors.ServiceUnavailableException;
22 import org.eclipse.jgit.api.errors.UnsupportedSigningFormatException;
23 import org.eclipse.jgit.internal.JGitText;
24 import org.eclipse.jgit.lib.Constants;
25 import org.eclipse.jgit.lib.GpgConfig;
26 import org.eclipse.jgit.lib.GpgConfig.GpgFormat;
27 import org.eclipse.jgit.lib.GpgObjectSigner;
28 import org.eclipse.jgit.lib.GpgSigner;
29 import org.eclipse.jgit.lib.ObjectId;
30 import org.eclipse.jgit.lib.ObjectInserter;
31 import org.eclipse.jgit.lib.PersonIdent;
32 import org.eclipse.jgit.lib.Ref;
33 import org.eclipse.jgit.lib.RefUpdate;
34 import org.eclipse.jgit.lib.RefUpdate.Result;
35 import org.eclipse.jgit.lib.Repository;
36 import org.eclipse.jgit.lib.RepositoryState;
37 import org.eclipse.jgit.lib.TagBuilder;
38 import org.eclipse.jgit.revwalk.RevObject;
39 import org.eclipse.jgit.revwalk.RevWalk;
40 import org.eclipse.jgit.transport.CredentialsProvider;
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65 public class TagCommand extends GitCommand<Ref> {
66
67 private RevObject id;
68
69 private String name;
70
71 private String message;
72
73 private PersonIdent tagger;
74
75 private Boolean signed;
76
77 private boolean forceUpdate;
78
79 private Boolean annotated;
80
81 private String signingKey;
82
83 private GpgConfig gpgConfig;
84
85 private GpgObjectSigner gpgSigner;
86
87 private CredentialsProvider credentialsProvider;
88
89
90
91
92
93
94 protected TagCommand(Repository repo) {
95 super(repo);
96 this.credentialsProvider = CredentialsProvider.getDefault();
97 }
98
99
100
101
102
103
104
105
106
107
108
109 @Override
110 public Ref call() throws GitAPIException, ConcurrentRefUpdateException,
111 InvalidTagNameException, NoHeadException {
112 checkCallable();
113
114 RepositoryState state = repo.getRepositoryState();
115 processOptions(state);
116
117 try (RevWalk revWalk = new RevWalk(repo)) {
118
119 if (id == null) {
120 ObjectId objectId = repo.resolve(Constants.HEAD + "^{commit}");
121 if (objectId == null)
122 throw new NoHeadException(
123 JGitText.get().tagOnRepoWithoutHEADCurrentlyNotSupported);
124
125 id = revWalk.parseCommit(objectId);
126 }
127
128 if (!isAnnotated()) {
129 return updateTagRef(id, revWalk, name,
130 "SimpleTag[" + name + " : " + id
131 + "]");
132 }
133
134
135 TagBuilder newTag = new TagBuilder();
136 newTag.setTag(name);
137 newTag.setMessage(message);
138 newTag.setTagger(tagger);
139 newTag.setObjectId(id);
140
141 if (gpgSigner != null) {
142 gpgSigner.signObject(newTag, signingKey, tagger,
143 credentialsProvider, gpgConfig);
144 }
145
146
147 try (ObjectInserter inserter = repo.newObjectInserter()) {
148 ObjectId tagId = inserter.insert(newTag);
149 inserter.flush();
150
151 String tag = newTag.getTag();
152 return updateTagRef(tagId, revWalk, tag, newTag.toString());
153
154 }
155
156 } catch (IOException e) {
157 throw new JGitInternalException(
158 JGitText.get().exceptionCaughtDuringExecutionOfTagCommand,
159 e);
160 }
161 }
162
163 private Ref updateTagRef(ObjectId tagId, RevWalk revWalk,
164 String tagName, String newTagToString) throws IOException,
165 ConcurrentRefUpdateException, RefAlreadyExistsException {
166 String refName = Constants.R_TAGS + tagName;
167 RefUpdate tagRef = repo.updateRef(refName);
168 tagRef.setNewObjectId(tagId);
169 tagRef.setForceUpdate(forceUpdate);
170 tagRef.setRefLogMessage("tagged " + name, false);
171 Result updateResult = tagRef.update(revWalk);
172 switch (updateResult) {
173 case NEW:
174 case FORCED:
175 return repo.exactRef(refName);
176 case LOCK_FAILURE:
177 throw new ConcurrentRefUpdateException(
178 JGitText.get().couldNotLockHEAD, tagRef.getRef(),
179 updateResult);
180 case NO_CHANGE:
181 if (forceUpdate) {
182 return repo.exactRef(refName);
183 }
184 throw new RefAlreadyExistsException(MessageFormat
185 .format(JGitText.get().tagAlreadyExists, newTagToString),
186 updateResult);
187 case REJECTED:
188 throw new RefAlreadyExistsException(MessageFormat.format(
189 JGitText.get().tagAlreadyExists, newTagToString),
190 updateResult);
191 default:
192 throw new JGitInternalException(MessageFormat.format(
193 JGitText.get().updatingRefFailed, refName, newTagToString,
194 updateResult));
195 }
196 }
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213 private void processOptions(RepositoryState state)
214 throws InvalidTagNameException, ServiceUnavailableException,
215 UnsupportedSigningFormatException {
216 if (name == null
217 || !Repository.isValidRefName(Constants.R_TAGS + name)) {
218 throw new InvalidTagNameException(
219 MessageFormat.format(JGitText.get().tagNameInvalid,
220 name == null ? "<null>" : name));
221 }
222 if (!isAnnotated()) {
223 if ((message != null && !message.isEmpty()) || tagger != null) {
224 throw new JGitInternalException(JGitText
225 .get().messageAndTaggerNotAllowedInUnannotatedTags);
226 }
227 } else {
228 if (tagger == null) {
229 tagger = new PersonIdent(repo);
230 }
231
232 if (!(Boolean.FALSE.equals(signed) && signingKey == null)) {
233 if (gpgConfig == null) {
234 gpgConfig = new GpgConfig(repo.getConfig());
235 }
236 boolean doSign = isSigned() || gpgConfig.isSignAllTags();
237 if (!Boolean.TRUE.equals(annotated) && !doSign) {
238 doSign = gpgConfig.isSignAnnotated();
239 }
240 if (doSign) {
241 if (signingKey == null) {
242 signingKey = gpgConfig.getSigningKey();
243 }
244 if (gpgSigner == null) {
245 GpgSigner signer = GpgSigner.getDefault();
246 if (!(signer instanceof GpgObjectSigner)) {
247 throw new ServiceUnavailableException(
248 JGitText.get().signingServiceUnavailable);
249 }
250 gpgSigner = (GpgObjectSigner) signer;
251 }
252
253
254 if (message != null && !message.isEmpty()
255 && !message.endsWith("\n")) {
256 message += '\n';
257 }
258 }
259 }
260 }
261 }
262
263
264
265
266
267
268
269
270 public TagCommand setName(String name) {
271 checkCallable();
272 this.name = name;
273 return this;
274 }
275
276
277
278
279
280
281 public String getName() {
282 return name;
283 }
284
285
286
287
288
289
290 public String getMessage() {
291 return message;
292 }
293
294
295
296
297
298
299
300
301 public TagCommand setMessage(String message) {
302 checkCallable();
303 this.message = message;
304 return this;
305 }
306
307
308
309
310
311
312
313
314 public boolean isSigned() {
315 return Boolean.TRUE.equals(signed) || signingKey != null;
316 }
317
318
319
320
321
322
323
324
325
326
327
328
329
330 public TagCommand setSigned(boolean signed) {
331 checkCallable();
332 this.signed = Boolean.valueOf(signed);
333 return this;
334 }
335
336
337
338
339
340
341
342
343
344 public TagCommand setGpgSigner(GpgObjectSigner signer) {
345 checkCallable();
346 this.gpgSigner = signer;
347 return this;
348 }
349
350
351
352
353
354
355
356
357
358
359
360 public TagCommand setGpgConfig(GpgConfig config) {
361 checkCallable();
362 this.gpgConfig = config;
363 return this;
364 }
365
366
367
368
369
370
371
372
373
374 public TagCommand setTagger(PersonIdent tagger) {
375 checkCallable();
376 this.tagger = tagger;
377 return this;
378 }
379
380
381
382
383
384
385 public PersonIdent getTagger() {
386 return tagger;
387 }
388
389
390
391
392
393
394 public RevObject getObjectId() {
395 return id;
396 }
397
398
399
400
401
402
403
404
405
406 public TagCommand setObjectId(RevObject id) {
407 checkCallable();
408 this.id = id;
409 return this;
410 }
411
412
413
414
415
416
417 public boolean isForceUpdate() {
418 return forceUpdate;
419 }
420
421
422
423
424
425
426
427
428
429 public TagCommand setForceUpdate(boolean forceUpdate) {
430 checkCallable();
431 this.forceUpdate = forceUpdate;
432 return this;
433 }
434
435
436
437
438
439
440
441
442
443 public TagCommand setAnnotated(boolean annotated) {
444 checkCallable();
445 this.annotated = Boolean.valueOf(annotated);
446 return this;
447 }
448
449
450
451
452
453
454
455
456 public boolean isAnnotated() {
457 boolean setExplicitly = Boolean.TRUE.equals(annotated) || isSigned();
458 if (setExplicitly) {
459 return true;
460 }
461
462 return annotated == null;
463 }
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485 public TagCommand setSigningKey(String signingKey) {
486 checkCallable();
487 this.signingKey = signingKey;
488 return this;
489 }
490
491
492
493
494
495
496
497 public String getSigningKey() {
498 return signingKey;
499 }
500
501
502
503
504
505
506
507
508
509
510 public TagCommand setCredentialsProvider(
511 CredentialsProvider credentialsProvider) {
512 checkCallable();
513 this.credentialsProvider = credentialsProvider;
514 return this;
515 }
516
517 }