Skip to main content
Мы публикуем частые обновления нашей документации, и перевод этой страницы может все еще выполняться. Актуальные сведения см. в документации на английском языке.

Создание скриптов с помощью REST API и JavaScript

Создайте скрипт с помощью пакета SDK для Octokit.js для взаимодействия с REST API.

Сведения о Octokit.js

Если вы хотите написать скрипт с помощью JavaScript для взаимодействия с REST API GitHub, GitHub рекомендует использовать пакет SDK для Octokit.js. Octokit.js поддерживается GitHub. Пакет SDK реализует рекомендации и упрощает взаимодействие с REST API через JavaScript. Octokit.js работает со всеми современными браузерами, Node.js и Deno. Дополнительные сведения о Octokit.js см. в файле сведений Octokit.js.

Предварительные требования

В этом руководстве предполагается, что вы знакомы с JavaScript и REST API GitHub. Дополнительные сведения о REST API см. в разделе Начало работы с REST API.

Чтобы использовать библиотеку Octokit.js, необходимо установить и импортировать octokit ее. В этом руководстве используются инструкции импорта в соответствии с ES6. Дополнительные сведения о различных методах установки и импорта см . в разделе использование файла сведений Octokit.js.

Создание экземпляра и проверка подлинности

Предупреждение. Рассматривайте учетные данные проверки подлинности как пароль.

Чтобы обеспечить безопасность учетных данных, вы можете сохранить свои учетные данные в виде секрета и запустить скрипт с помощью GitHub Actions. Дополнительные сведения см. в разделе Зашифрованные секреты.

Если это невозможно, рассмотрите возможность безопасного хранения учетных данных с помощью другой службы, например cli 1Password .

Проверка подлинности с помощью personal access token

Если вы хотите использовать REST API GitHub для личного использования, можно создать personal access token. Дополнительные сведения о создании personal access token см. в разделе Создание личного маркера доступа.

Сначала импортируйте Octokit из octokit. Затем передайте personal access token при создании экземпляра Octokit. В следующем примере замените YOUR-TOKEN ссылкой на personal access token.{ % ifversion ghes or ghae %} Замените [hostname] именем экземпляр GitHub Enterprise Server.{ % endif %}

JavaScript
import { Octokit } from "octokit";

const octokit = new Octokit({ 
  baseUrl: "http(s)://HOSTNAME/api/v3",
  auth: 'YOUR-TOKEN',
});

Проверка подлинности с помощью GitHub App

Если вы хотите использовать API от имени организации или другого пользователя, GitHub рекомендует использовать GitHub App. Если конечная точка доступна для GitHub Apps, в справочной документации по REST для этой конечной точки будет указано "Работает с GitHub Apps". Дополнительные сведения см. в разделах "Создание приложения GitHub", "Сведения о проверке подлинности с помощью Приложение GitHub" и "Проверка подлинности с помощью Приложение GitHub от имени пользователя".

Вместо импорта из octokitимпорта Octokit импортируйте App. В следующем примере замените APP_ID ссылкой на идентификатор приложения. Замените PRIVATE_KEY ссылкой на закрытый ключ приложения. Замените INSTALLATION_ID идентификатором установки приложения, от имени которого требуется пройти проверку подлинности. Вы можете найти идентификатор приложения и создать закрытый ключ на странице параметров приложения. Дополнительные сведения см. в разделе Управление закрытыми ключами для приложений GitHub. Идентификатор установки можно получить с конечными GET /users/{username}/installationточками , GET /repos/{owner}/{repo}/installationили GET /orgs/{org}/installation . Дополнительные сведения см. в разделе Приложения GitHub справочной документации по REST.

JavaScript
import { App } from "octokit";

const app = new App({
  appId: APP_ID,
  privateKey: PRIVATE_KEY,
});

const octokit = await app.getInstallationOctokit(INSTALLATION_ID);

Проверка подлинности в GitHub Actions

Если вы хотите использовать API в рабочем процессе GitHub Actions, GitHub рекомендует выполнять проверку подлинности с помощью встроенного GITHUB_TOKEN вместо создания маркера. Вы можете предоставить разрешения для GITHUB_TOKEN с помощью ключа permissions. Дополнительные сведения о GITHUB_TOKENсм. в разделе Автоматическая проверка подлинности токенов.

Если рабочему процессу требуется доступ к ресурсам за пределами репозитория рабочего процесса, вы не сможете использовать GITHUB_TOKEN. В этом случае сохраните учетные данные в виде секрета и замените GITHUB_TOKEN в приведенных ниже примерах именем секрета. Дополнительные сведения о секретах см. в разделе Зашифрованные секреты.

Если вы используете run ключевое слово для выполнения скрипта JavaScript в рабочих процессах GitHub Actions, значение GITHUB_TOKEN можно сохранить в виде переменной среды. Ваш скрипт может получить доступ к переменной среды как process.env.VARIABLE_NAME.

