Skip to content
This repository has been archived by the owner on Dec 8, 2023. It is now read-only.

Fetch files with Github API #173

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
6d278b9
feat: get query parameters for preview
aswanson-nr May 11, 2022
853f875
chore: removed preview.js for prefered .jsx extension
josephgregoryii May 11, 2022
069d19c
chore: grab quickstart filepath and SHA
josephgregoryii May 12, 2022
6103abc
chore: comment for retreiving branch sha
josephgregoryii May 12, 2022
199515f
chore: get files from quickstart using Github API
josephgregoryii May 12, 2022
426977e
chore: remove unneeded hook
josephgregoryii May 12, 2022
31fc804
chore: update iterateDirs to a more functional paradigm
josephgregoryii May 12, 2022
e808e30
chore: refactor function name
josephgregoryii May 12, 2022
f97ab31
chore: add redirect to homepage
josephgregoryii May 12, 2022
c1ec63b
chore: create content object for parsing files
josephgregoryii May 13, 2022
d92111b
chore: JSDocs for functions
josephgregoryii May 13, 2022
a66f1b4
chore: refactor useEffect to set content in state
josephgregoryii May 13, 2022
5c75a51
chore: refactor useEffect for parsing
josephgregoryii May 13, 2022
d580dcb
chore: refactor some names for readability"
josephgregoryii May 16, 2022
4009d2a
refactor: supply download_url if type of file is an image
josephgregoryii May 16, 2022
a0b136b
chore: add in filePath to fileContent
josephgregoryii May 16, 2022
aded5c1
chore: organize files and helper functions
josephgregoryii May 16, 2022
d17fed2
chore: added newline to end of file
josephgregoryii May 16, 2022
9357a35
chore: move src/utils/helpers to src/utils/preview
josephgregoryii May 16, 2022
7e5e316
chore: add error handling in useEffect
josephgregoryii May 16, 2022
a3af140
chore: simplify returns on content
josephgregoryii May 16, 2022
b17e37f
chore: change console.error to console.log to keep logs in inspector
josephgregoryii May 16, 2022
692be57
chore: added error throwing
josephgregoryii May 16, 2022
cb29216
chore: remove async from function and update JSDoc
josephgregoryii May 16, 2022
a44b186
chore: additional console logging
josephgregoryii May 16, 2022
3c37250
chore: fix error message in iterateDirs
josephgregoryii May 16, 2022
3dc6165
chore: remove try catch block in helpers file
josephgregoryii May 16, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/data/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,11 @@ export const LOCALS = [
},
];


/* Quickstart Preview */

export const GITHUB_API_BASE_URL =
'https://api.github.com/repos/newrelic/newrelic-quickstarts/contents';

export const GITHUB_API_PULL_URL =
'https://api.github.com/repos/newrelic/newrelic-quickstarts/pulls';
70 changes: 70 additions & 0 deletions src/pages/preview.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import React, { useEffect, useState } from 'react';

import PropTypes from 'prop-types';
import { getQuickstartFilesFromPR } from '../utils/preview/fetchHelpers';
import { navigate } from 'gatsby';

const PreviewPage = ({ location }) => {
const [contentFiles, setContentFiles] = useState([]);

// TODO: Make this into a custom hook to reduce useEffect usage
josephgregoryii marked this conversation as resolved.
Show resolved Hide resolved
useEffect(() => {
// grab query parameters to determine if it is a local preview or
// PR preview
const urlParams = new URLSearchParams(location.search);
const prNumber = urlParams.get('pr');
const quickstartPath = urlParams.get('quickstart');
josephgregoryii marked this conversation as resolved.
Show resolved Hide resolved

// check to make sure query parameters are set
// otherwise, return home
if (!prNumber || !quickstartPath) {
console.log('Error: Missing query parameters');
if (!prNumber) {
console.log('prNumber');
}
if (!quickstartPath) {
console.log('quickstartPath');
}

navigate('/');
aswanson-nr marked this conversation as resolved.
Show resolved Hide resolved
return;
}

/*
* Async function to walk the file system in Github
* and set the content to a stateful variable.
**/
const fetchRawFiles = async () => {
try {
const fileContent = await getQuickstartFilesFromPR(
prNumber,
quickstartPath
);
setContentFiles(fileContent);
} catch (error) {
console.log('Error:', error.message);
navigate('/');
return;
}
};
fetchRawFiles();
}, []);

// To console log the results as part of AC
// TODO: Remove/refactor this in parsing implementation
useEffect(() => {
if (!contentFiles) {
return;
}

console.log(contentFiles);
}, [contentFiles]);

return <span>oh hai</span>;
};

