Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,4 @@ bundle-stats.json
# Generated JSON
src/generated/
plugins/source-terasology-modules/data.json
plugins/source-terasology-engine/data.json
6 changes: 6 additions & 0 deletions gatsby-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,12 @@ module.exports = {
accessToken: process.env.GITHUB_TOKEN,
},
},
{
resolve: "source-terasology-engine",
options: {
accessToken: process.env.GITHUB_TOKEN,
},
},
{
resolve: "gatsby-plugin-nprogress",
options: {
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"private": "true",
"workspaces": [
".",
"plugins/source-terasology-modules"
"plugins/source-terasology-modules",
"plugins/source-terasology-engine"
],
"author": "The Terasology Foundation",
"dependencies": {
Expand Down
51 changes: 51 additions & 0 deletions plugins/source-terasology-engine/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# source-terasology-engine

Custom [Gatsby Source Plugin](https://www.gatsbyjs.com/docs/how-to/plugins-and-themes/creating-a-source-plugin/) to fetch enriched information for the [Terasology Engine](https://github.com/MovingBlocks/Terasology) from GitHub.

## Install

This is a local plugin that is automatically loaded from the `plugins/` folder.

## Configuration

```js
// in gatsby-config.js
module.exports = {
plugins: [
//...
{
resolve: "source-terasology-engine",
options: {
accessToken: `<your GitHub access token>`
}
}
]
}
```

Use [Environment Variables](https://www.gatsbyjs.com/docs/how-to/local-development/environment-variables/) to avoid exposing secrets.

## Usage

```graphql
query Engine {
allTerasologyEngine {
issues{
nodes {
id
title
author {
login
}
labels {
nodes {
name
}
}
updatedAt
url
}
}
}
}
```
103 changes: 103 additions & 0 deletions plugins/source-terasology-engine/gatsby-node.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
const { graphql } = require("@octokit/graphql");
const { DateTime } = require("luxon");
const fs = require("fs");

const PLUGIN_NAME = "source-terasology-engine";

const query = `
query Engine {
organization(login: "MovingBlocks") {
repository(name: "Terasology") {
issues(first: 10, filterBy: {labels: "Good First Issue", states: OPEN}, orderBy: {field: UPDATED_AT, direction: DESC}) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we only fetching the first ten issues here? This seems to be quite a few, and even if we fetch more we can still decide to only display a few on the page...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's change this to fetching all of them with respective pagination in a follow-up PR

nodes {
id
title
author {
login
}
labels(first: 10) {
nodes {
name
}
}
updatedAt
url
}
Comment on lines +12 to +25
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is (naturally) the same structure as we use for fetching issues for modules. We could use GraphQL Fragments to make sure they always have the same structure.

Which makes me wonder whether this should actually be a separate plugin, or whether we just merge it with the other one for simplicity (and easier sharing of code and query fragments....)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's consider doing that in a follow-up PR 👍

}
}
}
}
`;

exports.onPreInit = ({ reporter }) =>
reporter.verbose("Loaded source-terasology-engine");

exports.sourceNodes = async (
{
actions: { createNode },
createContentDigest,
createNodeId,
reporter,
cache,
},
{ accessToken }
) => {
const gql = graphql.defaults({
headers: {
authorization: `token ${accessToken}`,
},
});

const lastFetchedKey = "terasology-engine-last-fetched";
const dataKey = "terasology-engine-data";
Comment on lines +51 to +52
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the caches are scoped for the plugins individually, so prefixing is not strictly required. This applies to the other plugin as well, so that's rather a note to self here...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

guess if we plan to merge the plugins anyway, we can make use of the prefix for scoping then, so keeping it for now.


const now = DateTime.utc();
const lastFetched = DateTime.fromISO(await cache.get(lastFetchedKey), {
zone: "utc",
});

let engine = {};

// Temporary hack to avoid fetching data from GitHub during local testing.
// Un-/comment as needed after changing the query.
if (fs.existsSync(`${__dirname}/data.json`)) {
// engine = JSON.parse(fs.readFileSync(`${__dirname}/data.json`));
}

if (lastFetched.plus({ hours: 12 }) > now) {
reporter.info(
`[${PLUGIN_NAME}] Loading Terasology engine info from cache ...`
);
engine = JSON.parse(await cache.get(dataKey));
} else {
reporter.info(
`[${PLUGIN_NAME}] Fetching Terasology engine info from GitHub ...`
);

const { organization } = await gql(query);
engine = organization.repository;

await cache.set(dataKey, JSON.stringify(engine));
await cache.set(lastFetchedKey, now.toISO());

fs.writeFileSync(`${__dirname}/data.json`, JSON.stringify(engine, null, 2));
}

reporter.success(`[${PLUGIN_NAME}] Loaded Terasology engine info.`);

const node = {
id: createNodeId(`TerasologyEngine`),
issues: engine.issues,
parent: "__SOURCE__",
children: [],
internal: {
type: "TerasologyEngine",
},
};

node.internal.contentDigest = createContentDigest(node);

createNode(node);

reporter.success(`[${PLUGIN_NAME}] Created node for Terasology engine.`);
};
1 change: 1 addition & 0 deletions plugins/source-terasology-engine/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// noop
21 changes: 21 additions & 0 deletions plugins/source-terasology-engine/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "source-terasology-engine",
"version": "0.0.1",
"private": true,
"description": "A Gatsby source plugin to fetch Terasology engine information.",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "echo \"No build script setup\""
},
"keywords": [
"gatsby",
"gatsby-plugin"
],
"author": "The Terasology Foundation <terasology@gmail.com>",
"dependencies": {
"@octokit/graphql": "^5.0.4",
"gatsby-source-filesystem": "^5.3.1",
"luxon": "^3.2.0"
}
}