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
Changes from 14 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
172 changes: 172 additions & 0 deletions src/pages/preview.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
import React, { useState, useEffect } from 'react';
import { navigate } from 'gatsby';

import PropTypes from 'prop-types';

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

const GITHUB_API_PULL_URL =
'https://api.github.com/repos/newrelic/newrelic-quickstarts/pulls';
josephgregoryii marked this conversation as resolved.
Show resolved Hide resolved

/**
* 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
**/
const iterateDirs = async (url) => {
const branchResponse = await fetch(url);
const branchResponseJSON = await branchResponse.json();
let fileAggregator = [];

for (const dirListing of branchResponseJSON) {
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
**/
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
**/
const determineContent = async ({ download_url, name: fileName }) => {
const rawFileResponse = await fetch(download_url);
const type = getFileType(fileName);
const content =
type === 'image'
? await rawFileResponse.blob()
: await rawFileResponse.text();

const rawContentObj = {
type,
fileName,
content,
};
return rawContentObj;
};

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

return rawContent;
};

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

if (prResponse.status !== 200 || !prResponse.ok) {
return null;
}

// Response containing files at root of PR
const prResponseJSON = await prResponse.json();
const branchSHA = prResponseJSON.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}`
);

const fileContent = await getRawContentOrBlob(fileAggregator);
return fileContent;
};

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

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) {
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 () => {
const fileContent = await getQuickstartFilesFromPR(
prNumber,
quickstartPath
);

// Error handling in the chance Github returns
// a non 200 status
if (fileContent === null) {
navigate('/');
return;
}
setContentFiles(fileContent);
};
fetchRawFiles();
}, []);

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

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

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

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

export default PreviewPage;