Desarrollando una "version tag" basada en git y renderizada a través de un componente de Blade - Parte II > Blog | Josep Salvà - Desarrollo Web

La palabra de Wifft

Tal y como se menciona en la publicación anterior, en esta segunda parte vamos a ver como obtener el versionNumber y el buildNumber de nuestra "version tag".

Empecemos por recordar como estaba la propiedad $versionNumber asignada en el constructor.

$this->versionNumber = $this->getVersionNumber();

Vemos que se invoca al método getVersionNumber(), definido en el propio objeto.

/**
 * Gets the the "version number" (most recent tag name, if any).
 */
private function getVersionNumber(): string
{
    /** @var string */
    $tagsPath = $this->gitPath . '/refs/tags';

    /** @var array */
    $files = glob($tagsPath . '/*');
    usort($files, fn (string $a, string $b) : bool => filemtime($a) < filemtime($b));
    rsort($files);

    /** @var string */
    $tagName = self::getLastPathItem($files[0]);

    return $tagName;
}

En primer lugar, definimos un string cuyo valor es la ruta del directorio .git/refs/tags, que contiene todas las "tags" del repo. Estas tags se usan comunmente para definir números de versión, como es nuestro caso.

$tagsPath = $this->gitPath . '/refs/tags';

Una vez definida dicha variable, definimos otra llamada $files haciendo uso de la función nativa de PHP glob().

$files = glob($tagsPath . '/*');

La función glob() devuelve un array con todos los elementos de un directorio coincidentes con el patrón proporcionado.

Acto seguido invocamos a la función nativa de PHP usort() que en nuestro caso ordena los elementos del array en base a la fecha de creación de los ficheros que representan, comprobándola mediante la función nativa de PHP filemtime().

usort($files, fn (string $a, string $b): bool => filemtime($a) < filemtime($b));

Finalmente, ordenamos el array a la inversa mediante la función nativa de PHP rsort().

rsort($files);

Nota: Tanto la función usort() como la función rsort() reciben el array a modificar por referencia (&), es por ello que no reasignamos la variable y simplemente nos limitamos a proporcionarla como parámetro de estas.

Finalmentes, declaramos la variable $tagName que invoca al método estático getLastPathItem(), definido en el propio objeto, proporcionandole como parámetro el primer elemento del array (archivo más reciente), para posteriormente retornar el resultado.

$tagName = self::getLastPathItem($files[0]);

return $tagName;

Dicho método (getLastPathItem()) es el encargado de filtrar dicho string mediante una expresión regular, obteniendo el último eslabón / elemento, basicamene, el que no termina en /. Para ello hacemos uso de las funciones nativas de PHP preg_replace() y trim() (para eliminar posibles espacios en blanco al principio y al final).

/**
 * Gets last item from given path.
 */
private static function getLastPathItem(string $path): string
{
     return rtrim(preg_replace("/(.*?\/){2}/", '', $path));
}

Ahora procedemos a obtener el buildNumber. Recordemos como estaba definida dicha propiedad en el constructor:

$this->buildNumber = $this->getBuildNumber();

Vemos que se invoca al método getBuildNumber(), definido en el propio objeto.

/**
 * Gets the the "build number" (total commits count).
 */
private function getBuildNumber(): int
{
    /** @var array */
    $file = file($this->gitPath . '/logs/' . self::HEAD_FILENAME, FILE_SKIP_EMPTY_LINES);

    /** @var int */
    $pos = 0;

    /** @var string $line */
    foreach ($file as $line) {
        $pos++;

        if (str_contains($line, $this->getHash())) {
            preg_match("/[0-9]{10}/", $line, $m);

            $this->setBuildDate((int) $m[0]);

            break;
        }
    }

    return $pos;
}

Lo que realiza dicha función es transformar el fichero de log en un array (cada línea es un elemento). Para ello, utilizamos la función nativa de PHP file() con la correspondiente flag FILE_SKIP_EMPTY_LINES y así ignorar las líneas vacías de manera deliberada.

$file = file($this->gitPath . '/logs/' . self::HEAD_FILENAME, FILE_SKIP_EMPTY_LINES);

Acto seguido, declaramos la variable $pos cuyo valor será 0. Dicha variable contendrá la posición (línea) en la que nos encontramos. En base a esa línea calcularemos el número de compilación.

Ej: la linea 550 equivale al commit número 550 del historico de la rama activa, desde el inicio del repo. Por tanto, si dicha línea coincide con el último commit de la rama actual, significa que nuestro buildNumber es el 550.

Entonces, leemos el array que contiene cada línea mediante un bucle e incrementamos el valor de la variable $pos en 1. Si la línea actual coincide con el hash del commit actual, identificamos la fecha del commit mediante la siguiente expresión regular /[0-9]{10}/ almacenándola en una variable $m (invocada por referencia &) y se la proporcionamos al método setBuildDate(int $timestamp) y detenemos la ejecución del bucle mediante la instrucción break.

foreach ($file as $line) {
    $pos++;

    if (str_contains($line, $this->getHash())) {
        preg_match("/[0-9]{10}/", $line, $m);

        $this->setBuildDate((int) $m[0]);

        break;
    }
}

Finalmente retornamos el valor de $pos.

return $pos;

En el siguiente post veremos como obtener el hash del commit actual gracias al cual obtenemos el buildNumber, y su fecha (que ya obtenemos y asignamos mediante el el método setBuildDate(int $timestamp) anteriormente citado.