PreviewPage.propTypes = {
location: PropTypes.object.isRequired,
};

export default PreviewPage;
115 changes: 115 additions & 0 deletions src/utils/preview/fetchHelpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { GITHUB_API_BASE_URL, GITHUB_API_PULL_URL } from '../../data/constants';

/**
* Recursive function to walk the file system in Github
* @param {String} url - Github API URL to walk the file system
* @returns {Array} array of files
**/
export const iterateDirs = async (url) => {
const response = await fetch(url);
if (response.status !== 200 || !response.ok) {
throw new Error(
`Response came back while walking the file tree with status ${response.status}\nFetched URL: ${url}`
);
}
const json = await response.json();
let fileAggregator = [];

for (const dirListing of json) {
if (dirListing.type === 'dir') {
const dirFiles = await iterateDirs(dirListing.url);
fileAggregator = [...fileAggregator, ...dirFiles];
} else {
fileAggregator = [...fileAggregator, dirListing];
}
}
return fileAggregator;
};

/**
* Function handles retreiving the type of file for parsing
* @param {String} fileName - file name to check
* @returns {String} - type of file
**/
export const getFileType = (fileName) => {
// Regex for different filetypes
const imageFileTypes = /^.*\.(jpg|jpeg|svg|png)$/i;
const yamlFileTypes = /^.*\.(yaml|yml)$/i;
const jsonFileType = /^.*\.(json)$/i;

if (fileName.match(imageFileTypes)) {
return 'image';
} else if (fileName.match(yamlFileTypes)) {
return 'yaml';
} else if (fileName.match(jsonFileType)) {
return 'json';
}
};

/**
* Function determines the type of content depending on type of image
* @param {Object} - Metadata object to parse
* @param {Object}.download_url - raw file URL
* @param {Object}.name - name of the file
* @returns {Object} - Object of file containing type, fileName, and content of
* file
**/
export const determineContent = async ({
download_url,
name: fileName,
path,
}) => {
const type = getFileType(fileName);
let rawFileResponse = null;

if (type !== 'image') {
rawFileResponse = await fetch(download_url);
}

// if the file is an image, we can supply the URL to the raw content
const content =
type === 'image' ? download_url : await rawFileResponse.text();

const filePath = path.split('quickstarts/').pop();

return {
type,
filePath,
fileName,
content,
};
};

/**
* Function grabs the raw content from files
* @param {Array} fileAggregator - array of Github metadata objects
* @returns {Promise<Array<Object>>} - array of objects containg raw content to parse
*
**/
export const getRawContent = (fileAggregator) => {
return Promise.all(fileAggregator.map(determineContent));
};

/**
* Async function handles fetching changed files in pull request from Github
**/
export const getQuickstartFilesFromPR = async (prNumber, quickstartPath) => {
// Hit the Github API for SHA that references the PR branch
const response = await fetch(`${GITHUB_API_PULL_URL}/${prNumber}`);

if (response.status !== 200 || !response.ok) {
throw new Error(
`Response from pull request came back with status ${response.status}\n`
);
}

// Response containing files at root of PR
const json = await response.json();
const branchSHA = json.head.sha;

// Recursively walk the Github API from the root of the quickstart
const fileAggregator = await iterateDirs(
`${GITHUB_API_BASE_URL}/quickstarts/${quickstartPath}?ref=${branchSHA}`
);
return getRawContent(fileAggregator);
};