Este capítulo se centrará en explicar las características que incorpora ghedsh tras la etapa de desarrollo tratada en el capítulo anterior.

Se hará una distinción entre comandos del núcleo y comandos incorporados (built-in commands). Los comandos del núcleo, son aquellos que no trabajan con los datos de GitHub del usuario pero que, sin embargo, son esenciales desde el punto de vista de la usabilidad y experiencia de usuario con el CLI.

Además, los comandos incorporados sí trabajan con los datos de GitHub del usuario identificado. Permiten realizar diversas tareas, priorizando la rapidez en la ejecución de las mismas y la facilidad de uso de la herramienta.

Autenticación con credenciales de GitHub

El contenido de esta sección pretende explicar el proceso de autenticación que debe seguir el usuario al usar ghedsh por primera vez.

Dicho proceso es necesario, puesto que se trabajan con los datos que dispone el usuario en GitHub. Además, la API REST v3 requiere, para ciertas consultas (en especial, modificaciones como crear repositorios, equipos y administrar la configuración), verificar la identidad del usuario. Si no fuera así, se podrían llevar a cabo comportamientos indeseados.

En ghedsh, se realiza la autenticación con OAuth access token, que consiste, en una definición muy simplificada, en una cadena de caracteres alfanuméricos que actúa como una contraseña. No obstante, en este caso de uso es mucho más potente y segura. Las principales ventajas son:

Para sintetizar este apartado, el usuario que utilice por primera vez ghedsh, debe verificar su identidad mediante sus credenciales (nombre de usuario y contraseña) de GitHub y se generará de forma automática un token de acceso con los permisos necesarios para usar la herramienta.

Ejemplo de autenticación al usar ghedsh por primera vez.
Ejemplo de autenticación al usar ghedsh por primera vez.

Comandos del núcleo de ghedsh

Como se ha indicado en la introducción de este tercer capítulo, se han separado, por un lado, los comandos del núcleo de ghedsh y, por otro, los comandos característicos de ghedsh.

En esta sección, se explicará este primer grupo de comandos, encargado de tareas relacionadas con el sistema operativo y, lo más importante, hacer que la herramienta sea agradable de manejar para el usuario. Además, se revisarán aspectos importantes de su implementación.

bash (comando ghedsh)

Permite interpretar un comando en la terminal del sistema operativo, sin salir de ghedsh.

Sintaxis: bash <comando_terminal> . En la figura [fig:bash-example], se muestra un ejemplo de uso.

Ejemplo de uso del comando bash.
Ejemplo de uso del comando bash.

Change directory: cd

Análogamente al comando cd de la Bash, que permite cambiar nuestro directorio actual de trabajo, en ghedsh también existe este comando. No obstante, aunque la idea es similar, existen diferencias a la hora de usarlo.

En nuestro sistema operativo (tipo Unix), cuando realizamos la operación cd, sólo podemos movernos entre directorios (dependiendo de los permisos). Dado que en ghedsh no existen directorios como tal, hablaremos de contextos. Los contextos en esta herramienta hacen referencia a nivel de usuario, nivel de organización, nivel de repositorio, etcétera.

Imaginemos por un momento que nuestro usuario se llama ejemplo, disponemos de un repositorio que se llama ejemplo y una organización denominada ejemplo. Ésto es totalmente válido, puesto que lo que no permite GitHub es que dos usuarios se llamen igual, que el usuario tenga dos repositorios con el mismo nombre o dos organizaciones bajo el mismo nombre. Entonces, debemos proporcionar alguna manera de desambiguar a qué contexto nos queremos cambiar.

En ghedsh se ha optado por el siguiente planteamiento: para realizar la operación de cd, es necesario especificar el tipo de contexto (nivel) al que queremos cambiarnos, así, aunque el usuario se encuentre en el caso anteriormente comentado, ghedsh es capaz de saber a qué contexto debe cambiar. La sintaxis del comando sería cd <tipo> <nombre>, donde nombre es la cadena de texto que identifica al tipo.