Например, этот шаг рабочего процесса сохраняет GITHUB_TOKEN в переменной среды с именем TOKEN:

- name: Run script
  env:
    TOKEN: ${{ secrets.GITHUB_TOKEN }}
  run: |
    node .github/actions-scripts/use-the-api.mjs

Сценарий, который выполняется рабочим процессом, используется process.env.TOKEN для проверки подлинности:

JavaScript
import { Octokit } from "octokit";

const octokit = new Octokit({ 
  baseUrl: "http(s)://HOSTNAME/api/v3",
  auth: process.env.TOKEN,
});

Создание экземпляра без проверки подлинности

Вы можете использовать REST API без проверки подлинности, хотя у вас будет более низкий предел скорости и вы не сможете использовать некоторые конечные точки. Чтобы создать экземпляр без Octokit проверки подлинности auth , не передайте аргумент.{ % ifversion ghes or ghae %} Задайте для базового URL-адреса значение http(s)://HOSTNAME/api/v3. Замените [hostname] именем экземпляр GitHub Enterprise Server.{ % endif %}

JavaScript
import { Octokit } from "octokit";

const octokit = new Octokit({ 
  baseUrl: "http(s)://HOSTNAME/api/v3",
});

Выполнение запросов

Octokit поддерживает несколько способов выполнения запросов. Метод можно использовать для request выполнения запросов, если вы знаете HTTP-команду и путь для конечной точки. Метод можно использовать, rest если вы хотите воспользоваться преимуществами автозавершения в интегрированной среде разработки и ввода текста. Для конечных точек с разбивкой на paginate страницы можно использовать метод для запроса нескольких страниц данных.

Использование метода для request выполнения запросов

Чтобы использовать request метод для выполнения запросов, передайте метод HTTP и путь в качестве первого аргумента. Передайте все параметры текста, запроса или пути в объекте в качестве второго аргумента. Например, чтобы выполнить GET запрос к /repos/{owner}/{repo}/issues параметрам , repoи per_page передать ихowner, выполните следующие действия:

JavaScript
await octokit.request("GET /repos/{owner}/{repo}/issues", {
  owner: "github",
  repo: "docs",
  per_page: 2
});

Метод request автоматически передает Accept: application/vnd.github+json заголовок . Чтобы передать дополнительные заголовки или другой Accept заголовок, добавьте headers свойство к объекту , который передается в качестве второго аргумента. Значение свойства headers — это объект с именами заголовков в качестве ключей и значениями заголовков в качестве значений. Например, чтобы отправить content-type заголовок со значением text/plain:

JavaScript
await octokit.request("POST /markdown/raw", {
  text: "Hello **world**",
  headers: {
    "content-type": "text/plain",
  },
});

Использование rest методов конечной точки для выполнения запросов

Каждая конечная точка REST API имеет связанный rest метод конечной точки в Octokit. Эти методы обычно автозавершения в интегрированной среде разработки для удобства. В метод можно передать любые параметры в виде объекта .

JavaScript
await octokit.rest.issues.listForRepo({
  owner: "github",
  repo: "docs",
  per_page: 2
});

Кроме того, если вы используете типизированный язык, например TypeScript, можно импортировать типы для использования с этими методами. Дополнительные сведения см. в разделе TypeScript в файле сведений plugin-rest-endpoint-methods.js.

Выполнение запросов с разбивкой на страницы

Если конечная точка разбита на страницы и вы хотите получить несколько страниц результатов, можно использовать paginate метод . paginate получает следующую страницу результатов, пока не достигнет последней страницы, а затем возвращает все результаты в виде одного массива. Несколько конечных точек возвращают результаты с разбивкой на страницы в виде массива в объекте, а не возвращают результаты с разбивкой на страницы в виде массива. paginate всегда возвращает массив элементов, даже если необработанным результатом был объект .

Например, следующий пример получает все проблемы из репозитория github/docs . Хотя она запрашивает 100 проблем за раз, функция не возвращается, пока не будет достигнута последняя страница данных.

JavaScript
const issueData = await octokit.paginate("GET /repos/{owner}/{repo}/issues", {
  owner: "github",
  repo: "docs",
  per_page: 100,
});

Метод paginate принимает необязательную функцию map, которую можно использовать для сбора только нужных данных из ответа. Это сокращает использование памяти скриптом. Функция map может принимать второй аргумент , doneкоторый можно вызвать для завершения разбиения на страницы до достижения последней страницы. Это позволяет получить подмножество страниц. Например, в следующем примере продолжается получение результатов до тех пор, пока не будет возвращена проблема, которая содержит слово "test" в заголовке. Для страниц возвращаемых данных сохраняются только название проблемы и автор.

JavaScript
const issueData = await octokit.paginate("GET /repos/{owner}/{repo}/issues", {
  owner: "github",
  repo: "docs",
  per_page: 100,
},
    (response, done) => response.data.map((issue) => {
    if (issue.title.includes("test")) {
      done()
    }
    return ({title: issue.title, author: issue.user.login})
  })
);

