1 /** 2 * Copyright (c) 2013-2023, jcabi.com 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 1) Redistributions of source code must retain the above 8 * copyright notice, this list of conditions and the following 9 * disclaimer. 2) Redistributions in binary form must reproduce the above 10 * copyright notice, this list of conditions and the following 11 * disclaimer in the documentation and/or other materials provided 12 * with the distribution. 3) Neither the name of the jcabi.com nor 13 * the names of its contributors may be used to endorse or promote 14 * products derived from this software without specific prior written 15 * permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT 19 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21 * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 28 * OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 package com.jcabi.github; 31 32 import com.google.common.base.Optional; 33 import com.jcabi.aspects.Immutable; 34 import com.jcabi.aspects.Loggable; 35 import java.io.IOException; 36 import java.util.HashMap; 37 import java.util.Map; 38 import javax.json.Json; 39 import javax.json.JsonObject; 40 import javax.json.JsonObjectBuilder; 41 import javax.json.JsonValue; 42 import lombok.EqualsAndHashCode; 43 import lombok.ToString; 44 45 /** 46 * Github Repo API. 47 * 48 * @author Yegor Bugayenko (yegor256@gmail.com) 49 * @version $Id: 68f582e486584d6dd01444aeb8d5b0243430792c $ 50 * @since 0.5 51 * @see <a href="https://developer.github.com/v3/repos/">Repos API</a> 52 */ 53 @SuppressWarnings("PMD.TooManyMethods") 54 @Immutable 55 public interface Repos { 56 57 /** 58 * Get its owner. 59 * @return Github 60 */ 61 Github github(); 62 //byte[] 63 64 /** 65 * Create repository. 66 * @param settings Settings to use for creating the new repository 67 * @return Repository 68 * @throws IOException If there is any I/O problem 69 * @since 0.5 70 * @see <a href="https://developer.github.com/v3/repos/#create">Create Repository</a> 71 */ 72 Repo create(RepoCreate settings) 73 throws IOException; 74 75 /** 76 * Get repository by name. 77 * @param coords Repository name in "user/repo" format 78 * @return Repository 79 * @see <a href="https://developer.github.com/v3/repos/#get">Get Repository</a> 80 */ 81 Repo get(Coordinates coords); 82 83 /** 84 * Remove repository by name. 85 * 86 * <p>Note: Deleting a repository requires admin access. 87 * If OAuth is used, the delete_repo scope is required. 88 * 89 * @param coords Repository name in "user/repo" format 90 * @throws IOException If there is any I/O problem 91 * @see <a href="https://developer.github.com/v3/repos/#delete-a-repository">Delete a Repository</a> 92 */ 93 void remove(Coordinates coords) throws IOException; 94 95 /** 96 * Iterate all public repos, starting with the one you've seen already. 97 * @param identifier The integer ID of the last Repo that you’ve seen. 98 * @return Iterator of repo 99 * @see <a href="https://developer.github.com/v3/repos/#list-all-public-repositories">List all public repositories</a> 100 */ 101 Iterable<Repo> iterate( 102 String identifier 103 ); 104 105 /** 106 * Check if a repository exists on Github. 107 * @param coords Coordinates of the repo. 108 * @return True if it exists, false otherwise. 109 * @throws IOException If something goes wrong. 110 */ 111 boolean exists(final Coordinates coords) throws IOException; 112 113 /** 114 * Settings to use when creating a new GitHub repository. 115 * 116 * @author Chris Rebert (github@rebertia.com) 117 * @version $Id: 68f582e486584d6dd01444aeb8d5b0243430792c $ 118 * @since 0.24 119 * @see <a href="https://developer.github.com/v3/repos/#create">Create Repo API</a> 120 * @todo #1095:30m Add the ability to set the other parameters of 121 * the repo creation API (has_issues, has_wiki, has_downloads, 122 * team_id, gitignore_template, license_template). 123 */ 124 @SuppressWarnings("PMD.TooManyMethods") 125 @ToString 126 @Loggable(Loggable.DEBUG) 127 @EqualsAndHashCode(of = {"nam", "priv", "descr", "home", "init"}) 128 final class RepoCreate implements JsonReadable { 129 /** 130 * Name of the new repo. 131 */ 132 private final transient String nam; 133 /** 134 * Privateness of the new repo. 135 */ 136 private final transient boolean priv; 137 /** 138 * Description of the new repo. 139 */ 140 private final transient String descr; 141 /** 142 * Homepage of the new repo. 143 */ 144 private final transient String home; 145 /** 146 * Auto-init the new repo? 147 */ 148 private final transient Optional<Boolean> init; 149 /** 150 * Organization where the created repo belongs. 151 */ 152 private final transient String organization; 153 154 /** 155 * Other parameters which repo might have. 156 */ 157 private final transient Map<String, JsonValue> other; 158 159 /** 160 * Public ctor. 161 * @param nme Name of the new repository. Cannot be empty. 162 * @param prvt Will the new repo be private? 163 * If not, then it will be public. 164 */ 165 public RepoCreate(final String nme, final boolean prvt) { 166 this(nme, prvt, "", "", Optional.<Boolean>absent(), ""); 167 } 168 169 /** 170 * Private ctor. 171 * @param nme Name of the new repo. Cannot be empty. 172 * @param prvt Will the new repo be private? 173 * If not, then it will be public. 174 * @param desc Description of the new repo 175 * @param page Homepage of the new repo 176 * @param auto Auto-init the new repo? 177 * @param org Organization to which this repo belongs. 178 * When empty or null, the repo is created under the 179 * authenticated user. 180 * @checkstyle ParameterNumberCheck (7 lines) 181 */ 182 private RepoCreate( 183 final String nme, 184 final boolean prvt, 185 final String desc, 186 final String page, 187 final Optional<Boolean> auto, 188 final String org 189 ) { 190 if (nme.isEmpty()) { 191 throw new IllegalArgumentException("Name cannot be empty!"); 192 } 193 this.nam = nme; 194 this.priv = prvt; 195 this.descr = desc; 196 this.home = page; 197 this.init = auto; 198 this.organization = org; 199 this.other = new HashMap<>(0); 200 } 201 202 /** 203 * Name of the new repo. 204 * @return Name 205 */ 206 public String name() { 207 return this.nam; 208 } 209 210 /** 211 * Will the new repo be private? If not, then it will be public. 212 * @return Is this repo private? 213 */ 214 public boolean isPrivate() { 215 return this.priv; 216 } 217 218 /** 219 * Description of the new repo. 220 * If it has no description, this is an empty string. 221 * @return Description 222 */ 223 public String description() { 224 return this.descr; 225 } 226 227 /** 228 * Homepage of the new repo. 229 * If it has no homepage, this is an empty string. 230 * @return Homepage 231 */ 232 public String homepage() { 233 return this.home; 234 } 235 236 /** 237 * Auto-init the new repo? 238 * If absent, the GitHub default will be used. 239 * @return Optional boolean 240 */ 241 public Optional<Boolean> autoInit() { 242 return this.init; 243 } 244 245 /** 246 * Name of the organization to which this repo belongs. 247 * @return String org name 248 */ 249 public String organization() { 250 return this.organization; 251 } 252 253 /** 254 * Returns a RepoCreate with the given name. 255 * The name cannot be empty. 256 * @param nme Name of the new repo 257 * @return RepoCreate 258 */ 259 public RepoCreate withName( 260 final String nme 261 ) { 262 return new RepoCreate( 263 nme, 264 this.priv, 265 this.descr, 266 this.home, 267 this.init, 268 this.organization 269 ); 270 } 271 272 /** 273 * Returns a RepoCreate with the given privacy. 274 * @param privacy Privateness of the new repo 275 * @return RepoCreate 276 */ 277 public RepoCreate withPrivacy(final boolean privacy) { 278 return new RepoCreate( 279 this.nam, 280 privacy, 281 this.descr, 282 this.home, 283 this.init, 284 this.organization 285 ); 286 } 287 288 /** 289 * Returns a RepoCreate with the given description. 290 * @param desc Description 291 * @return RepoCreate 292 */ 293 public RepoCreate withDescription( 294 final String desc 295 ) { 296 return new RepoCreate( 297 this.nam, 298 this.priv, 299 desc, 300 this.home, 301 this.init, 302 this.organization 303 ); 304 } 305 306 /** 307 * Returns a RepoCreate with the given homepage. 308 * @param page Homepage URL 309 * @return RepoCreate 310 */ 311 public RepoCreate withHomepage( 312 final String page 313 ) { 314 return new RepoCreate( 315 this.nam, 316 this.priv, 317 this.descr, 318 page, 319 this.init, 320 this.organization 321 ); 322 } 323 324 /** 325 * Returns a RepoCreate with the given auto-init enabledness. 326 * @param auto Auto-init the new repo? 327 * @return RepoCreate 328 */ 329 public RepoCreate withAutoInit(final Optional<Boolean> auto) { 330 return new RepoCreate( 331 this.nam, 332 this.priv, 333 this.descr, 334 this.home, 335 auto, 336 this.organization 337 ); 338 } 339 340 /** 341 * Returns a RepoCreate with the given auto-init enabledness. 342 * @param auto Auto-init the new repo? 343 * @return RepoCreate 344 */ 345 public RepoCreate withAutoInit(final boolean auto) { 346 return new RepoCreate( 347 this.nam, 348 this.priv, 349 this.descr, 350 this.home, 351 Optional.of(auto), 352 this.organization 353 ); 354 } 355 356 /** 357 * Returns a RepoCreate with the given organization. 358 * @param org Organization to which this repo belongs. 359 * @return RepoCreate 360 */ 361 public RepoCreate withOrganization(final String org) { 362 return new RepoCreate( 363 this.nam, 364 this.priv, 365 this.descr, 366 this.home, 367 this.init, 368 org 369 ); 370 } 371 372 /** 373 * Returns a RepoCreate with the given json fields. 374 * @param key Json key 375 * @param value Json value 376 * @return The same RepoCreate. 377 * @todo #1660:30min Make 'with' method immutable. 378 * Currently, the 'with' method mutates the 'other' field. 379 * This is not ideal, as it makes the class mutable. 380 * Make the 'with' method immutable and return a new 381 * RepoCreate object with the new field. 382 */ 383 public RepoCreate with(final String key, final JsonValue value) { 384 this.other.put(key, value); 385 return this; 386 } 387 388 @Override 389 public JsonObject json() { 390 JsonObjectBuilder builder = Json.createObjectBuilder() 391 .add("name", this.nam) 392 .add("description", this.descr) 393 .add("homepage", this.home) 394 .add("private", this.priv); 395 if (this.init.isPresent()) { 396 builder = builder.add("auto_init", this.init.get()); 397 } 398 for (final Map.Entry<String, JsonValue> entry 399 : this.other.entrySet()) { 400 builder.add(entry.getKey(), entry.getValue()); 401 } 402 return builder.build(); 403 } 404 } 405 }