Los tipos de contexto (pueden ser ampliables) que actualmente se soportan en ghedsh son:

Además, si deseamos volver al contexto anterior, haremos de la misma manera que en sistemas operativos tipo Unix: cd .. . Hay que tener en cuenta que, actualmete, no se puede realizar la operación de volver al contexto anterior y cambiar a otro de manera simultánea (como en Unix cd ../another/dir ), es necesario hacerlo por separado.

Detalles de implementación

Puesto que se trata de uno de los comandos más importantes de ghedsh, se comentarán los aspectos destacados de la implementación del mismo, incluyendo las dificultades encontradas.

Internamente, el comando cd contiene una pila (stack) en la que se almacenan todos los contextos previos. La estructura de un contexto se muestra en el siguiente fragmento de código:

  config = {
    'User' => client.login.to_s,
    'user_url' => client.web_endpoint.to_s << client.login.to_s,
    'Org' => nil,
    'org_url' => nil,
    'Repo' => nil,
    'repo_url' => nil,
    'Team' => nil,
    'team_url' => nil
  }

En esencia, change directory irá variando estos parámetros para conocer a qué nivel se encuentra el usuario (User siempre tendrá un valor asignado porque representa el usuario autenticado). Por ejemplo, para referirnos a un repositorio de una organización en la que el usuario es miembro, tendríamos:

    config = {
    'User' => client.login.to_s,
    'user_url' => client.web_endpoint.to_s << client.login.to_s,
    'Org' => "EXAMPLE-ORG",
    'org_url' => nil,
    'Repo' => "repository-within-example-org",
    'repo_url' => nil,
    'Team' => nil,
    'team_url' => nil
  }

En el caso de un repositorio de usuario, User tendría valor asignado y Repo también tendría valor asignado. A diferencia con el caso anterior, Org sería nulo ya que nos referimos a un repositorio a nivel de usuario.

Una de las dificultades en la implementación de este comando, fue que, antes de reasignar la estructura de datos que respresenta los contextos, era necesario almacenar el contexto actual para poder volver a éste más tarde.

Ruby proporciona dos métodos para copiar/clonar objetos: dup y clone. No obstante, realizan una copia superficial del objeto, es decir, crearán un nuevo identificador de objeto pero el contenido del mismo referenciará al de la entidad original.

Para solucionarlo, se utilizó el módulo Marshal de Ruby, que sí realiza una copia profunda del objeto.

Comandos incorporados en ghedsh

A lo largo de esta sección, se explicarán individualmente los comandos característicos de ghedsh. Los comandos característicos o incorporados por ghedsh son aquellos que trabajan con los datos de GitHub del usuario de la herramienta. Colaboran estrechamente con la GitHub API REST v3 (véase, para más detalle, la documentación oficial de Octokit). Se explicará la sintaxis para cada uno de ellos y se proporcionará ejemplos de uso.

Como convenio, los parámetros con el formato <parameter>, son obligatorios. Los que tengan el formato [parameter], son opcionales.

Por otro lado, las expresiones regulares admiten las opciones establecidas por Ruby.

clear

Realiza la misma tarea que el comando clear en Bash. Borra la pantalla si es posible y sitúa el cursor en la parte superior izquierda de la pantalla (ignora cualquier parámetro adicional).

Sintaxis: clear .

clone

Clona repositorios y, si ya existe en el directorio local, realizará git pull --all. Recibe como parámetro obligatorio el nombre del repositorio que se desea clonar o una expresión regular, que permitirá clonar todos los repositorios que casen con ella. Opcionalmente, es posible especificar un directorio dentro de $HOME de la máquina local. En caso de no exisir, se creará. Por defecto, se clonarán en el directorio actual de la máquina local.

Sintaxis: clone <nombre_repo/Regexp/>| [ruta_en_home] .

Se puede ejecutar en:

En la figura [fig:clone-example] y [fig:clone-example-org] se muestran ejemplos de uso.

Ejemplo de clonar un repositorio de usuario.
Ejemplo de clonar un repositorio de usuario.
Ejemplo de clonar un repositorio de organización.
Ejemplo de clonar un repositorio de organización.

