Explorando la GitHub API para Java

Explorando la GitHub API para Java



1. Introducción

En este artículo, vamos a tener un vistazo a la GitHub API For Java que provee una representación orientada a objetos de la API de GitHub, permitiéndonos interactuar fácilmente con ella desde nuestras aplicaciones Java. Utilizaremos esta biblioteca para realizar diversas operaciones, incluyendo la autenticación, la obtención de información sobre usuarios y repositorios, y la manipulación de estos.



2. Dependencias

Para usar la biblioteca de GitHub API para Java, necesitamos incluir la última versión en nuestro proyecto. Actualmente, la versión más reciente es 1.327.

Si estamos usando Maven, podemos incluir esta dependencia en nuestro archivo pom.xml:

<dependency>
    <groupId>org.kohsuke</groupId>
    <artifactId>github-api</artifactId>
    <version>1.327</version>
</dependency>

Una vez que tengamos esto configurado, estaremos listos para comenzar a usarlo en nuestra aplicación.



3. Creación del Cliente

Para utilizar la biblioteca, primero necesitamos crear una instancia de cliente de GitHub. Este actuará como el punto de entrada principal para interactuar con la API de GitHub.

La forma más sencilla de crear esta instancia es conectándose de manera anónima:

GitHub gitHub = GitHub.connectAnonymously();

Esto nos permite acceder a la API sin credenciales de autenticación, aunque nuestra capacidad será limitada a aquellas funciones que puedan trabajar de esta forma.

Alternativamente, podemos conectarnos con credenciales:

GitHub gitHub = GitHub.connect();

Al hacer esto, la biblioteca intentará determinar las credenciales a usar de diversas maneras:

  • Si la propiedad de entorno GITHUB_OAUTH está establecida, se usará como un token de acceso personal.
  • Si la propiedad de entorno GITHUB_JWT está configurada, se utilizará como token JWT.
  • Si ambos, GITHUB_LOGIN y GITHUB_PASSWORD están configurados, se usarán directamente como credenciales.
  • Si ninguno de estos valores están disponibles, la biblioteca intentará usar el archivo de propiedades .github en el directorio de inicio del usuario para proporcionar las propiedades equivalentes.

Si ninguno de estos valores está disponible, la creación del cliente fallará.

También podemos optar por crear el cliente proporcionando las credenciales manualmente:

GitHub github = new GitHubBuilder().withOAuthToken("my_personal_token").build();
GitHub github = new GitHubBuilder().withJwtToken("my_jwt_token").build();
GitHub github = new GitHubBuilder().withPassword("my_user", "my_password").build();

El uso de credenciales manuales nos da la flexibilidad de cargar las credenciales desde cualquier lugar. Cabe destacar que la biblioteca utiliza estas credenciales solo cuando es necesario, lo que significa que si las credenciales proporcionadas son inválidas, solo nos daremos cuenta cuando intentemos interactuar con la API de una manera que requiera autenticación.



4. Consultando a uno mismo y otros usuarios

Una vez que hemos creado un cliente, podemos comenzar a interactuar con la API de GitHub.

Si tenemos un cliente correctamente autenticado, podemos usarlo para consultar la información del usuario con el que estamos autenticados, conocido como Myself.

GHMyself myself = gitHub.getMyself();

Luego podemos usar este objeto para consultar al usuario actual:

assertEquals("someone", myself.getLogin());
assertEquals("someone@example.com", myself.getEmail());
assertEquals(50, myself.getFollows().size());

También podemos consultar los detalles de otros usuarios:

GHUser user = gitHub.getUser("eugenp");
assertEquals("eugenp", user.getLogin());
assertEquals(2, user.getFollows().size());

Este código devuelve un GHUser, que es la superclase de GHMyself. Como resultado, hay ciertas funciones que podemos ejecutar con el objeto GHMyself que no son aplicables a otros usuarios. Estas funciones incluyen la gestión de claves públicas, la administración de direcciones de correo electrónico y la gestión de membresías de organizaciones.



5. Repositorios

También podemos trabajar con repositorios, así como con usuarios. Esto incluye la capacidad de consultar la lista de repositorios de un usuario, acceder al contenido de un repositorio o incluso hacer cambios en él.

Recuerda que todos los repositorios en GitHub son propiedad de exactamente un usuario, por lo que necesitamos conocer el nombre de usuario así como el nombre del repositorio para poder acceder a ellos correctamente.



5.1. Listando Repositorios

Si tenemos un objeto GHUser, ya sea GHMyself o GHUser, podemos usarlo para obtener los repositorios que este usuario posee. Esto se logra utilizando listRepositories():

PagedIterable<GHRepository> repositories = user.listRepositories();

El resultado es un PagedIterable, ya que podría haber un número muy grande de repositorios. De forma predeterminada, esto funciona con un tamaño de página de 30, pero podemos especificar esto al listar los repositorios si es necesario:

PagedIterable<GHRepository> repositories = user.listRepositories(50);

Esto nos da varias formas de acceder a los repositorios. Podemos convertirlo a un Array, List o Set que contenga la colección completa:

Array<GHRepository> repositoriesArray = repositories.toArray();
List<GHRepository> repositoriesList = repositories.toList();
Set<GHRepository> repositoriesSet = repositories.toSet();

