Skip to content

Commit

Permalink
Merge pull request #493 from makerdao/develop
Browse files Browse the repository at this point in the history
v0.6.0 - Peanut Wandering Whistling-Duck - (Dendrocygna arcuata)
  • Loading branch information
b-pmcg authored Jun 27, 2022
2 parents f592e14 + 9961b5b commit 2e85e2e
Show file tree
Hide file tree
Showing 142 changed files with 2,076 additions and 909 deletions.
2 changes: 1 addition & 1 deletion .env.sample
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
INFURA_KEY=xxxx
USE_FS_CACHE=true
USE_CACHE=true
GITHUB_TOKEN=xxxx
NEXT_PUBLIC_MIXPANEL_DEV=xxx
NEXT_PUBLIC_MIXPANEL_PROD=xxx
Expand Down
5 changes: 3 additions & 2 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,13 @@
"react/react-in-jsx-scope": 0,
"testing-library/await-async-query": "error",
"testing-library/no-await-sync-query": "error",
"testing-library/no-debug": "warn",
"testing-library/no-debug": "off",
"testing-library/no-dom-import": "off",
"jest-dom/prefer-checked": "error",
"jest-dom/prefer-enabled-disabled": "error",
"jest-dom/prefer-required": "error",
"jest-dom/prefer-to-have-attribute": "error"
"jest-dom/prefer-to-have-attribute": "error",
"no-debugger":"off"
},
"settings": {
"react": {
Expand Down
54 changes: 8 additions & 46 deletions .github/workflows/main.yml → .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
@@ -1,51 +1,11 @@
name: CI Tests

on: [push]
name: E2E Tests

on:
push:
branches:
- master
- develop
jobs:
unit:
runs-on: ubuntu-latest
container: makerdaodux/cypress-dapptools-node-14:latest
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
USE_FS_CACHE: 1
steps:
- name: Checkout
uses: actions/checkout@v2

- name: Install node packages
run: yarn

- name: Cypress install
uses: cypress-io/github-action@v2
with:
# Disable running of tests within install job
runTests: false
build: yarn build
install: false

- run: yarn lint

- run: yarn test:ci

- name: Codecov
run: |
yarn add --dev codecov
./node_modules/.bin/codecov
# Store built next data
# - name: Save build folder
# uses: actions/upload-artifact@v2
# with:
# name: build
# if-no-files-found: error
# path: |
# .next
# public

ui-chrome-tests:
runs-on: ubuntu-latest
container: makerdaodux/cypress-dapptools-node-14:latest
Expand All @@ -60,6 +20,8 @@ jobs:
ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }}
POCKET_KEY: ${{ secrets.POCKET_KEY }}
ALCHEMY_KEY: ${{ secrets.ALCHEMY_KEY }}
REDIS_URL: ${{ secrets.REDIS_URL }}
USE_CACHE: true

steps:
- name: Checkout
Expand Down
48 changes: 48 additions & 0 deletions .github/workflows/unit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Unit Tests

on: [push]

jobs:
unit:
runs-on: ubuntu-latest
container: makerdaodux/cypress-dapptools-node-14:latest
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
USE_CACHE: false
REDIS_URL: ${{ secrets.REDIS_URL }}
steps:
- name: Checkout
uses: actions/checkout@v2

- name: Install node packages
run: yarn

- name: Cypress install
uses: cypress-io/github-action@v2
with:
# Disable running of tests within install job
runTests: false
build: yarn build
install: false

- run: yarn lint

- run: yarn test:ci

- name: Codecov
run: |
yarn add --dev codecov
./node_modules/.bin/codecov
# Store built next data
# - name: Save build folder
# uses: actions/upload-artifact@v2
# with:
# name: build
# if-no-files-found: error
# path: |
# .next
# public
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<h1 align="center" style="margin-top: 1em; margin-bottom: 3em;">
<p><a href="https://vote.makerdao.com/"><img alt="maker logo" src="./maker-logo.png" alt="vote.makerdao.com" width="125"></a></p>
<p> <img src="https://media.giphy.com/media/hvRJCLFzcasrR4ia7z/giphy.gif" alt="Waving Hand" width="25px"> Maker Governance Portal</p>
<p>Maker Governance Portal</p>
</h1>

