Laboratorio 20

Activar GitHub Copilot usando Node.js

Este laboratorio es para ayudar a entender el proyecto Demo para gestionar laboratorios que evalúen la viabilidad de Copilot.

Fuente validada

Lab_20_NodeJS_Copilot.docx

Esta pagina fue reconstruida desde el documento del ZIP entregado como fuente principal.

Conformidad visual

Sin imagenes publicadas

El archivo fuente contiene 0 imagenes embebidas. Para garantizar conformidad, no se publican imagenes heredadas de otros materiales.

Criterio GH-300

Practica verificable

Ejecuta los comandos, captura evidencia propia y valida cada sugerencia de Copilot antes de aceptarla.

Alcance de publicacion: Solo se publica el contenido del laboratorio indicado por el archivo Lab_20_NodeJS_Copilot.docx. Las imagenes no se muestran porque el ZIP no incluye imagenes embebidas en este documento.

Certificación GH-300

Laboratorio 20

Activar GitHub Copilot usando Node.js

Autor: Carlos Crudo

linkedin.com/in/carloscrudo

Uso de GitHub Copilot integrado en un proyecto Node.js completo: generación de código, tests, documentación y optimización de aplicaciones JavaScript/TypeScript.

Temas que cubre este laboratorio:

Node.js + GitHub Copilot setup

Generación de funciones y módulos

Express.js endpoints con Copilot

Tests con Jest usando Copilot Chat

Copilot para refactoring JS/TS

npm scripts y automatización

Laboratorio 20: Activar GitHub Copilot usando Node.js

Lab 20 - Activa GitHub Copilot usando Nodejs

Objetivo:

Este laboratorio es para ayudar a entender el proyecto Demo para gestionar laboratorios que evalúen la viabilidad de Copilot.

Antes de ejecutar este laboratorio, instalemos primero los paquetes de software necesarios y configuremos el entorno.

Ejercicio 0: Instalar y configurar el entorno

Necesitas descargar e instalar los siguientes paquetes de software para configurar el entorno que ejecute este laboratorio.

  • a. Node.js
  • B. mocha

Abre el navegador de Edge.

En el campo URL del navegador, copia y pega el enlace para descargar los paquetes de software en la máquina virtual de tu laboratorio.

  • a. Node.js y MVN https://nodejs.org/dist/v20.16.0/node-v20.16.0-x64.msi
  • B. Mocha (no se requiere descarga)

Nota: Por defecto, los paquetes se guardarán en la carpeta de descargas.

  • a. Instalar Node.js y MVN

Ve a la carpeta Descargas (C:\Usuarios\Admin\Descargas) y haz doble clic node-v20.16.0-x64.msi.

En la ventana de "asistente de configuración de Node.js" haz clic en Siguiente.

Acepta el EULA y haz clic en Siguiente.

Mantén la carpeta de destino predeterminada y luego haz clic en Siguiente.

Haz clic en Añadir al CAMINO y luego en Siguiente.

En la ventana de Herramientas para Módulos nativos, selecciona la casilla y haz clic en Siguiente.

Haz clic en Instalar.

Nota: Si ves una ventana emergente de Control de Acceso de Usuario, por favor haz clic en Sí para continuar.

Haz clic en Terminar cuando termines.

Se abre la terminal del CMD. Pulsa cualquier tecla para continuar...

Nota: Puede que notes un retraso tras pulsar una tecla. Por favor, espere un tiempo para proceder con la instalación.

Haz clic en Sí para continuar en la ventana UAC.

Windows Powershell se abre mostrando los detalles de instalación.

Una vez completada la instalación, escribe Enter para salir de PowerShell.

  • b. Instalar mocha

Abre el símbolo de comandos

Primero ejecuta el siguiente comando.

Instalación de NPM --Global Mocha

A continuación, ejecuta el siguiente comando

Instalación de Axios de NPM

Ahora has terminado de instalar mocha. Cierra el terminal para continuar instalando otros paquetes.

Ejercicio 1: Introducción

Desde Visual Studio, abre nodeserver.js desde el nodo exercise files ->.