Sin embargo, esto retornará todos los repositorios de inmediato, lo cual puede ser costoso si hay un número muy grande. Por ejemplo, el usuario de GitHub Microsoft actualmente tiene 6,688 repositorios. A 30 repositorios por página, esto requeriría 223 llamadas a la API para obtener la lista completa.

Alternativamente, podemos obtener un iterador de los repositorios, que realizará llamadas a la API bajo demanda, permitiéndonos acceder a la colección de manera más eficiente:

Iterator<GHRepository> repositoriesSet = repositories.toIterator();

De manera aún más simple, el PagedIterable es en sí mismo un Iterable y puede utilizarse directamente donde sea aplicable, por ejemplo, en un bucle mejorado:

Set<String> names = new HashSet<>();
for (GHRepository ghRepository : user.listRepositories()) {
    names.add(ghRepository.getName());
}

Esto itera sobre cada repositorio devuelto e extrae sus nombres. Debido a que estamos usando PagedIterable, esto actuará como un Iterable normal pero hará llamadas a la API solo cuando sea necesario.



5.2. Accediendo directamente a repositorios

Además de listar repositorios, podemos acceder a ellos directamente por nombre:

GHRepository repository = user.getRepository("tutorials");

Alternativamente, podemos acceder al repositorio directamente desde nuestro cliente. En este caso, necesitamos el nombre completo que combina el nombre de usuario y el nombre del repositorio:

GHRepository repository = gitHub.getRepository("eugenp/tutorials");

Esto nos da el mismo objeto GHRepository que si hubiéramos navegado a través del objeto GHUser.



5.3. Trabajando Con Repositorios

Una vez que tenemos un objeto GHRepository, podemos comenzar a interactuar con él directamente. Podemos recuperar detalles del repositorio, como su nombre, propietario, fecha de creación y más.

String name = repository.getName();
String fullName = repository.getFullName();
GHUser owner = repository.getOwner();
Date created = repository.getCreatedAt();

Además, podemos consultar el contenido del repositorio. Esto se puede hacer tratándolo como un repositorio Git, lo que nos permite acceder a ramas, etiquetas, commits, etc.

String defaultBranch = repository.getDefaultBranch();
GHBranch branch = repository.getBranch(defaultBranch);
String branchHash = branch.getSHA1();

GHCommit commit = repository.getCommit(branchHash);
System.out.println(commit.getCommitShortInfo().getMessage());

Por otro lado, si conocemos los nombres completos, podemos acceder al contenido completo de los archivos:

String defaultBranch = repository.getDefaultBranch();
GHContent file = repository.getFileContent("pom.xml", defaultBranch);

String fileContents = IOUtils.toString(file.read(), Charsets.UTF_8);

Si existen, también podemos acceder a ciertos archivos especiales, como el readme y la licencia:

GHContent readme = repository.getReadme();
GHContent license = repository.getLicenseContent();

Estos funcionan exactamente igual que acceder al archivo directamente, pero sin necesidad de conocer el nombre del archivo.



5.4. Manipulando Repositorios

Además de leer el contenido del repositorio, también podemos hacer cambios en los mismos. Esto incluye actualizar la configuración del repositorio, lo que nos permite cambiar descripciones, páginas de inicio, visibilidad, etc.

repository.setDescription("Una nueva descripción");
repository.setVisibility(GHRepository.Visibility.PRIVATE);

También podemos crear forks de otros repositorios en nuestra propia cuenta:

repository.createFork().name("my_fork").create();

Podemos crear ramas, etiquetas, solicitudes de extracción y otras cosas:

repository.createRef("new-branch", oldBranch.getSHA1());
repository.createTag("new-tag", "Esto es una etiqueta", branch.getSHA1(), "commit");
repository.createPullRequest("new-pr", "from-branch", "to-branch", "Descripción de la solicitud de extracción");

Incluso es posible crear commits completos si lo necesitamos, aunque esto es más complicado.



6. Conclusión

En este artículo, hemos realizado una breve mirada a la GitHub API For Java. Aprendimos a crear un cliente, interactuar con usuarios y repositorios, y hasta manipular repositorios. Hay muchas más operaciones que se pueden realizar utilizando esta biblioteca. La próxima vez que necesites trabajar con la API de GitHub, ¿por qué no probarla?

Consejos Prácticos:

  • Manejo de Errores: Asegúrate de implementar un manejo de errores robusto para manejar cualquier excepción que pueda surgir durante la interacción con la API.
  • Límites de Tasa: Ten en cuenta los límites de tasa de la API de GitHub, especialmente si planeas hacer muchas llamadas. Considera implementar un mecanismo para manejar el rate limiting.
  • Uso Eficiente de Recursos: Usa PagedIterable y iteradores para reducir la carga en la API, esto te ayudará a manejar colecciones grandes sin realizar todas las llamadas al mismo tiempo.
  • Revisar la Documentación: Asegúrate de consultar la documentación de la API para comprender completamente las opciones y restricciones de cada endpoint que utilices.

Espero que encuentres útil esta guía y que te ayude a mejorar tus proyectos de programación en Java utilizando la API de GitHub.