An open source interface for Dai Credit System governance
Expand Down Expand Up @@ -29,7 +29,7 @@ _Requires node version >= v11.15.0_
4. Set `TRACING_RPC_NODE` to an ethereum RPC parity node with tracing enabled
5. Set `MONGODB_URI` to a full mongodb uri (ex: `mongodb+srv://...`)
6. Set `MONGODB_COMMENTS_DB` the mongodb db name to be used for vote comments
7. Set `USE_FS_CACHE` to true if you want to use file system cache
7. Set `USE_CACHE` to true if you want to use cache, if `REDIS_URL` is set it will use REDIS otherwhise filesystem cache
8. Set `GITHUB_TOKEN` to fetch delegates information and executive proposals from GitHub (optionally set `GITHUB_TOKEN_2` and `GITHUB_TOKEN_3`)
9. Set `NEXT_PUBLIC_MIXPANEL_DEV` to the valid Mixpanel dev environment API key
10. Set `NEXT_PUBLIC_MIXPANEL_PROD` to the valid Mixpanel prod environment API key
Expand Down
4 changes: 4 additions & 0 deletions __tests__/setup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { mockIntersectionObserver } from '../__tests__/helpers';
import { getENS } from 'modules/web3/helpers/ens';
import { useWeb3React } from '@web3-react/core';
import { ethers } from 'ethers';
import { config } from 'lib/config';