Tenemos que empezar a programar para el nodo... servidor JS que expondrá una llamada al método "get" que devolverá el valor de la clave pasada en la cadena de consulta. Usemos el Copilot para ayudarnos con esto.

Pulsa Ctrl+I y pega los comandos siguientes para que el Copilot genere el código y luego pulse Enviar.

*// write a nodejs server that will expose a method call "get" that will return the value of the key passed in the query string*

*// example: http://localhost:3000/get?key=hello*

*// if the key is not passed, return "key not passed"*

*// if the key is passed, return "hello" + key*

*// if the url has other methods, return "method not supported"*

*// when server is listening, log "server is listening on port 3000"*

El Copilot genera el código y lo muestra. Haz clic en Aceptar para aceptarlo.

Haz clic derecho en la carpeta del nodo y selecciona Abrir en Terminal Integrado.

Una vez que el terminal esté abierto, ejecuta el comando de abajo desde él.

mocha test.js

Deberías obtener un resultado como 1 Pasando, como en la captura de pantalla de abajo.

Esta es la prueba unitaria del método en el nodeserver.js y ha pasado.

Seguiremos añadiendo diferentes métodos al servidor usando el Copilot.

Ejercicio 2: Desarrollar nuevas funcionalidades

El ejercicio consiste en construir un servidor web usando Nodejs que atiende a las solicitudes de diversas funcionalidades.

Añadir la solicitud de funcionalidad DaysBetweenDates a la que el servidor debe asistir.

Pulsa Enter después de que termine la condición if - nombre de ruta == '/get'.

Nota: Consulta el refuerzo en rojo donde necesitas pulsar Enter

Pulsa Ctrl+I para abrir la función en línea de Copilot, introduce lo siguiente y haz clic en Enviar.

/DaysBetweenDates:

Calculate days between two dates

receive by query string 2 parameters date1 and date 2, and calculate the days between those two dates.

Reference Code:

if (req.url.startsWith('/DaysBetweenDates')) {

*//calculate days between two dates*

*//get dates from querystring*

var queryData = url.parse(req.url, true).query;

var date1 = queryData.date1;

var date2 = queryData.date2;

*//convert dates to milliseconds*

var date1_ms = Date.parse(date1);

var date2_ms = Date.parse(date2);

*//calculate difference in milliseconds*

var difference_ms = date2_ms - date1_ms;

*//convert to days and return*

res.end(Math.round(difference_ms / 86400000) + " days");

}

Copilot genera el código. Haz clic en Aceptar para aceptar el código. Ten en cuenta que el código generado es un bloque if de otro tipo donde en la solicitud es DíasEntreFechas.

Haz clic en Entrar después del bloque DíasEntreFechas.

Introduce el bloque de comentarios de abajo y pulsa Enter.

*/

  • * /Validatephonenumber:*
  • * Receive by querystring a parameter called phoneNumber*
  • * validate phoneNumber with proper Spanish format, for example 34666666666*
  • * if phoneNumber is valid return "valid"*
  • * if phoneNumber is not valid return "invalid"*
  • * */*

Reference Code:

else if (req.url.startsWith('/Validatephonenumber')) {

*//get phoneNumber var from querystring*

var queryData = url.parse(req.url, true).query;

var phoneNumber = queryData.phoneNumber;

*//validate phoneNumber with Spanish format*

var regex = /^(\+34|0034|34)?[ -]*(6|7)[ -]*([0-9][ -]*){8}$/;

*//if phoneNumber is valid return "valid"*

if (regex.test(phoneNumber)) {

res.end("valid");

}

*//if phoneNumber is not valid return "invalid"*

else {

res.end("invalid");

}

}

El Copiloto genera el código. Haz clic en Aceptar para aceptar el código.

Haz clic en Enter después del bloque Validatephonenumber para añadir el siguiente bloque de código.

Copia y pega el texto de abajo en el archivo js.

*/

*/ValidateSpanishDNI:*

*Receive by querystring a parameter called dni*

*calculate DNI letter*

*if DNI is valid return "valid"*

*if DNI is not valid return "invalid"*

