Acerca de Octokit.js
Si quieres escribir un script mediante JavaScript para interactuar con la API de REST de GitHub, GitHub recomienda usar el SDK de Octokit.js. GitHub mantiene Octokit.js. El SDK implementa los procedimientos recomendados y facilita la interacción con la API de REST a través de JavaScript. Octokit.js funciona con todos los exploradores modernos, Node.js y Deno. Para más información, consulta el archivo README de Octokit.js.
Prerrequisitos
En esta guía se supone que sabes usar JavaScript y la API de REST GitHub. Para obtener más información sobre la API de REST, consulta "Introducción a la API REST".
Debes instalar e importar octokit
para usar la biblioteca de Octokit.js. En esta guía se usan instrucciones de importación de acuerdo con ES6. Para obtener más información sobre los diferentes métodos de instalación e importación, consulta la sección Uso del archivo README de Octokit.js.
Creación de instancias y autenticación
Advertencia: Trata tus credenciales de autenticación como una contraseña.
Para proteger tus credenciales, puedes almacenarlas como secreto y ejecutar el script a través de GitHub Actions. Para obtener más información, vea «Uso de secretos en Acciones de GitHub».
Si esto no es posible, considera el uso de otro servicio de CLI para almacenar tus credenciales de forma segura.
Autenticación con un personal access token
Si deseas usar la API de REST de GitHub para uso personal, puedes crear un personal access token. Para obtener más información sobre la creación de un personal access token, consulte "Administración de tokens de acceso personal".
En primer lugar, importa Octokit
desde octokit
. A continuación, pasa los datos de personal access token al crear una instancia de Octokit
. En el ejemplo siguiente, reemplaza YOUR-TOKEN
por una referencia a los datos de personal access token. Reemplaza HOSTNAME
por el nombre de tu instancia de GitHub Enterprise Server.
import { Octokit } from "octokit"; const octokit = new Octokit({ baseUrl: "http(s)://HOSTNAME/api/v3", auth: 'YOUR-TOKEN', });
import { Octokit } from "octokit";
const octokit = new Octokit({
baseUrl: "http(s)://HOSTNAME/api/v3",
auth: 'YOUR-TOKEN',
});
Autenticación con una GitHub App
Si deseas usar la API en nombre de una organización u otro usuario, GitHub recomienda usar un GitHub App. Si un punto de conexión está disponible para GitHub Apps, en la documentación de referencia de REST para ese punto de conexión se indicará que tipo de token de GitHub App se requiere. Para obtener más información, vea «Registro de una instancia de GitHub App» y «Acerca de la autenticación con una aplicación de GitHub».
En lugar de importar Octokit
desde octokit
, importa App
. En el ejemplo siguiente, reemplaza APP_ID
por una referencia al identificador de la aplicación. Reemplaza PRIVATE_KEY
por una referencia a la clave privada de la aplicación. Reemplaza INSTALLATION_ID
por el identificador de la instalación de la aplicación en nombre de la cual quieras autenticarte. Puedes encontrar el identificador de la aplicación y generar una clave privada en la página de configuración de la aplicación. Para obtener más información, vea «Administración de claves privadas para aplicaciones de GitHub». Puedes obtener un identificador de instalación con GET /users/{username}/installation
, GET /repos/{owner}/{repo}/installation
o los puntos de conexión de GET /orgs/{org}/installation
. Para más información, consulta "Puntos de conexión de la API de REST para GitHub Apps." Reemplaza HOSTNAME
por el nombre de tu instancia de GitHub Enterprise Server.
import { App } from "octokit"; const app = new App({ appId: APP_ID, privateKey: PRIVATE_KEY, Octokit: Octokit.defaults({ baseUrl: "http(s)://HOSTNAME/api/v3", }), }); const octokit = await app.getInstallationOctokit(INSTALLATION_ID);
import { App } from "octokit";
const app = new App({
appId: APP_ID,
privateKey: PRIVATE_KEY,
Octokit: Octokit.defaults({
baseUrl: "http(s)://HOSTNAME/api/v3",
}),
});
const octokit = await app.getInstallationOctokit(INSTALLATION_ID);
Autenticación en GitHub Actions
Si deseas usar la API en un flujo de trabajo de GitHub Actions, GitHub recomienda autenticarse con el GITHUB_TOKEN
integrado en lugar de crear un token. Puedes conceder permisos a GITHUB_TOKEN
con la clave permissions
. Para obtener más información sobre GITHUB_TOKEN
, consulta "Autenticación automática de tokens".
Si el flujo de trabajo necesita acceder a los recursos fuera del repositorio del flujo de trabajo, no podrás usar GITHUB_TOKEN
. En ese caso, almacena tus credenciales como secreto y reemplaza GITHUB_TOKEN
en el ejemplo siguiente por el nombre del secreto. Para obtener más información sobre secretos, consulte "Uso de secretos en Acciones de GitHub".
Si usas la palabra clave run
para ejecutar el script de JavaScript en tus flujos de trabajo de GitHub Actions, puedes almacenar el valor de GITHUB_TOKEN
como una variable de entorno. El script puede acceder a la variable de entorno como process.env.VARIABLE_NAME
.
Por ejemplo, este paso de flujo de trabajo almacena GITHUB_TOKEN
en una variable de entorno denominada TOKEN
:
- name: Run script
env:
TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
node .github/actions-scripts/use-the-api.mjs
El script que el flujo de trabajo ejecuta usa process.env.TOKEN
para autenticarse:
import { Octokit } from "octokit"; const octokit = new Octokit({ baseUrl: "http(s)://HOSTNAME/api/v3", auth: process.env.TOKEN, });
import { Octokit } from "octokit";
const octokit = new Octokit({
baseUrl: "http(s)://HOSTNAME/api/v3",
auth: process.env.TOKEN,
});
Creación de instancias sin autenticación
Puedes usar la API de REST sin autenticación, aunque tendrás un límite de velocidad inferior y no podrás usar algunos puntos de conexión. Para crear una instancia de Octokit
sin autenticación, no pases el argumento auth
. Establece la dirección URL base en http(s)://HOSTNAME/api/v3
. Reemplaza [hostname]
por el nombre de host de tu instancia de GitHub Enterprise Server.
import { Octokit } from "octokit"; const octokit = new Octokit({ baseUrl: "http(s)://HOSTNAME/api/v3", });
import { Octokit } from "octokit";
const octokit = new Octokit({
baseUrl: "http(s)://HOSTNAME/api/v3",
});
Realización de solicitudes
Octokit admite varias formas de realizar solicitudes. Puedes usar el método request
para realizar solicitudes si conoces el verbo HTTP y la ruta de acceso del punto de conexión. Puedes usar el método rest
si quieres aprovechar la función de autocompletar en el IDE y escribir. En el caso de los puntos de conexión paginados, puedes usar el método paginate
para solicitar varias páginas de datos.
Uso del método request
para realizar solicitudes
Para usar el método request
para realizar solicitudes, pasa el método HTTP y la ruta de acceso como primer argumento. Pasa cualquier parámetro de cuerpo, consulta o ruta en un objeto como segundo argumento. Por ejemplo, para realizar una solicitud GET
a /repos/{owner}/{repo}/issues
y pasar los parámetros owner
, repo
y per_page
:
await octokit.request("GET /repos/{owner}/{repo}/issues", { owner: "github", repo: "docs", per_page: 2 });
await octokit.request("GET /repos/{owner}/{repo}/issues", {
owner: "github",
repo: "docs",
per_page: 2
});
El método request
pasa automáticamente el encabezado Accept: application/vnd.github+json
. Para pasar encabezados adicionales o un encabezado Accept
diferente, agrega una propiedad headers
al objeto que se pasa como segundo argumento. El valor de la propiedad headers
es un objeto con los nombres de encabezado como claves y valores de encabezado como valores. Por ejemplo, para enviar un encabezado content-type
con un valor de text/plain
y un encabezado x-github-api-version
con un valor de 2022-11-28
:
await octokit.request("POST /markdown/raw", { text: "Hello **world**", headers: { "content-type": "text/plain", "x-github-api-version": "2022-11-28", }, });
await octokit.request("POST /markdown/raw", {
text: "Hello **world**",
headers: {
"content-type": "text/plain",
"x-github-api-version": "2022-11-28",
},
});
Uso de métodos de punto de conexión rest
para realizar solicitudes
Cada punto de conexión de la API de REST tiene un método de punto de conexión asociado rest
en Octokit. Por lo general, estos métodos se autocompletan en el IDE para mayor comodidad. Puedes pasar cualquier parámetro como un objeto al método.
await octokit.rest.issues.listForRepo({ owner: "github", repo: "docs", per_page: 2 });
await octokit.rest.issues.listForRepo({
owner: "github",
repo: "docs",
per_page: 2
});
Además, si usas un lenguaje con tipo como TypeScript, puedes importar tipos para usarlos con estos métodos. Para obtener más información, consulta la sección TypeScript en el archivo README de plugin-rest-endpoint-methods.js.
Realización de solicitudes paginadas
Si el punto de conexión está paginado y quieres capturar más de una página de resultados, puedes usar el método paginate
. paginate
capturará la siguiente página de resultados hasta llegar a la última página y, a continuación, devolverá todos los resultados como una sola matriz. Algunos puntos de conexión devuelven resultados paginados como matriz en un objeto, en lugar de devolverlos como una matriz. paginate
siempre devuelve una matriz de elementos, aun cuando el resultado sin procesar sea un objeto.
Por ejemplo, el siguiente ejemplo obtiene todas las incidencias del repositorio github/docs
. Aunque se solicitan 100 incidencias a la vez, la función no regresará hasta que se alcance la última página de datos.
const issueData = await octokit.paginate("GET /repos/{owner}/{repo}/issues", { owner: "github", repo: "docs", per_page: 100, headers: { "x-github-api-version": "2022-11-28", }, });
const issueData = await octokit.paginate("GET /repos/{owner}/{repo}/issues", {
owner: "github",
repo: "docs",
per_page: 100,
headers: {
"x-github-api-version": "2022-11-28",
},
});
El método paginate
acepta una función de asignación opcional, que puedes usar para recopilar solo los datos que quieras de la respuesta. Esto reduce la cantidad de memoria que usa el script. La función de asignación puede tomar un segundo argumento, done
, al que puedes llamar para finalizar la paginación antes de alcanzar la última página. Esto te permite capturar un subconjunto de páginas. Por ejemplo, el ejemplo siguiente continúa capturando resultados hasta que se devuelve un problema que incluye "test" en el título. Para las páginas de datos que se han devuelto, solo se almacenan el título del problema y el autor.
const issueData = await octokit.paginate("GET /repos/{owner}/{repo}/issues", { owner: "github", repo: "docs", per_page: 100, headers: { "x-github-api-version": "2022-11-28", }, }, (response, done) => response.data.map((issue) => { if (issue.title.includes("test")) { done() } return ({title: issue.title, author: issue.user.login}) }) );
const issueData = await octokit.paginate("GET /repos/{owner}/{repo}/issues", {
owner: "github",
repo: "docs",
per_page: 100,
headers: {
"x-github-api-version": "2022-11-28",
},
},
(response, done) => response.data.map((issue) => {
if (issue.title.includes("test")) {
done()
}
return ({title: issue.title, author: issue.user.login})
})
);
En lugar de capturar todos los resultados a la vez, puedes usar octokit.paginate.iterator()
para recorrer en iteración una sola página a la vez. Por ejemplo, en el ejemplo siguiente se captura una página de resultados a la vez y se procesa cada objeto de la página antes de capturar la página siguiente. Una vez que se alcanza un problema que incluye "prueba" en el título, el script detiene la iteración y devuelve el título del problema y el autor del problema de cada objeto que se procesó. El iterador es el método más eficiente en memoria para obtener datos paginados.
const iterator = octokit.paginate.iterator("GET /repos/{owner}/{repo}/issues", { owner: "github", repo: "docs", per_page: 100, headers: { "x-github-api-version": "2022-11-28", }, }); let issueData = [] let breakLoop = false for await (const {data} of iterator) { if (breakLoop) break for (const issue of data) { if (issue.title.includes("test")) { breakLoop = true break } else { issueData = [...issueData, {title: issue.title, author: issue.user.login}]; } } }
const iterator = octokit.paginate.iterator("GET /repos/{owner}/{repo}/issues", {
owner: "github",
repo: "docs",
per_page: 100,
headers: {
"x-github-api-version": "2022-11-28",
},
});
let issueData = []
let breakLoop = false
for await (const {data} of iterator) {
if (breakLoop) break
for (const issue of data) {
if (issue.title.includes("test")) {
breakLoop = true
break
} else {
issueData = [...issueData, {title: issue.title, author: issue.user.login}];
}
}
}
También puedes usar el método paginate
con los métodos de punto de conexión rest
. Pasa el método de punto de conexión rest
como primer argumento. Pasa los parámetros como segundo argumento.
const iterator = octokit.paginate.iterator(octokit.rest.issues.listForRepo, { owner: "github", repo: "docs", per_page: 100, headers: { "x-github-api-version": "2022-11-28", }, });
const iterator = octokit.paginate.iterator(octokit.rest.issues.listForRepo, {
owner: "github",
repo: "docs",
per_page: 100,
headers: {
"x-github-api-version": "2022-11-28",
},
});
Para obtener más información sobre la paginación, consulta "Uso de la paginación en la API de REST".
Almacenamiento en caché de los errores
Detección de todos los errores
A veces, la API de REST de GitHub devolverá un error. Por ejemplo, recibirás un error si el token de acceso ha expirado o si has omitido un parámetro necesario. Octokit.js reintenta automáticamente la solicitud cuando obtiene un error distinto de 400 Bad Request
, 401 Unauthorized
, 403 Forbidden
, 404 Not Found
y 422 Unprocessable Entity
. Si se produce un error de API incluso después de varios reintentos, Octokit.js genera un error que incluye el código de estado HTTP de la respuesta (response.status
) y los encabezados de respuesta (response.headers
). Debes controlar estos errores en el código. Por ejemplo, puedes usar un bloque try/catch para detectar errores:
let filesChanged = [] try { const iterator = octokit.paginate.iterator("GET /repos/{owner}/{repo}/pulls/{pull_number}/files", { owner: "github", repo: "docs", pull_number: 22809, per_page: 100, headers: { "x-github-api-version": "2022-11-28", }, }); for await (const {data} of iterator) { filesChanged = [...filesChanged, ...data.map(fileData => fileData.filename)]; } } catch (error) { if (error.response) { console.error(`Error! Status: ${error.response.status}. Message: ${error.response.data.message}`) } console.error(error) }
let filesChanged = []
try {
const iterator = octokit.paginate.iterator("GET /repos/{owner}/{repo}/pulls/{pull_number}/files", {
owner: "github",
repo: "docs",
pull_number: 22809,
per_page: 100,
headers: {
"x-github-api-version": "2022-11-28",
},
});
for await (const {data} of iterator) {
filesChanged = [...filesChanged, ...data.map(fileData => fileData.filename)];
}
} catch (error) {
if (error.response) {
console.error(`Error! Status: ${error.response.status}. Message: ${error.response.data.message}`)
}
console.error(error)
}
Control de los códigos de error previstos
A veces, los datos GitHub usan un código de estado 4xx para indicar una respuesta que no es de error. Si el punto de conexión que usa lo hace, puedes agregar control adicional para errores específicos. Por ejemplo, el punto de conexión GET /user/starred/{owner}/{repo}
devolverá un valor 404
si el repositorio no está destacado. En el ejemplo siguiente se usa la respuesta 404
para indicar que el repositorio no se ha destacado; todos los demás códigos de error se tratan como errores.
try { await octokit.request("GET /user/starred/{owner}/{repo}", { owner: "github", repo: "docs", headers: { "x-github-api-version": "2022-11-28", }, }); console.log(`The repository is starred by me`); } catch (error) { if (error.status === 404) { console.log(`The repository is not starred by me`); } else { console.error(`An error occurred while checking if the repository is starred: ${error?.response?.data?.message}`); } }
try {
await octokit.request("GET /user/starred/{owner}/{repo}", {
owner: "github",
repo: "docs",
headers: {
"x-github-api-version": "2022-11-28",
},
});
console.log(`The repository is starred by me`);
} catch (error) {
if (error.status === 404) {
console.log(`The repository is not starred by me`);
} else {
console.error(`An error occurred while checking if the repository is starred: ${error?.response?.data?.message}`);
}
}
Control de errores de límite de frecuencia
Si recibes un error de límite de frecuencia, es posible que quieras volver a realizar la solicitud después de esperar. Cuando se limita la velocidad, GitHub responde con un error 403 Forbidden
y el valor del encabezado de respuesta x-ratelimit-remaining
será "0"
. Los encabezados de respuesta incluirán un encabezado x-ratelimit-reset
, que indica la hora a la que se restablece la ventana de límite de velocidad actual, en segundos de época UTC. Puedes volver a intentar realizar tu solicitud después del tiempo especificado por x-ratelimit-reset
.
async function requestRetry(route, parameters) { try { const response = await octokit.request(route, parameters); return response } catch (error) { if (error.response && error.status === 403 && error.response.headers['x-ratelimit-remaining'] === '0') { const resetTimeEpochSeconds = error.response.headers['x-ratelimit-reset']; const currentTimeEpochSeconds = Math.floor(Date.now() / 1000); const secondsToWait = resetTimeEpochSeconds - currentTimeEpochSeconds; console.log(`You have exceeded your rate limit. Retrying in ${secondsToWait} seconds.`); setTimeout(requestRetry, secondsToWait * 1000, route, parameters); } else { console.error(error); } } } const response = await requestRetry("GET /repos/{owner}/{repo}/issues", { owner: "github", repo: "docs", per_page: 2 })
async function requestRetry(route, parameters) {
try {
const response = await octokit.request(route, parameters);
return response
} catch (error) {
if (error.response && error.status === 403 && error.response.headers['x-ratelimit-remaining'] === '0') {
const resetTimeEpochSeconds = error.response.headers['x-ratelimit-reset'];
const currentTimeEpochSeconds = Math.floor(Date.now() / 1000);
const secondsToWait = resetTimeEpochSeconds - currentTimeEpochSeconds;
console.log(`You have exceeded your rate limit. Retrying in ${secondsToWait} seconds.`);
setTimeout(requestRetry, secondsToWait * 1000, route, parameters);
} else {
console.error(error);
}
}
}
const response = await requestRetry("GET /repos/{owner}/{repo}/issues", {
owner: "github",
repo: "docs",
per_page: 2
})
Análisis de la respuesta
El método request
devuelve una promesa que se resuelve en un objeto si la solicitud se ha realizado correctamente. Las propiedades del objeto son data
(el cuerpo de la respuesta devuelto por el punto de conexión), status
(el código de respuesta HTTP), url
(la dirección URL de la solicitud) y headers
(un objeto que contiene los encabezados de respuesta). A menos que se especifique lo contrario, el cuerpo de la respuesta está en formato JSON. Algunos puntos de conexión no devuelven un cuerpo de respuesta; en esos casos, se omite la propiedad data
.
const response = await octokit.request("GET /repos/{owner}/{repo}/issues/{issue_number}", { owner: "github", repo: "docs", issue_number: 11901, headers: { "x-github-api-version": "2022-11-28", }, }); console.log(`The status of the response is: ${response.status}`) console.log(`The request URL was: ${response.url}`) console.log(`The x-ratelimit-remaining response header is: ${response.headers["x-ratelimit-remaining"]}`) console.log(`The issue title is: ${response.data.title}`)
const response = await octokit.request("GET /repos/{owner}/{repo}/issues/{issue_number}", {
owner: "github",
repo: "docs",
issue_number: 11901,
headers: {
"x-github-api-version": "2022-11-28",
},
});
console.log(`The status of the response is: ${response.status}`)
console.log(`The request URL was: ${response.url}`)
console.log(`The x-ratelimit-remaining response header is: ${response.headers["x-ratelimit-remaining"]}`)
console.log(`The issue title is: ${response.data.title}`)
Del mismo modo, el método paginate
devuelve una promesa. Si la solicitud se ha realizado correctamente, la promesa se resuelve en una matriz de datos devueltos por el punto de conexión. A diferencia del método request
, el método paginate
no devuelve el código de estado, la dirección URL ni los encabezados.
const data = await octokit.paginate("GET /repos/{owner}/{repo}/issues", { owner: "github", repo: "docs", per_page: 100, headers: { "x-github-api-version": "2022-11-28", }, }); console.log(`${data.length} issues were returned`) console.log(`The title of the first issue is: ${data[0].title}`)
const data = await octokit.paginate("GET /repos/{owner}/{repo}/issues", {
owner: "github",
repo: "docs",
per_page: 100,
headers: {
"x-github-api-version": "2022-11-28",
},
});
console.log(`${data.length} issues were returned`)
console.log(`The title of the first issue is: ${data[0].title}`)
Script de ejemplo
Este es un script de ejemplo completo que usa Octokit.js. El script importa Octokit
y crea una nueva instancia de Octokit
. Si quieres autenticarte con un valor GitHub App en lugar de un personal access token, tendrás que crear e importar instancias de App
en lugar de Octokit
. Para más información, consulta "Autenticación con una GitHub App".
La función getChangedFiles
obtiene todos los archivos modificados para una solicitud de incorporación de cambios. La función commentIfDataFilesChanged
llama a la función getChangedFiles
. Si alguno de los archivos que cambió la solicitud de incorporación de cambios incluye /data/
en la ruta de acceso del archivo, la función comentará la solicitud de incorporación de cambios.
import { Octokit } from "octokit"; const octokit = new Octokit({ baseUrl: "http(s)://HOSTNAME/api/v3", auth: 'YOUR-TOKEN', }); async function getChangedFiles({owner, repo, pullNumber}) { let filesChanged = [] try { const iterator = octokit.paginate.iterator("GET /repos/{owner}/{repo}/pulls/{pull_number}/files", { owner: owner, repo: repo, pull_number: pullNumber, per_page: 100, headers: { "x-github-api-version": "2022-11-28", }, }); for await (const {data} of iterator) { filesChanged = [...filesChanged, ...data.map(fileData => fileData.filename)]; } } catch (error) { if (error.response) { console.error(`Error! Status: ${error.response.status}. Message: ${error.response.data.message}`) } console.error(error) } return filesChanged } async function commentIfDataFilesChanged({owner, repo, pullNumber}) { const changedFiles = await getChangedFiles({owner, repo, pullNumber}); const filePathRegex = new RegExp(/\/data\//, "i"); if (!changedFiles.some(fileName => filePathRegex.test(fileName))) { return; } try { const {data: comment} = await octokit.request("POST /repos/{owner}/{repo}/issues/{issue_number}/comments", { owner: owner, repo: repo, issue_number: pullNumber, body: `It looks like you changed a data file. These files are auto-generated. \n\nYou must revert any changes to data files before your pull request will be reviewed.`, headers: { "x-github-api-version": "2022-11-28", }, }); return comment.html_url; } catch (error) { if (error.response) { console.error(`Error! Status: ${error.response.status}. Message: ${error.response.data.message}`) } console.error(error) } } await commentIfDataFilesChanged({owner: "github", repo: "docs", pullNumber: 191});
import { Octokit } from "octokit";
const octokit = new Octokit({
baseUrl: "http(s)://HOSTNAME/api/v3",
auth: 'YOUR-TOKEN',
});
async function getChangedFiles({owner, repo, pullNumber}) {
let filesChanged = []
try {
const iterator = octokit.paginate.iterator("GET /repos/{owner}/{repo}/pulls/{pull_number}/files", {
owner: owner,
repo: repo,
pull_number: pullNumber,
per_page: 100,
headers: {
"x-github-api-version": "2022-11-28",
},
});
for await (const {data} of iterator) {
filesChanged = [...filesChanged, ...data.map(fileData => fileData.filename)];
}
} catch (error) {
if (error.response) {
console.error(`Error! Status: ${error.response.status}. Message: ${error.response.data.message}`)
}
console.error(error)
}
return filesChanged
}
async function commentIfDataFilesChanged({owner, repo, pullNumber}) {
const changedFiles = await getChangedFiles({owner, repo, pullNumber});
const filePathRegex = new RegExp(/\/data\//, "i");
if (!changedFiles.some(fileName => filePathRegex.test(fileName))) {
return;
}
try {
const {data: comment} = await octokit.request("POST /repos/{owner}/{repo}/issues/{issue_number}/comments", {
owner: owner,
repo: repo,
issue_number: pullNumber,
body: `It looks like you changed a data file. These files are auto-generated. \n\nYou must revert any changes to data files before your pull request will be reviewed.`,
headers: {
"x-github-api-version": "2022-11-28",
},
});
return comment.html_url;
} catch (error) {
if (error.response) {
console.error(`Error! Status: ${error.response.status}. Message: ${error.response.data.message}`)
}
console.error(error)
}
}
await commentIfDataFilesChanged({owner: "github", repo: "docs", pullNumber: 191});
Pasos siguientes
- Para más información sobre Octokit.js, consulta la documentación de Octokit.js.
- Para ver algunos ejemplos de la vida real, consulta cómo GitHub Docs usa Octokit.js mediante la búsqueda en el repositorio de GitHub Docs.