Вместо того чтобы получать все результаты одновременно, можно использовать для octokit.paginate.iterator() итерации по одной странице за раз. Например, в следующем примере извлекается одна страница результатов за раз и обрабатывается каждый объект со страницы перед получением следующей страницы. После достижения проблемы, которая включает в себя "test" в заголовке, скрипт останавливает итерацию и возвращает заголовок проблемы и автора проблемы для каждого обработанного объекта. Итератор является наиболее эффективным в памяти методом получения данных с разбивкой на страницы.

JavaScript
const iterator = octokit.paginate.iterator("GET /repos/{owner}/{repo}/issues", {
  owner: "github",
  repo: "docs",
  per_page: 100,
});

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}];
    }
  }
}

Метод можно также использовать paginate с методами конечной rest точки. Передайте метод конечной rest точки в качестве первого аргумента. Передайте все параметры в качестве второго аргумента.

JavaScript
const iterator = octokit.paginate.iterator(octokit.rest.issues.listForRepo, {
  owner: "github",
  repo: "docs",
  per_page: 100,
});

Дополнительные сведения о разбиении на страницы см. в разделе Использование разбиения на страницы в REST API.

выявления ошибок;

Перехват всех ошибок

Иногда REST API GitHub возвращает ошибку. Например, вы получите сообщение об ошибке, если срок действия маркера доступа истек или если вы опустили обязательный параметр. Octokit.js автоматически повторяет запрос при получении ошибки, отличной от 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, и 422 Unprocessable Entity. Если ошибка API возникает даже после повторных попыток, Octokit.js выдает ошибку, которая включает код состояния HTTP ответа (response.status) и заголовки ответа (response.headers). Эти ошибки следует обрабатывать в коде. Например, можно использовать блок try/catch для перехвата ошибок:

JavaScript
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,
  });

  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)
}

Обработка предполагаемых кодов ошибок

Иногда GitHub использует код состояния 4xx для указания ответа без ошибок. Если это делает конечная точка, вы можете добавить дополнительную обработку определенных ошибок. Например, конечная GET /user/starred/{owner}/{repo} точка вернет , 404 если репозиторий не помечен звездою. В следующем примере используется 404 ответ, чтобы указать, что репозиторий не помечен звездой; все остальные коды ошибок обрабатываются как ошибки.

JavaScript
try {
  await octokit.request("GET /user/starred/{owner}/{repo}", {
    owner: "github",
    repo: "docs",
  });

  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}`);
  }
}

Обработка ошибок ограничения скорости

При возникновении ошибки ограничения скорости может потребоваться повторить запрос после ожидания. Если скорость ограничена, GitHub отвечает с ошибкой 403 Forbidden , а x-ratelimit-remaining заголовок ответа будет иметь "0"значение . Заголовки ответа будут содержать x-ratelimit-reset заголовок, который сообщает время сброса текущего окна ограничения скорости в секундах в формате UTC. Вы можете повторить запрос по истечении времени, указанного параметром x-ratelimit-reset.

JavaScript
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
  })

Использование ответа

Метод request возвращает обещание, которое разрешается в объект в случае успешного выполнения запроса. Свойства объекта: data (текст ответа, возвращаемый конечной точкой), status (код HTTP-ответа), url (URL-адрес запроса) и headers (объект, содержащий заголовки ответа). Если не указано иное, текст ответа имеет формат JSON. Некоторые конечные точки не возвращают текст ответа; в таких случаях свойство опущено data .

JavaScript
const response = await octokit.request("GET /repos/{owner}/{repo}/issues/{issue_number}", {
  owner: "github",
  repo: "docs",
  issue_number: 11901,
});

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}`)

Аналогичным образом метод paginate возвращает обещание. Если запрос был выполнен успешно, обещание разрешается в массив данных, возвращенных конечной точкой. request В отличие от метода, paginate метод не возвращает код состояния, URL-адрес или заголовки.

JavaScript
const data = await octokit.paginate("GET /repos/{owner}/{repo}/issues", {
  owner: "github",
  repo: "docs",
  per_page: 100,
});

console.log(`${data.length} issues were returned`)
console.log(`The title of the first issue is: ${data[0].title}`)

Пример сценария

Ниже приведен полный пример скрипта, использующего Octokit.js. Скрипт импортирует Octokit и создает новый экземпляр Octokit. Если вы хотите пройти проверку подлинности с помощью GitHub App вместо personal access token, импортируйте и создайте App экземпляр вместо Octokit. Дополнительные сведения см. в разделе Проверка подлинности с помощью GitHub App.

Функция getChangedFiles получает все файлы, измененные для запроса на вытягивание. Функция commentIfDataFilesChanged вызывает функцию getChangedFiles . Если какой-либо из файлов, измененных запросом на вытягивание, включается /data/ в путь к файлу, функция будет комментировать запрос на вытягивание.

JavaScript
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,
    });

    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.`,
    });

    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});

Дальнейшие действия