/*

Reference Code:

else if (req.url.startsWith('/ValidateSpanishDNI')) {

var queryData = url.parse(req.url, true).query;

var dni = queryData.dni;

*// calculate DNI letter*

var dniLetter = dni.charAt(dni.length - 1);

var dniNumber = dni.substring(0, dni.length - 1);

var dniLetterCalc = "TRWAGMYFPDXBNJZSQVHLCKE".charAt(dniNumber % 23);

*//if DNI is valid return "valid"*

if (dniLetter == dniLetterCalc) {

res.end("valid");

}

*//if DNI is not valid return "invalid"*

else {

res.end("invalid");

}

}

Una vez pegado el contenido anterior, el Copilot genera el código que se muestra justo debajo del comentario. Haz clic en Aceptar para aceptar el código.

Abre el chat de Copilot desde el panel de navegación izquierdo.

Pega el contenido de abajo en el chat y haz clic en el botón Enviar.

/ReturnColorCode:

Receive by querystring a parameter called color

read colors.json file and return the rgba field

get color var from querystring

iterate for each color in colors.json to find the color

return the code.hex field

Reference code:

else if (req.url.startsWith('/ReturnColorCode')) {

*//read colors.json file and return the rgba field*

var colors = fs.readFileSync('colors.json', 'utf-8');

var colorsObj = JSON.parse(colors);

*//get color var from querystring*

var queryData = url.parse(req.url, true).query;

var color = queryData.color;

var colorFound = "not found";

*//for each color in colors.json*

for (var i = 1; i < colorsObj.length; i++) {

*//if color is found return the color code*

if (colorsObj[i].color == color) {

colorFound = colorsObj[i].code.hex;

}

}

res.end(colorFound);

}

Nota: Copilot usará por defecto el archivo abierto como contexto para generar la sugerencia.

Mantén el cursor después del bloque ValidateSpanishDNI y haz clic en el icono Insertar en el cursor en el chat. Esto copia el código generado por Copilot desde el chat al archivo js del servidor en la ubicación mencionada.

Comprueba si hay errores, si es que hay alguno. En este código generado, hay un error ya que hay una declaración constante entre los bloques else.

Pulsa Ctrl+I para abrir el Copilot Inline, escribe y haz clic en el botón Enviar./fix

Copilot genera una solución si puede encontrar una. Acepta o descarta la solución según lo precisa que sea.

Aquí, estamos moviendo la declaración constante dentro del bloque else if de returncolors para resolver el error.

Importante: El código y la resolución pueden ser diferentes para ti según la que genere el Copilot.

Después del bloque añadido, pulsa Ctrl+I para abrir la función en línea de Copilot, pega el contenido de abajo y haz clic en Enviar.

/TellMeAJoke:

Make a call to the joke api and return a random joke using axios (https:*//official-joke-api.appspot.com/random_joke)*

Reference code:

else if (req.url.startsWith('/TellMeAJoke')) {

*//make a call to the joke api and return a random joke using axios*

const axios = require('axios');

axios.get('https://official-joke-api.appspot.com/random_joke')

.then(function (response) {

*// handle success*

res.end(response.data.setup + " " + response.data.punchline);

}

)

.catch(function (error) {

*// handle error*

console.log(error);

})

.then(function () {

*// always executed*

});

}

Haz clic en Aceptar para aceptar el código generado por el Copilot.

Después del bloque de código generado, pulsa Ctrl+I, introduce el texto de abajo y haz clic en el botón Enviar.

/MoviesByDirector:

Receive by querystring a parameter called director

Make a call to the movie api and return a list of movies of that director using axios

Return the full list of movies

Reference code:

*//method that gets the name of a director and retrieves from an api the list of movies of that director*

else if (req.url.startsWith('/MoviesByDirector')) {

*//get a director name from querystring*

var queryData = url.parse(req.url, true).query;

var director = queryData.director;

*//make a call to the movie api omdbapi.com and return a list of movies of that director using axios*

const axios = require('axios');

axios.get('http://www.omdbapi.com/?apikey=XXXXXXX&s=' + director)

.then(function (response) {

*//return the full list of movies*

var movies = "";

for (var i = 0; i < response.data.Search.length; i++) {

movies = movies + response.data.Search[i].Title + ", ";

}

res.end(movies);

}

)

.catch(function (error) {

*// handle error*

console.log(error);

}

)

.then(function () {

*// always executed*

}

);

}

Haz clic en Aceptar para aceptar el código.

Después del bloque de código generado, pulsa Ctrl+I, introduce el texto de abajo y haz clic en el botón Enviar.

/ParseUrl:

Retrieves a parameter from querystring called someurl

Parse the url and return the protocol, host, port, path, querystring and hash

Return the parsed host

Reference code:

*//If url equals to ParseUrl*

else if (req.url.startsWith('/ParseUrl')) {

*//retrieves a parameter from querystring called someurl*

var queryData = url.parse(req.url, true).query;

var someUrl = queryData.someurl;

*//parse the url and return the protocol, host, port, path, querystring and hash*

var urlObj = new URL(someUrl);

var protocol = urlObj.protocol;

var host = urlObj.host;

var port = urlObj.port;

var path = urlObj.pathname;

var querystring = urlObj.search;

var hash = urlObj.hash;

*//return the parsed host*

res.end("host: " + host);

}

Haz clic en Aceptar para aceptar el código.

Después del bloque de código generado, pulsa Ctrl+I, introduce el texto de abajo y haz clic en el botón Enviar.

/GetFullTextFile:

Read sample.txt` and return lines that contains the word "Fusce"

Reference code:

else if (req.url.startsWith('/GetFullTextFile')) {

//read sample.txt and return lines that contains the word "Fusce"

var text = fs.readFileSync('sample.txt', 'utf-8');

var lines = text.split("\r");

var linesFound = "";

for (var i = 1; i < lines.length; i++) {

if (lines[i].includes("Fusce")) {

linesFound = linesFound + lines[i] + ", ";

}

}

res.end(linesFound);

}

NOTA: Ten cuidado con esta implementación, ya que normalmente lee el contenido completo del archivo antes de analizarlo, por lo que el uso de memoria es alto y puede fallar cuando los archivos son demasiado grandes.

Haz clic en Aceptar para aceptar el código.

Después del bloque de código generado, pulsa Ctrl+I, introduce el texto de abajo y haz clic en el botón Enviar.

/GetLineByLinefromtTextFile:

Read sample.txt line by line

Create a promise to read the file line by line, and return a list of lines that contains the word "Fusce"

Return the list of lines

Reference code:

else if (req.url.startsWith('/GetLineByLinefromtTextFile')) {

*//read sample.txt line by line*

var lineReader = require('readline').createInterface({

input: require('fs').createReadStream('sample.txt')

});

*//create a promise to read the file line by line, and return a list of lines that contains the word "Fusce"*

var promise = new Promise(function (resolve, reject) {

var lines = [];

lineReader.on('line', function (line) {

if (line.includes("Fusce")) {

lines.push(line);

}

});

lineReader.on('close', function () {

resolve(lines);

});

});

*//return the list of lines*

promise.then(function (lines) {

res.end(lines.toString());

});

}

Haz clic en Aceptar para aceptar el código.

Después del bloque de código generado, pulsa Ctrl+I, introduce el texto de abajo y haz clic en el botón Enviar.

/CalculateMemoryConsumption:

Return the memory consumption of the process in GB, rounded to 2 decimals

Reference code:

else if (req.url.startsWith('/CalculateMemoryConsumption')) {

*//return the memory consumption of the process in GB, rounded to 2 decimals*

var memory = process.memoryUsage().heapUsed / 1024 / 1024;

res.end(memory.toFixed(2) + " GB");

}

Haz clic en Aceptar para aceptar el código.

Después del bloque de código generado, pulsa Ctrl+I, introduce el texto de abajo y haz clic en el botón Enviar.

/RandomEuropeanCountry:

Make an array of european countries and its iso codes

Return a random country from the array

Return the country and its iso code

Reference code:

else if (req.url.startsWith('/RandomEuropeanCountry')) {

*//make an array of european countries and its iso codes*

var countries = [

{ country: "Italy", iso: "IT" },

{ country: "France", iso: "FR" },

{ country: "Spain", iso: "ES" },

{ country: "Germany", iso: "DE" },

{ country: "United Kingdom", iso: "GB" },

{ country: "Greece", iso: "GR" },

{ country: "Portugal", iso: "PT" },

{ country: "Romania", iso: "RO" },

{ country: "Bulgaria", iso: "BG" },

{ country: "Croatia", iso: "HR" },

{ country: "Czech Republic", iso: "CZ" },

{ country: "Denmark", iso: "DK" },

{ country: "Estonia", iso: "EE" },

{ country: "Finland", iso: "FI" },

{ country: "Hungary", iso: "HU" },

{ country: "Ireland", iso: "IE" },

{ country: "Latvia", iso: "LV" },

{ country: "Lithuania", iso: "LT" },

{ country: "Luxembourg", iso: "LU" },

{ country: "Malta", iso: "MT" },

{ country: "Netherlands", iso: "NL" },

{ country: "Poland", iso: "PL" },

{ country: "Slovakia", iso: "SK" },

{ country: "Slovenia", iso: "SI" },

{ country: "Sweden", iso: "SE" },

{ country: "Belgium", iso: "BE" },

{ country: "Austria", iso: "AT" },

{ country: "Switzerland", iso: "CH" },

{ country: "Cyprus", iso: "CY" },

{ country: "Iceland", iso: "IS" },

{ country: "Norway", iso: "NO" },

{ country: "Albania", iso: "AL" },

{ country: "Andorra", iso: "AD" },

{ country: "Armenia", iso: "AM" },

{ country: "Azerbaijan", iso: "AZ" },

{ country: "Belarus", iso: "BY" },

{ country: "Bosnia and Herzegovina", iso: "BA" },

{ country: "Georgia", iso: "GE" },

{ country: "Kazakhstan", iso: "KZ" },

{ country: "Kosovo", iso: "XK" },

{ country: "Liechtenstein", iso: "LI" },

{ country: "Macedonia", iso: "MK" },

{ country: "Moldova", iso: "MD" },

{ country: "Monaco", iso: "MC" },

{ country: "Montenegro", iso: "ME" },

{ country: "Russia", iso: "RU" },

{ country: "San Marino", iso: "SM" },

{ country: "Serbia", iso: "RS" },

{ country: "Turkey", iso: "TR" },

{ country: "Ukraine", iso: "UA" },

{ country: "Vatican City", iso: "VA" }

];

*//return a random country from the array*

var randomCountry = countries[Math.floor(Math.random() * countries.length)];

*//return the country and its iso code*

res.end(randomCountry.country + " " + randomCountry.iso);

}

Haz clic en Aceptar para aceptar el código.

Ejercicio 3: Documentar el código

Documentar código siempre es una tarea aburrida y dolorosa. Sin embargo, podemos usar Copilot para documentarlo por nosotros. En el chat, pide a Copilot que documente el archivo nodeserver.js.

Selecciona todo en el archivo nodeserver.js.

Desde el chat de Copilot, entra y haz clic en enviar.document the nodeserver.js file

El Copilot genera una documentación detallada del archivo.

Ejercicio 4: Pruebas de construcción

Crearemos pruebas automatizadas para comprobar que la funcionalidad de los endpoints anteriores está correctamente implementada. Las pruebas deberían estar juntas en el archivo test.js.

Puedes aprovechar Copilot para hacer las pruebas. Hay un comando /tests que puedes ejecutar directamente desde Copilot Chat o seleccionando el fragmento de código para el que quieres crear pruebas y usando la función en línea de Copilot.

Abre el archivo test.js.

Haz clic en Enter después del bloque it existente.

Introduce el texto siguiente y haz clic en Enter.

add test to test DaysBetweenDates

Esto genera el bloque de pruebas unitario para DíasEntreFechas. Haz clic en Aceptar para aceptar el código.

Desde el terminal, ejecuta el siguiente comando mocha test.js

Introduce el texto siguiente y haz clic en Enter.*//add test to check validatephoneNumber*

Haz clic en Aceptar para aceptar el código generado por el Copilot.

Desde el terminal, ejecuta el comando, . Comprueba que el número de teléfono validado haya pasado.mocha test.js

Introduce el texto de abajo y pulsa Enter.

*//write test to validate validateSpanishDNI*

Acepta el texto generado por Copilot.

Desde el terminal, ejecuta y comprueba que el ValidateSpanishDNI ha pasado.mocha test.js

Reference Code:

*//write npm command line to install mocha*

*//npm install --global mocha*

*//command to run this test file*

*//mocha test.js*

const assert = require('assert');

const http = require('http');

const server = require('./nodeserver');

describe('Node Server', () => {

it('should return "key not passed" if key is not passed', (done) => {

http

.get('http://localhost:3000/Get' , (res) => {

let data = '';

res.on('data', (chunk) => {

data += chunk;

});

res.on('end', () => {

assert.equal(data, 'key not passed');

done();

});

});

});

it('should return the value of the key if key is found', (done) => {

http.get('http://localhost:3000/Get?key=world', (res) => {

let data = '';

res.on('data', (chunk) => {

data += chunk;

});

res.on('end', () => {

assert.equal(data, 'hello world');

done();

});

});

});

*//add test to check validatephoneNumber*

it('should return "valid" if phoneNumber is valid', (done) => {

http.get('http://localhost:3000/Validatephonenumber?phoneNumber=34666666666', (res) => {

let data = '';

res.on('data', (chunk) => {

data += chunk;

});

res.on('end', () => {

assert.equal(data, 'valid');

done();

});

});

});

*//write test to validate spanish DNI*

it('should return "valid" if spanish DNI 86471508H is valid', (done) => {

http.get('http://localhost:3000/ValidateSpanishDNI?dni=86471508H', (res) => {

let data = '';

res.on('data', (chunk) => {

data += chunk;

});

res.on('end', () => {

assert.equal(data, 'valid');

done();

});

});

});

*//write test to validate spanish DNI*

it('should return "valid" if spanish DNI 24153149K is valid', (done) => {

http.get('http://localhost:3000/ValidateSpanishDNI?dni=24153149K', (res) => {

let data = '';

res.on('data', (chunk) => {

data += chunk;

});

res.on('end', () => {

assert.equal(data, 'valid');

done();

});

});

});

*//write test to validate spanish DNI*

it('should return "valid" if spanish DNI 12345678A is invalid', (done) => {

http.get('http://localhost:3000/ValidateSpanishDNI?dni=12345678A', (res) => {

let data = '';

res.on('data', (chunk) => {

data += chunk;

});

res.on('end', () => {

assert.equal(data, 'invalid');

done();

});

});

});

*//write test for returnColorCode*

it('should return "red" if color is red', (done) => {

http.get('http://localhost:3000/ReturnColorCode?color=red', (res) => {

let data = '';

res.on('data', (chunk) => {

data += chunk;

});

res.on('end', () => {

assert.equal(data, '#FF0000');

done();

});

});

});

*//write test for daysBetweenDates*

it('should return "1" if dates are 2020-01-01 and 2020-01-02', (done) => {

http.get('http://localhost:3000/DaysBetweenDates?date1=2020-01-01&date2=2020-01-02', (res) => {

let data = '';

res.on('data', (chunk) => {

data += chunk;

});

res.on('end', () => {

assert.equal(data, '1 days');

done();

});

});

});

});

Ejercicio 5: Crear un archivo Dockerfile

Abre el dockerfile desde la carpeta node.

El archivo consistirá en comentarios sobre cómo debe poblarse.

Pulsa Ctrl+I y escribe . Haz clic en el icono de enviar./fix

El Copilot generará el contenido del archivo Docker. Haz clic en Aceptar.

Desde el terminal, ejecuta el siguiente comando

docker build -t mynodeapp .

Esto es para construir la imagen y etiquetarla como mynodeapp.

Ejecuta el docker en el puerto 4000 usando el comando de abajo.

docker run -p 4000:3000 -d mynodeapp

Abre el demonio Docker para ver que la aplicación ha sido contenedora y está ejecutándose en él.

Resumen:

En este laboratorio, hemos aprendido a usar el Copilot en un proyecto de nodo