简介
可使用 用于 Copilot 指标的 REST API 终结点 查看用户采用 GitHub Copilot 的趋势。 在推出 GitHub Copilot 的过程中,查看这些趋势非常有用,可以检查用户是否使用了分配的许可证,了解用户使用了哪些功能,并评估公司启用计划对开发者的影响。
该 API 包括:
- 过去 28 天的数据
- 活动用户数和参与用户数
- 按语言和 IDE 细分
- 查看企业、组织或团队指标的选项
如果当前使用 GitHub Copilot 使用指标的 REST API 终结点,建议尽快迁移到 用于 Copilot 指标的 REST API 终结点。
本指南演示如何查询 API、存储数据,以及如何分析每周用户数的变化趋势。 本指南中的示例使用组织的终结点,但你可以根据需求调整示例。
关于终结点可用性
终结点可用于获取企业、组织、组织团队或企业团队的数据。
- 如果你是常规组织或企业的成员,并拥有 GitHub Copilot Business 或 GitHub Copilot Enterprise 订阅,可以使用适用于企业、组织或组织团队的终结点****。 除非你已在预览版中注册,否则无权访问企业团队。
- 如果你为 GitHub Copilot Business 使用了专用企业帐户(即无法创建组织的企业帐户),你可以使用适用于企业或企业团队的终结点****。
先决条件
- 必须为企业或组织启用 Copilot 指标 API 访问策略****。 请参阅“管理组织中的 Copilot 策略”或“管理企业中 Copilot 的策略和功能”。
- 要查询的组织、企业或团队必须有足够的活动 Copilot 用户。 仅当指定日有五名或更多名成员拥有活动 Copilot 许可证时,API 才会返回该日的结果****。
- 在此示例中,我们将创建一个 JavaScript 脚本,用于查询和分析数据。 要在本地运行此脚本,必须安装 Node.js,然后使用
npm install -g octokit
安装 Octokit.js SDK。
1.创建 personal access token
以我们的示例为例,要获取一个组织的指标,我们将创建一个带有 manage_billing:copilot
范围的 personal access token (classic)。 请参阅“管理个人访问令牌”。
如果使用另一个终结点,可能需要不同的范围。 请参阅“用于 Copilot 指标的 REST API 终结点”。
2.连接到 API
我们将从脚本中调用 API 并将响应保存为一个变量。 然后,我们可以在外部存储数据并分析数据的趋势。
以下示例使用适用于 JavaScript 的 Octokit 客户端。 可以使用其他方法调用 API,例如 cURL 或 GitHub CLI。
示例
在此示例中:
- 将 YOUR_TOKEN 替换为 personal access token。
- 将 YOUR_ORG 替换为组织名称,例如
octo-org
。
// Import Octokit import { Octokit } from "octokit"; // Set your token and organization const octokit = new Octokit({ auth: 'YOUR_TOKEN' }); const org = 'YOUR_ORG'; // Set other variables if required for the endpoint you're using /* const team = 'YOUR_TEAM'; const enterprise = 'YOUR_ENTERPRISE'; const entTeam = 'YOUR_ENTERPRISE_TEAM'; */ // Call the API async function orgMetrics() { const resp = await octokit.request(`GET /orgs/${org}/copilot/metrics`, { org: 'ORG', headers: { 'X-GitHub-Api-Version': '2022-11-28' } }); const copilotUsage = resp.data; console.log(copilotUsage); } // Call the function orgMetrics();
import { Octokit } from "octokit";
Import Octokit
const octokit = new Octokit({
auth: 'YOUR_TOKEN'
});
const org = 'YOUR_ORG';
Set your token and organization
/*
const team = 'YOUR_TEAM';
const enterprise = 'YOUR_ENTERPRISE';
const entTeam = 'YOUR_ENTERPRISE_TEAM';
*/
Set other variables if required for the endpoint you're using
async function orgMetrics() {
const resp = await octokit.request(`GET /orgs/${org}/copilot/metrics`, {
org: 'ORG',
headers: {
'X-GitHub-Api-Version': '2022-11-28'
}
});
const copilotUsage = resp.data;
console.log(copilotUsage);
}
Call the API
orgMetrics();
Call the function
// Import Octokit
import { Octokit } from "octokit";
// Set your token and organization
const octokit = new Octokit({
auth: 'YOUR_TOKEN'
});
const org = 'YOUR_ORG';
// Set other variables if required for the endpoint you're using
/*
const team = 'YOUR_TEAM';
const enterprise = 'YOUR_ENTERPRISE';
const entTeam = 'YOUR_ENTERPRISE_TEAM';
*/
// Call the API
async function orgMetrics() {
const resp = await octokit.request(`GET /orgs/${org}/copilot/metrics`, {
org: 'ORG',
headers: {
'X-GitHub-Api-Version': '2022-11-28'
}
});
const copilotUsage = resp.data;
console.log(copilotUsage);
}
// Call the function
orgMetrics();
在本地运行脚本
要在本地测试脚本,请将文件另存为 copilot.mjs
,然后运行 node copilot.mjs
。
Important
.mjs 文件类型非常重要****。 import { Octokit }
语句可能不适用于常规 .js
文件。
你应会在终端中看到类似以下的 JSON 数组输出。
[
{
date: '2024-11-07',
copilot_ide_chat: { editors: [Array], total_engaged_users: 14 },
total_active_users: 28,
copilot_dotcom_chat: { models: [Array], total_engaged_users: 4 },
total_engaged_users: 28,
copilot_dotcom_pull_requests: { total_engaged_users: 0 },
copilot_ide_code_completions: { editors: [Array], total_engaged_users: 22 }
},
...
3.存储数据
要分析超过 28 天的趋势,需要执行以下操作:
- 每天调用 API,可以使用 cron 作业或计划的 GitHub Actions 工作流。
- 在本地或使用数据库服务(如 MySQL)存储数据。
- 查询数据以确定随时间推移的趋势。
示例
在此示例中,我们会将数据保存到本地 .json
文件。 为此,我们将导入一些用于处理文件的模块,并更新 orgMetrics
函数以保存响应数据。
该函数会保存每天返回的新数据,而不会覆盖文件中的旧数据。
新步骤用粗体注明****。
// Import Octokit import { Octokit } from "octokit"; // **Import modules for working with files** import path from 'path'; import fs from 'fs'; import { fileURLToPath } from 'url'; import { dirname } from 'path'; // **Declare variables for working with files** const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); // Set your token and organization const octokit = new Octokit({ auth: 'YOUR_TOKEN' }); const org = 'YOUR_ORG'; // Call the API async function orgMetrics() { const resp = await octokit.request(`GET /orgs/${org}/copilot/metrics`, { org: 'ORG', headers: { 'X-GitHub-Api-Version': '2022-11-28' } }); const copilotUsage = resp.data; // **Define the path to the local file where data will be stored** const dataFilePath = path.join(__dirname, 'copilotMetricsData.json'); // **Read existing data from the file, if it exists** let existingData = []; if (fs.existsSync(dataFilePath)) { const fileContent = fs.readFileSync(dataFilePath, 'utf8'); existingData = JSON.parse(fileContent); } // **Filter out the new data that is not already in the existing data** const newData = copilotUsage.filter(entry => !existingData.some(existingEntry => existingEntry.date === entry.date)); // **Append new data to the existing data** if (newData.length > 0) { existingData = existingData.concat(newData); // **Save the updated data back to the file** fs.writeFileSync(dataFilePath, JSON.stringify(existingData, null, 2)); console.log(`Saved ${newData.length} new entries.`); } else { console.log('No new data to save.'); } } // Call the function orgMetrics();
import { Octokit } from "octokit";
Import Octokit
import path from 'path';
import fs from 'fs';
import { fileURLToPath } from 'url';
import { dirname } from 'path';
Import modules for working with files
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
Declare variables for working with files
const octokit = new Octokit({
auth: 'YOUR_TOKEN'
});
const org = 'YOUR_ORG';
Set your token and organization
async function orgMetrics() {
const resp = await octokit.request(`GET /orgs/${org}/copilot/metrics`, {
org: 'ORG',
headers: {
'X-GitHub-Api-Version': '2022-11-28'
}
});
const copilotUsage = resp.data;
Call the API
const dataFilePath = path.join(__dirname, 'copilotMetricsData.json');
Define the path to the local file where data will be stored
let existingData = [];
if (fs.existsSync(dataFilePath)) {
const fileContent = fs.readFileSync(dataFilePath, 'utf8');
existingData = JSON.parse(fileContent);
}
Read existing data from the file, if it exists
const newData = copilotUsage.filter(entry => !existingData.some(existingEntry => existingEntry.date === entry.date));
Filter out the new data that is not already in the existing data
if (newData.length > 0) {
existingData = existingData.concat(newData);
Append new data to the existing data
fs.writeFileSync(dataFilePath, JSON.stringify(existingData, null, 2));
console.log(`Saved ${newData.length} new entries.`);
} else {
console.log('No new data to save.');
}
}
Save the updated data back to the file
orgMetrics();
Call the function
// Import Octokit
import { Octokit } from "octokit";
// **Import modules for working with files**
import path from 'path';
import fs from 'fs';
import { fileURLToPath } from 'url';
import { dirname } from 'path';
// **Declare variables for working with files**
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Set your token and organization
const octokit = new Octokit({
auth: 'YOUR_TOKEN'
});
const org = 'YOUR_ORG';
// Call the API
async function orgMetrics() {
const resp = await octokit.request(`GET /orgs/${org}/copilot/metrics`, {
org: 'ORG',
headers: {
'X-GitHub-Api-Version': '2022-11-28'
}
});
const copilotUsage = resp.data;
// **Define the path to the local file where data will be stored**
const dataFilePath = path.join(__dirname, 'copilotMetricsData.json');
// **Read existing data from the file, if it exists**
let existingData = [];
if (fs.existsSync(dataFilePath)) {
const fileContent = fs.readFileSync(dataFilePath, 'utf8');
existingData = JSON.parse(fileContent);
}
// **Filter out the new data that is not already in the existing data**
const newData = copilotUsage.filter(entry => !existingData.some(existingEntry => existingEntry.date === entry.date));
// **Append new data to the existing data**
if (newData.length > 0) {
existingData = existingData.concat(newData);
// **Save the updated data back to the file**
fs.writeFileSync(dataFilePath, JSON.stringify(existingData, null, 2));
console.log(`Saved ${newData.length} new entries.`);
} else {
console.log('No new data to save.');
}
}
// Call the function
orgMetrics();
在本地运行脚本
使用 node copilot.mjs
运行脚本后,目录中应有一个名为 copilotMetricsData.json
的新文件。 该文件应包含 API 响应中的数据。
如果明天再次运行该脚本,它应该只会将新一天的数据保存到文件中。
4.分析趋势
可以使用 API 返回的数据来识别过去 28 天的趋势,或者如果你已经存储了之前的 API 调用数据,则可以分析更长时间的趋势。
示例
在以下示例中,我们更新了 orgMetrics
函数,以提取每周活动用户和参与用户的总数和平均数。 然后,我们可以使用这些数据来跟踪随时间变化的情况。 此示例使用直接从 API 返回的数据,并且不需要存储的数据。
新步骤用粗体注明****。
// Call the API async function orgMetrics() { const resp = await octokit.request(`GET /orgs/${org}/copilot/metrics`, { org: 'ORG', headers: { 'X-GitHub-Api-Version': '2022-11-28' } }); const copilotUsage = resp.data; // **Create an object to store data for each week** let userTrends ={ week1: { days:0, activeUsers:0, engagedUsers:0, }, week2: { days:0, activeUsers:0, engagedUsers:0, }, week3: { days:0, activeUsers:0, engagedUsers:0, }, week4: { days:0, activeUsers:0, engagedUsers:0, }, }; // **Iterate over the data** for (let i =0; i<copilotUsage.length; i++) { // **Determine the week number (1-4) based on the index** const week = Math.ceil((i+1)/7); // **Increment userTrends for the current week** userTrends[`week${week}`].days += 1; userTrends[`week${week}`].activeUsers += copilotUsage[i].total_active_users; userTrends[`week${week}`].engagedUsers += copilotUsage[i].total_engaged_users; } // **Calculate the average number of active and engaged users per day for each week, rounded to two decimal places** for (const week in userTrends) { userTrends[week].avgActiveUsers = (userTrends[week].activeUsers / userTrends[week].days).toFixed(2); userTrends[week].avgEngagedUsers = (userTrends[week].engagedUsers / userTrends[week].days).toFixed(2); } // Output to the console console.log(userTrends); }
async function orgMetrics() {
const resp = await octokit.request(`GET /orgs/${org}/copilot/metrics`, {
org: 'ORG',
headers: {
'X-GitHub-Api-Version': '2022-11-28'
}
});
const copilotUsage = resp.data;
Call the API
let userTrends ={
week1: {
days:0,
activeUsers:0,
engagedUsers:0,
},
week2: {
days:0,
activeUsers:0,
engagedUsers:0,
},
week3: {
days:0,
activeUsers:0,
engagedUsers:0,
},
week4: {
days:0,
activeUsers:0,
engagedUsers:0,
},
};
Create an object to store data for each week
for (let i =0; i<copilotUsage.length; i++) {
Iterate over the data
const week = Math.ceil((i+1)/7);
Determine the week number (1-4) based on the index
userTrends[`week${week}`].days += 1;
userTrends[`week${week}`].activeUsers += copilotUsage[i].total_active_users;
userTrends[`week${week}`].engagedUsers += copilotUsage[i].total_engaged_users;
}
Increment userTrends for the current week
for (const week in userTrends) {
userTrends[week].avgActiveUsers = (userTrends[week].activeUsers / userTrends[week].days).toFixed(2);
userTrends[week].avgEngagedUsers = (userTrends[week].engagedUsers / userTrends[week].days).toFixed(2);
}
Calculate the average number of active and engaged users per day for each week, rounded to two decimal places
console.log(userTrends);
}
Output to the console
// Call the API
async function orgMetrics() {
const resp = await octokit.request(`GET /orgs/${org}/copilot/metrics`, {
org: 'ORG',
headers: {
'X-GitHub-Api-Version': '2022-11-28'
}
});
const copilotUsage = resp.data;
// **Create an object to store data for each week**
let userTrends ={
week1: {
days:0,
activeUsers:0,
engagedUsers:0,
},
week2: {
days:0,
activeUsers:0,
engagedUsers:0,
},
week3: {
days:0,
activeUsers:0,
engagedUsers:0,
},
week4: {
days:0,
activeUsers:0,
engagedUsers:0,
},
};
// **Iterate over the data**
for (let i =0; i<copilotUsage.length; i++) {
// **Determine the week number (1-4) based on the index**
const week = Math.ceil((i+1)/7);
// **Increment userTrends for the current week**
userTrends[`week${week}`].days += 1;
userTrends[`week${week}`].activeUsers += copilotUsage[i].total_active_users;
userTrends[`week${week}`].engagedUsers += copilotUsage[i].total_engaged_users;
}
// **Calculate the average number of active and engaged users per day for each week, rounded to two decimal places**
for (const week in userTrends) {
userTrends[week].avgActiveUsers = (userTrends[week].activeUsers / userTrends[week].days).toFixed(2);
userTrends[week].avgEngagedUsers = (userTrends[week].engagedUsers / userTrends[week].days).toFixed(2);
}
// Output to the console
console.log(userTrends);
}
在本地运行脚本
使用 node copilot.mjs
运行脚本后,终端中应会显示如下所示的输出。
{
week1: {
days: 7,
activeUsers: 174,
engagedUsers: 174,
avgActiveUsers: '24.86',
avgEngagedUsers: '24.86'
},
week2: {
days: 7,
activeUsers: 160,
engagedUsers: 151,
avgActiveUsers: '22.86',
avgEngagedUsers: '21.57'
},
week3: {
days: 7,
activeUsers: 134,
engagedUsers: 123,
avgActiveUsers: '19.14',
avgEngagedUsers: '17.57'
},
week4: {
days: 6,
activeUsers: 143,
engagedUsers: 132,
avgActiveUsers: '23.83',
avgEngagedUsers: '22.00'
}
}