| 
 | 1 | +/*  | 
 | 2 | + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one  | 
 | 3 | + * or more contributor license agreements. Licensed under the "Elastic License  | 
 | 4 | + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side  | 
 | 5 | + * Public License v 1"; you may not use this file except in compliance with, at  | 
 | 6 | + * your election, the "Elastic License 2.0", the "GNU Affero General Public  | 
 | 7 | + * License v3.0 only", or the "Server Side Public License, v 1".  | 
 | 8 | + */  | 
 | 9 | + | 
 | 10 | +import { promisify } from 'util';  | 
 | 11 | +import { exec } from 'child_process';  | 
 | 12 | +import { Octokit } from '@octokit/rest';  | 
 | 13 | +import type { TelemetrySchemaObject } from '../../schema_ftr_validations/schema_to_config_schema';  | 
 | 14 | + | 
 | 15 | +const execAsync = promisify(exec);  | 
 | 16 | +let octokit: null | Octokit;  | 
 | 17 | +let changedFilesCache: null | string[];  | 
 | 18 | + | 
 | 19 | +function getOctokit() {  | 
 | 20 | +  if (!process.env.GITHUB_TOKEN) {  | 
 | 21 | +    throw new Error('Missing environment variable: GITHUB_TOKEN');  | 
 | 22 | +  }  | 
 | 23 | +  octokit =  | 
 | 24 | +    octokit ??  | 
 | 25 | +    new Octokit({  | 
 | 26 | +      auth: process.env.GITHUB_TOKEN,  | 
 | 27 | +    });  | 
 | 28 | + | 
 | 29 | +  return octokit;  | 
 | 30 | +}  | 
 | 31 | + | 
 | 32 | +async function fetchPrChangedFiles(  | 
 | 33 | +  owner = process.env.GITHUB_PR_BASE_OWNER,  | 
 | 34 | +  repo = process.env.GITHUB_PR_BASE_REPO,  | 
 | 35 | +  prNumber: undefined | string | number = process.env.GITHUB_PR_NUMBER  | 
 | 36 | +): Promise<string[]> {  | 
 | 37 | +  if (!owner || !repo || !prNumber) {  | 
 | 38 | +    throw Error(  | 
 | 39 | +      "Couldn't retrieve Github PR info from environment variables in order to retrieve PR changes"  | 
 | 40 | +    );  | 
 | 41 | +  }  | 
 | 42 | + | 
 | 43 | +  const github = getOctokit();  | 
 | 44 | +  const files = await github.paginate(github.pulls.listFiles, {  | 
 | 45 | +    owner,  | 
 | 46 | +    repo,  | 
 | 47 | +    pull_number: typeof prNumber === 'number' ? prNumber : parseInt(prNumber, 10),  | 
 | 48 | +    per_page: 100,  | 
 | 49 | +  });  | 
 | 50 | + | 
 | 51 | +  return files.map(({ filename }) => filename);  | 
 | 52 | +}  | 
 | 53 | + | 
 | 54 | +async function getPrChangedFiles(): Promise<string[]> {  | 
 | 55 | +  changedFilesCache = changedFilesCache || (await fetchPrChangedFiles());  | 
 | 56 | +  return changedFilesCache;  | 
 | 57 | +}  | 
 | 58 | + | 
 | 59 | +async function getUncommitedChanges(): Promise<string[]> {  | 
 | 60 | +  const { stdout } = await execAsync(  | 
 | 61 | +    `git status --porcelain -- . ':!:config/node.options' ':!config/kibana.yml'`,  | 
 | 62 | +    { maxBuffer: 1024 * 1024 * 128 }  | 
 | 63 | +  );  | 
 | 64 | + | 
 | 65 | +  return stdout  | 
 | 66 | +    .split('\n')  | 
 | 67 | +    .map((line) =>  | 
 | 68 | +      line  | 
 | 69 | +        .replace('?? ', '')  | 
 | 70 | +        .replace('A ', '')  | 
 | 71 | +        .replace('M ', '')  | 
 | 72 | +        .replace('D ', '')  | 
 | 73 | +        .replace('R ', '')  | 
 | 74 | +        .trim()  | 
 | 75 | +    );  | 
 | 76 | +}  | 
 | 77 | + | 
 | 78 | +export async function isTelemetrySchemaModified({ path }: { path: string }): Promise<boolean> {  | 
 | 79 | +  const modifiedFiles = await getUncommitedChanges();  | 
 | 80 | +  if (modifiedFiles.includes(path)) {  | 
 | 81 | +    return true;  | 
 | 82 | +  }  | 
 | 83 | + | 
 | 84 | +  const prChanges = await getPrChangedFiles();  | 
 | 85 | +  return prChanges.length >= 3000 || prChanges.includes(path);  | 
 | 86 | +}  | 
 | 87 | + | 
 | 88 | +export async function fetchTelemetrySchemaAtRevision({  | 
 | 89 | +  path,  | 
 | 90 | +  ref,  | 
 | 91 | +}: {  | 
 | 92 | +  path: string;  | 
 | 93 | +  ref: string;  | 
 | 94 | +}): Promise<TelemetrySchemaObject> {  | 
 | 95 | +  const github = getOctokit();  | 
 | 96 | +  const res = await github.rest.repos.getContent({  | 
 | 97 | +    mediaType: {  | 
 | 98 | +      format: 'application/vnd.github.VERSION.raw',  | 
 | 99 | +    },  | 
 | 100 | +    owner: 'elastic',  | 
 | 101 | +    repo: 'kibana',  | 
 | 102 | +    path,  | 
 | 103 | +    ref,  | 
 | 104 | +  });  | 
 | 105 | + | 
 | 106 | +  if (!Array.isArray(res.data) && res.data.type === 'file') {  | 
 | 107 | +    return JSON.parse(Buffer.from(res.data.content!, 'base64').toString()) as TelemetrySchemaObject;  | 
 | 108 | +  } else {  | 
 | 109 | +    throw new Error(`Error retrieving contents of ${path}, unexpected response data.`);  | 
 | 110 | +  }  | 
 | 111 | +}  | 
0 commit comments