// Node/Jest don't have 'fetch' bc it's injected by next.js into global
// requiring next here applies the polyfills for fetch needed for some tests
Expand Down Expand Up @@ -57,4 +58,7 @@ beforeAll(async () => {

// Mock ens calls
(getENS as jest.Mock).mockReturnValue('');

config.REDIS_URL = '';
config.USE_CACHE = 'false';
});
2 changes: 1 addition & 1 deletion cypress/integration/polling.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ describe('/polling page', async () => {
it('Filters by ended polls', () => {
visitPage('/polling');
setAccount(TEST_ACCOUNTS.normal, () => {
cy.get('[data-testid="poll-filters-dropdown"]').click();
cy.get('[data-testid="poll-filters-status"]').click();
cy.get('[data-testid="checkbox-show-polls-ended"]').click();

cy.get('[data-testid="poll-overview-card"]').should('have.length', 3);
Expand Down
32 changes: 0 additions & 32 deletions cypress/support/commons/token.helpers.ts

This file was deleted.

40 changes: 40 additions & 0 deletions lib/__tests__/formatValue.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { parseUnits } from 'ethers/lib/utils';
import { formatValue } from 'lib/string';

describe('Format value for numbers', () => {
it('Should round down numbers', () => {
const result = formatValue(parseUnits('0.00132'), undefined, undefined, true, true);

expect(result).toEqual('≈0.00');
});

it('should not round down if disabled', () => {
const result = formatValue(parseUnits('0.00132'), undefined, 3);

expect(result).toEqual('0.001');
});

it('should not display commas if not stated', () => {
const result = formatValue(parseUnits('10222.0132'), undefined, undefined, false, true);

expect(result).toEqual('10222');
});

it('should not show decimals for a number bigger than 999', () => {
const result = formatValue(parseUnits('10222.013222'));

expect(result).toEqual('10,222');
});

it('should show 2 decimals for number less than 999', () => {
const result = formatValue(parseUnits('222.013222'));

expect(result).toEqual('222.01');
});

it('should show 5 decimals for number less than 999 if specified to 5', () => {
const result = formatValue(parseUnits('222.013222'), undefined, 5);

expect(result).toEqual('222.01322');
});
});
135 changes: 135 additions & 0 deletions lib/cache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import fs from 'fs';
import os from 'os';
import { DEFAULT_NETWORK, SupportedNetworks } from 'modules/web3/constants/networks';
import { config } from 'lib/config';
import Redis from 'ioredis';
import packageJSON from '../package.json';
import logger from './logger';

const redis = config.REDIS_URL
? new Redis(config.REDIS_URL, {
connectTimeout: 10000
})
: null;

const oneHourInMS = 60 * 60 * 1000;

// Mem cache does not work on local instances of nextjs because nextjs creates clean memory states each time.
const memoryCache = {};

function getFilePath(name: string, network: string): string {
const date = new Date().toISOString().substring(0, 10);

return `${os.tmpdir()}/gov-portal-version-${packageJSON.version}-${network}-${name}-${date}`;
}

export const cacheDel = (path: string): void => {
const isRedisCache = !!config.REDIS_URL;

if (isRedisCache && redis) {
redis?.del(path);
} else {
try {
logger.debug('cacheDel: ', path);
memoryCache[path] = null;
fs.unlinkSync(path);
} catch (e) {
logger.error(`cacheDel: ${e.message}`);
}
}
};

export const cacheGet = async (
name: string,
network?: SupportedNetworks,
expiryMs?: number
): Promise<any> => {
if (!config.USE_CACHE || config.USE_CACHE === 'false') {
return Promise.resolve(null);
}

const isRedisCache = !!config.REDIS_URL;

try {
const currentNetwork = network || DEFAULT_NETWORK.network;
const path = getFilePath(name, currentNetwork);

if (isRedisCache && redis) {
// Get redis data if it exists
const cachedData = await redis.get(path);
logger.debug(`Redis cache get for ${path}`);
return cachedData;
} else {
// If fs does not exist as a module, return null (TODO: This shouldn't happen, consider removing this check)
if (Object.keys(fs).length === 0) return null;
const memCached = memoryCache[path];

if (memCached) {
logger.debug(`mem cache hit: ${path}`);

if (memCached.expiry && memCached.expiry < Date.now()) {
logger.debug('mem cache expired');
cacheDel(path);
return null;
}

return memoryCache[path].data;
}

if (fs.existsSync(path)) {
// In nextjs serverless instances of API functions sometimes reset their in memory cache (they are different instances)
// In order to have an expiry date we can also check the last time this file was accessed or it was created. This conditions having to pass the expiryMs on the cacheGet too
const { birthtime } = fs.statSync(path);

if (expiryMs && birthtime && birthtime.getTime() < Date.now() + expiryMs) {
cacheDel(path);
return null;
}

logger.debug(`fs cache hit: ${path}`);
return fs.readFileSync(path).toString();
}
}
} catch (e) {
logger.error(`CacheGet: Error getting cached data, ${name} - ${network}`, e.message);
return null;
}
};

export const cacheSet = (
name: string,
data: string,
network?: SupportedNetworks,
expiryMs = oneHourInMS
): void => {
if (!config.USE_CACHE || config.USE_CACHE === 'false') {
return;
}

const isRedisCache = !!config.REDIS_URL;
const currentNetwork = network || DEFAULT_NETWORK.network;

const path = getFilePath(name, currentNetwork);

try {
if (isRedisCache && redis) {
// If redis cache is enabled, store in redis, with a TTL in seconds
const expirySeconds = Math.round(expiryMs / 1000);
logger.debug(`Redis cache set for ${path}, with TTL ${expirySeconds} seconds`);

redis.set(path, data, 'EX', expirySeconds);
} else {
// File cache
if (Object.keys(fs).length === 0) return;

fs.writeFileSync(path, data);

memoryCache[path] = {
expiry: expiryMs ? Date.now() + expiryMs : null,
data
};
}
} catch (e) {
logger.error(`CacheSet: Error storing data in cache, ${name} - ${network}`, e.message);
}
};
Loading

1 comment on commit 2e85e2e

@vercel
Copy link

@vercel vercel bot commented on 2e85e2e Jun 27, 2022

Choose a reason for hiding this comment

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

Please sign in to comment.