commits

Muestra los commits (SHA, fecha, autor y mensaje del commit) de la rama master, en caso de que no se le pase como parámetro una rama en concreto. Es necesario estar posicionado sobre un repositorio de cualquiera de los siguientes contextos: organización o usuario.

Sintaxis: commits [rama_repositorio] .

Mostrar commits en un repositorio de usuario.
Mostrar commits en un repositorio de usuario.
Mostrar commits de la rama de un repositorio de organización.
Mostrar commits de la rama de un repositorio de organización.

exit

Temina la ejecución de ghedsh, guardando el contexto actual. Es decir, si el usuario se encontraba dentro de una organización, la próxima vez que entre en ghedsh estará dentro de la organización.

Sintaxis: exit .

files

Muestra el contenido y el tipo de contenido (fichero o directorio) de un repositorio. Debe estar posicionado dentro de un repositorio de usuario o repositorio de organización. Si no se le proporciona ningún parámetro, muestra el contenido de la raíz del repositorio. Si se le especifica un subdirectorio, se mostrará su contenido.

Sintaxis: files [subdirectorio] .

Listar contenido del repositorio.
Listar contenido del repositorio.
Listar contenido de un subdirectorio.
Listar contenido de un subdirectorio.

invite_member

Añade nuevos miembros a una organización. Recibe como parámetros el/los nombres de usuario de GitHub, separados por comas o por espacios.

Sólo puede ejecutarse en el contexto de una organización.

Sintaxis: invite_member <user1, user2, user3, ..., n> .

Añadir miembros específicos.
Añadir miembros específicos.

invite_member_from_file

Añade nuevos miembros a una organización, especificando su nombre de usuario en GitHub. Recibe como único parámetro un fichero (ver plantilla ) existente en $HOME de la máquina local.

El comando se ejecuta, exclusivamente, dentro del contexto de una organización.

Sintaxis: invite_member_from_file <ruta_home_fichero> .

Añadir miembros mediante fichero.
Añadir miembros mediante fichero.

invite_outside_collaborators

Invita a ser miembros de la organización a los colaboradores externos de la misma. Si no se especifica ningún parámetro, invita a todos los colaboradores externos. En caso de que reciba un parámetro, tendrá que ser un fichero (ver plantilla ) situado en $HOME de la máquina local.

Se ejecuta, exclusivamente, cuando el usuario de ghedsh está situado en el contexto de una organización.

Sintaxis: invite_outside_collaborators [ruta_home_fichero] .

Invitación a ser miembros desde fichero.
Invitación a ser miembros desde fichero.

issues

Abre el navegador por defecto, situando al usuario en la lista de incidencias (issues). Debe estar posicionado dentro de un repositorio de usuario o repositorio de organización.

Sintaxis: issues .

Ver incidencias de un repositorio.
Ver incidencias de un repositorio.
Listado de incidencias del repositorio en GitHub.
Listado de incidencias del repositorio en GitHub.

new_issue

Abre el navegador por defecto, situando al usuario en el formulario de creación de un issue. Para ejecutarlo, es necesario estar posicionado sobre un repositorio.

Sintaxis: new_issue .

Está disponible para:

Nuevo issue en repositorio de organización.
Nuevo issue en repositorio de organización.
Formulario de creación de incidencias (issues).
Formulario de creación de incidencias (issues).

new_repo

Crea un nuevo repositorio. La herramienta muestra al usuario dos opciones para crearlo (menú):

Sintaxis: new_repo <nombre_repositorio>. Disponible para:

En la figura [fig:create-repo], vemos el menú de creación del repositorio.

Menú para la creación de un repositorio.
Menú para la creación de un repositorio.
Creación de un repositorio de usuario con opciones específicas.
Creación de un repositorio de usuario con opciones específicas.

new_team

