text: const _ = require(`lodash`)
  const Promise = require(`bluebird`)
  const getpkgjson = require(`get-package-json-from-github`)
  const parseGHUrl = require(`parse-github-url`)
  const { GraphQLClient } = require(`@jamo/graphql-request`)
  const { loadYaml } = require(`../load-yaml`)
  const { starters: featuredStarters } = loadYaml(
    `src/data/ecosystem/featured-items.yaml`
  )
  const { getTemplate } = require(`../get-template`)
  
  if (
    process.env.gatsby_executing_command === `build` &&
    !process.env.GITHUB_API_TOKEN
  ) {
    throw new Error(
      `A GitHub token is required to build the site. Check the README.`
    )
  }
  
  // used to gather repo data on starters
  const githubApiClient = process.env.GITHUB_API_TOKEN
    ? new GraphQLClient(`https://api.github.com/graphql`, {
        headers: {
          authorization: `Bearer ${process.env.GITHUB_API_TOKEN}`,
        },
      })
    : null
  
  exports.createPages = async ({ graphql, actions, reporter }) => {
    const { createPage } = actions
  
    const starterTemplate = getTemplate(`template-starter-page`)
  
    const { data, errors } = await graphql(`
      query {
        allStartersYaml {
          nodes {
            id
            fields {
              starterShowcase {
                slug
              }
              hasScreenshot
            }
            url
            repo
          }
        }
      }
    `)
    if (errors) throw errors
  
    // Create starter pages.
    const starters = _.filter(data.allStartersYaml.nodes, node => {
      const slug = _.get(node, `fields.starterShowcase.slug`)
      if (!slug) {
        return null
      } else if (!_.get(node, `fields.hasScreenshot`)) {
        reporter.warn(
          `Starter showcase entry "${node.repo}" seems offline. Skipping.`
        )
        return null
      } else {
        return node
      }
    })
  
    starters.forEach(node => {
      createPage({
        path: `/starters${node.fields.starterShowcase.slug}`,
        component: starterTemplate,
        context: {
          slug: node.fields.starterShowcase.slug,
        },
      })
    })
  }
  
  const fetchGithubData = async ({ owner, repo, reporter }, retry = 0) =>
    githubApiClient
      .request(
        `
      query {
        repository(owner:"${owner}", name:"${repo}") {
          name
          stargazers {
            totalCount
          }
          createdAt
          pushedAt
          owner {
            login
          }
          nameWithOwner
        }
      }
    `
      )
      .catch(async err => {
        // we only try to do a fetch once because we want to track the new owner's username.
        if (retry > 0) {
          throw err
        }
  
        const githubUrl = `https://github.com/${owner}/${repo}`
        const { url } = await fetch(githubUrl, { method: `HEAD` })
        const { owner: newOwner, name: newRepo } = parseGHUrl(url)
  
        reporter.warn(
          `Starter showcase entry "${owner}/${repo}" was renamed to "${newOwner}/${newRepo}". Retrying....`
        )
  
        return fetchGithubData(
          { owner: newOwner, repo: newRepo, reporter },
          retry + 1
        )
      })
  
  exports.onCreateNode = ({ node, actions, getNode, reporter }) => {
    const { createNodeField, deleteNode } = actions
    if (node.internal.type === `StartersYaml` && node.repo) {
      // To develop on the starter showcase, you'll need a GitHub
      // personal access token. Check the `www` README for details.
      // Default fields are to avoid graphql errors.
      const { owner, name: repoStub } = parseGHUrl(node.repo)
  
      // mark if it's a featured starter
      if (featuredStarters.includes(`/${owner}/${repoStub}/`)) {
        createNodeField({ node, name: `featured`, value: true })
      }
  
      const defaultFields = {
        slug: `/${owner}/${repoStub}/`,
        stub: repoStub,
        name: ``,
        description: ``,
        stars: 0,
        lastUpdated: ``,
        owner: ``,
        githubFullName: ``,
        gatsbyMajorVersion: [[`no data`, `0`]],
        allDependencies: [[`no data`, `0`]],
        gatsbyDependencies: [[`no data`, `0`]],
        miscDependencies: [[`no data`, `0`]],
      }
  
      // determine if screenshot is available
      const screenshotNode = node.children
        .map(childID => getNode(childID))
        .find(node => node.internal.type === `Screenshot`)
  
      createNodeField({ node, name: `hasScreenshot`, value: !!screenshotNode })
  
      if (!process.env.GITHUB_API_TOKEN) {
        createNodeField({
          node,
          name: `starterShowcase`,
          value: {
            ...defaultFields,
          },
        })
      } else {
        Promise.all([
          getpkgjson(node.repo),
          fetchGithubData({ owner, repo: repoStub, reporter }),
        ])
          .then(results => {
            const [pkgjson, githubData] = results
            const {
              stargazers: { totalCount: stars },
              pushedAt: lastUpdated,
              owner: { login: owner },
              name,
              nameWithOwner: githubFullName,
            } = githubData.repository
  
            const { dependencies = [], devDependencies = [] } = pkgjson
            const allDependencies = Object.entries(dependencies).concat(
              Object.entries(devDependencies)
            )
  
            const gatsbyMajorVersion = allDependencies
              .filter(([key]) => key === `gatsby`)
              .map(version => {
                const [gatsby, versionNum] = version
                if (versionNum === `latest` || versionNum === `next`) {
                  return [gatsby, `2`]
                }
                return [gatsby, versionNum.replace(/\D/g, ``).charAt(0)]
              })
  
            // If a new field is added here, make sure a corresponding
            // change is made to "defaultFields" to not break DX
            const starterShowcaseFields = {
              slug: `/${owner}/${repoStub}/`,
              stub: repoStub,
              name,
              description: pkgjson.description,
              stars,
              lastUpdated,
              owner,
              githubFullName,
              gatsbyMajorVersion,
              allDependencies,
              gatsbyDependencies: allDependencies
                .filter(
                  ([key]) => ![`gatsby-cli`, `gatsby-link`].includes(key) // remove stuff everyone has
                )
                .filter(([key]) => key.includes(`gatsby`)),
              miscDependencies: allDependencies.filter(
                ([key]) => !key.includes(`gatsby`)
              ),
            }
            createNodeField({
              node,
              name: `starterShowcase`,
              value: starterShowcaseFields,
            })
          })
          .catch(err => {
            reporter.warn(
              `Error getting repo data for starter "${repoStub}":\n
              ${err.message}`
            )
            deleteNode(node)
          })
      }
    }
  }
  