Crea un nuevo equipo dentro de la organización en la que esté posicionado el usuario. Si el comando no recibe ningún parámetro, se abrirá la URL del formulario para crear el equipo en la web de GitHub. En caso de especificarle un parámetro, éste tiene que ser un fichero (ver plantilla ) que se encuentre en algún lugar de $HOME en la máquina local.

Una vez más, este comando sólo se puede ejecutar cuando el usuario está posicionado dentro de una organización en ghedsh.

Sintaxis: new_team [ruta_home_fichero] .

Formulario de creación de un equipo en GitHub.
Formulario de creación de un equipo en GitHub.
Creación de un equipo mediante fichero.
Creación de un equipo mediante fichero.

open

Abre el navegador por defecto y muestra información de GitHub según el contexto:

Sintaxis general: open .

orgs

Muestra las organizaciones a las que pertenece el usuario autenticado en ghedsh. Si el comando no recibe ningún parámetro, se mostrarán todas las organizaciones. En caso de proporcionarle un parámetro, debe ser una expresión regular y mostrará los resultados que casen.

Sólo está disponible en contexto de usuario.

Sintaxis: orgs [/Regexp/] .

Mostrar todas las organizaciones del usuario autenticado en ghedsh.
Mostrar todas las organizaciones del usuario autenticado en ghedsh.
Filtrar organizaciones mediante expresión regular.
Filtrar organizaciones mediante expresión regular.

people

Muestra los nombres de los usuarios que componen una organización. Esto incluye miembros y colaboradores externos (si el usuario autenticado en ghedsh tiene permisos de administrador en la organización). Si no se le proporciona ningún parámetro, lista todos. En caso de utilizar una expresión regular, se mostrarán los resultados que hayan casado con ella.

Este comando se usa, exclusivamente, cuando el usuario está posicionado dentro del contexto de una organización.

Sintaxis: people [/Regexp/] .

Mostrar los miembros de una organización.
Mostrar los miembros de una organización.
Mostrar mediante expresión regular los miembros de una organización.
Mostrar mediante expresión regular los miembros de una organización.

repos

Muestra los repositorios según el contexto. Si no se le especifica nungún parámetro, mostrará todos los repositorios. Si se le proporciona una expresión regular, mostrará los nombres de los repositorios que hayan casado.

Sintaxis: repos[/Regexp/].

rm_repo

Elimina el repositorio especificado. Se puede realizar tanto a nivel de usuario como a nivel de organización.

Sintaxis: rm_repo <nombre_repositorio> .

Eliminación de un repositorio.
Eliminación de un repositorio.

rm_team

Elimina un equipo. No recibe ningún parámetro. Se abre el navegador por defecto y el usuario borrará el o los equipos que desee de la lista proporcionada. Se ejecuta sólo en contexto de organización.

Sintaxis: rm_team .

teams

Muestra los equipos existentes en una organización. Si no se le especifica ningún parámetro, listará todos los equipos. Si se le proporciona una expresión regular, mostrará los resultados que casen con ella. Se ejecuta, exclusivamente, en el contexto de una organización.

Sintaxis: teams [/Regexp/] .

Listar los equipos de una organización.
Listar los equipos de una organización.
Listar mediante expresión regular los equipos de una organización.
Listar mediante expresión regular los equipos de una organización.

Comandos que dan soporte al proceso de evaluación

Los comandos que se explicarán en esta sección reflejan uno de los principales objetivos de ghedsh: aportar funcionalidades específicas que usen las metodologías de GitHub Education, facilitando al profesorado la gestión de repositorios del alumnado así como la ejecución de scripts sobre los mismos.

En este conjunto de comandos tenemos: new_eval, foreach y foreach_try.

new_eval

Permite crear un repositorio de evaluación. Recibe como parámetros el nombre del repositorio de evaluación y una expresión regular que añade como subdirectorios los repositorios que lo conforman. En ghedsh, un repositorio de evaluación consiste en hacer uso de los submódulos de git, de manera que se crea un repositorio raíz que contiene como submódulos todos los proyectos que se van a evaluar. Los pasos que realiza son:

Dado que, para comprender todas las ventajas que ofrece este comando, es necesario conocer los submódulos de git (gitsubmodules), se explicará en qué consisten a continuación.

Esencialmente, un submódulo es un repositorio que se encuentra contenido dentro de otro repositorio. El submódulo tiene su propio histórico de commits y, el repositorio raíz que lo contiene, se denomina súper-proyecto o súper-repositorio.

Es probable que, mientras trabajamos en un proyecto, necesitemos usar otro proyecto dentro de él. Quizás se trate de una librería de terceros o una que desarrollamos nosotros mismos de forma separada dentro de un proyecto principal. En estos casos, surge un problema común: precisamos de ser capaces de tratar los dos proyectos por separado y, aún así, usar uno dentro del otro.

El control de versiones Git aborda ese problema usando submódulos. Los submódulos permiten mantener un repositorio como un subdirectorio de otro repositorio Git. Por lo tanto, permite clonar otro repositorio en nuestro proyecto, separando los commits de cada uno.

En ghedsh, el comando new_eval se encuentra disponible únicamente en el contexto de organización.

Sintaxis: new_eval <nombre_repo_evaluacion> </Regexp/> .

Ejemplo de creación de un repositorio de evaluación.
Ejemplo de creación de un repositorio de evaluación.
Estructura de un repositorio de evaluación en GitHub.
Estructura de un repositorio de evaluación en GitHub.

foreach

Ejecuta sobre cada submódulo el comando Bash especificado como parámetro. No se detiene ante posibles errores en el proceso. Internamente, ejecuta git submodule foreach .

Sintaxis: foreach <comando_bash> .

Para que el comando lleve a cabo su cometido, se necesita lo siguiente:

Como se indica en la documentación oficial de git submodule foreach , el comando que se le proporciona tiene acceso a las siguientes variables:

Por otro lado, como también indica la documentación, cuando existe un error en algún submódulo durante la ejecución del comando, se detiene y devuelve un código distinto de cero. No obstante, este comportamiento puede evitarse añadiendo || : al final del comando especificado como parámetro.

Hay que tener en cuenta que foreach en ghedsh, ya incorpora este comportamiento y no se detendrá ante errores.

Ejemplo de ghedsh foreach.
Ejemplo de ghedsh foreach.

foreach_try

Realiza la misma tarea que foreach(4.2) y requiere las mismas condiciones para su uso. A diferencia de éste, foreach_try detendrá su ejecución cuando se produzca un error en el proceso.

Caso de uso

Cabe destacar que el director de este Trabajo de Fin de Grado, Casiano Rodríguez León, ha hecho uso de la herramienta ghedsh en un entorno educativo real.

En concreto, se ha utilizado para facilitar tareas de gestión de repositorios y evaluación de prácticas en el curso de Procesadores de Lenguajes (año académico 2017-2018) a lo largo del mes de junio. Además, esto ha contribuido a mejorar aspectos de la herramienta, puesto que, en un entorno real, suelen aparecer nuevos casos de uso que han sido cubiertos satisfactoriamente.

Por otro lado, Casiano ha realizado diversos vídeo tutoriales (ver sección 6) en los que se profundiza en el manejo de comandos que dan soporte al proceso de evaluación.

Aprendiendo a evaluar usando Git, GitHub y GitHub Classroom

En esta sección se comentará una serie de recursos disponibles que contienen ejemplos e información de cómo Git, GitHub y GitHub Classroom ayudan en el proceso de evaluación. Además, se hará especial mención a los vídeo tutoriales realizados por Casiano Rodríguez León, en los que, mediante el uso de ghedsh, se gestiona mejor dicho proceso.

Se debe tener en cuenta que todavía se están incorporando cambios en ghedsh. Por lo tanto, es posible que el comportamiento de algunos comandos hayan cambiado respecto a los vídeos tutoriales que se indicarán a continuación. No obstante, la filosofía de uso sigue siendo la misma.

En cuanto a los tutoriales realizados por Casiano tenemos:

Por otro lado, también existen recursos de la propia plataforma GitHub y la comunidad GitHub Education: