feat: get list of spaces filtered by followers count from snapshot.org (#5)

* chore: update .eslintignore

* feat:test: get spaces by min of followers

* lint

* fix: do filter using GitHub prop

This prop is not available in response from explore api endpoint.
Need to use a graphql query

* Add script

* format
This commit is contained in:
r1oga
2023-01-09 16:03:28 +01:00
committed by GitHub
parent b5e6856fb3
commit 2cd4575112
14 changed files with 148 additions and 70 deletions

View File

@@ -1,10 +1,7 @@
node_modules
package-lock.json
pnpm-lock.yaml
yarn.lock
# build dirs
build
dist
# Jest

View File

@@ -1,40 +1,14 @@
<div style='display: flex'>
<img alt='ts icon' width='50' src='https://raw.githubusercontent.com/devicons/devicon/master/icons/typescript/typescript-original.svg'/>
<span style='font-weight: bold'>&nbsp;&nbsp<strong>PROJECT TEMPLATE</strong></span>
</div>
<br/>
# GH Groups
![Code Quality GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/r1oga/ts-template/code-quality.yaml?branch=main&label=Code%20Quality) ![Security Check GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/r1oga/ts-template/snyk.yaml?branch=main&label=Security%20%28Snyk%29)
[![Coverage Status](https://coveralls.io/repos/github/r1oga/ts-template/badge.svg?branch=main)](https://coveralls.io/github/r1oga/ts-template?branch=main)
[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier) [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com)
[![nps friendly](https://img.shields.io/badge/nps-friendly-blue.svg?style=flat-square)](https://github.com/sezna/nps)
Get list of GH users who contributed to the GitHub org of a given group of DAOs.
| Feature | With | Configuration File |
| ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Typings | [Typescript](https://www.typescriptlang.org/) | [tsconfig.json](./tsconfig.json) |
| Scripts | [Nps](https://github.com/sezna/nps) | [package-scripts.yaml](./package-scripts.yaml) |
| Testing | [Jest](https://jestjs.io/), [ts-jest](https://kulshekhar.github.io/ts-jest/) | [jest.config.ts](test/jest.config.ts) |
| Coverage reports | [Coveralls](https://coveralls.io/) | [Coveralls GitHub Action](https://github.com/marketplace/actions/coveralls-github-action) |
| Linting | [Eslint](https://eslint.org/) | [.eslintrc.yaml](./.eslintrc.yaml) |
| Formatting | [Prettier](https://prettier.io/) | [.prettierrc.yaml](./.prettierrc.yaml) |
| Continuous Integration | [GitHub Workflow](https://docs.github.com/en/actions/using-workflows) | [.github/workflows](./.github/workflows) |
| Import aliases | [Typescript paths](https://www.typescriptlang.org/tsconfig#paths), [module-alias](https://github.com/ilearnio/module-alias) | [tsconfig.json](https://github.com/r1oga/ts-template/blob/5d6983a6d28429b9dd256edf40bad5ee48c33d9c/tsconfig.json#L26), [package.json](https://github.com/r1oga/ts-template/blob/5d6983a6d28429b9dd256edf40bad5ee48c33d9c/package.json#L9) |
| Rollup exports | [Barrelsby](https://github.com/bencoveney/barrelsby) | [.barrelsby.json](./.barrelsby.json) |
| Containerization | [Docker](https://www.docker.com/) | [Dockerfile](./Dockerfile), [docker-compose.yaml](./docker-compose.yaml) |
| Pre-commit hook (linting, formatting) | [Husky](https://typicode.github.io/husky), [lint-staged](https://github.com/okonet/lint-staged) | [pre-commit](./.husky/pre-commit), [.lintstagedrc.yaml](./.lintstagedrc.yaml) |
| Security Checks | [Snyk](https://snyk.io/) | [snyk.yaml](./.github/workflows/snyk.yaml) |
## Usage
## Start
- script: `nps 'fetch -m <min followers amount> -s <group size>`
- node
Node
```
import { getSpaces} from './src/getSpaces'
```commandline
npm run setup
nps start
```
Docker
```commandline
docker compose up
```
const spaces = await getSpaces({min, size})()
```

View File

@@ -16,6 +16,10 @@ scripts:
script: nps lint.fix format.fix
hiddenFromHelp: Fix linting and formatting errors
fetch:
script: tsnd --cls --respawn --transpile-only scripts
description: Fetch query results (-m <min> -s <size>)
format:
default:
script: nps 'test.once --selectProjects prettier --coverage false'

View File

@@ -14,6 +14,7 @@
"@r1oga/eslint-config": "^1.1.6",
"@r1oga/prettier-config": "^1.1.8",
"@types/jest": "^29.2.3",
"@types/yargs": "^17.0.19",
"concurrently": "^7.6.0",
"husky": "^8.0.2",
"is-ci": "^3.0.1",
@@ -33,7 +34,8 @@
"ts-node-dev": "^2.0.0",
"tsconfig-paths": "^4.1.0",
"tslib": "^2.4.1",
"typescript": "^4.9.4"
"typescript": "^4.9.4",
"yargs": "^17.6.2"
},
"engines": {
"node": ">=18"

10
pnpm-lock.yaml generated
View File

@@ -4,6 +4,7 @@ specifiers:
'@r1oga/eslint-config': ^1.1.6
'@r1oga/prettier-config': ^1.1.8
'@types/jest': ^29.2.3
'@types/yargs': ^17.0.19
concurrently: ^7.6.0
husky: ^8.0.2
is-ci: ^3.0.1
@@ -24,11 +25,13 @@ specifiers:
tsconfig-paths: ^4.1.0
tslib: ^2.4.1
typescript: ^4.9.4
yargs: ^17.6.2
devDependencies:
'@r1oga/eslint-config': 1.1.6_bh7fyjwf3qvjuxqkkpsm2qjvfa
'@r1oga/prettier-config': 1.1.8_prettier@2.8.1
'@types/jest': 29.2.3
'@types/yargs': 17.0.19
concurrently: 7.6.0
husky: 8.0.2
is-ci: 3.0.1
@@ -49,6 +52,7 @@ devDependencies:
tsconfig-paths: 4.1.0
tslib: 2.4.1
typescript: 4.9.4
yargs: 17.6.2
packages:
@@ -767,7 +771,7 @@ packages:
'@types/istanbul-lib-coverage': 2.0.4
'@types/istanbul-reports': 3.0.1
'@types/node': 18.11.9
'@types/yargs': 17.0.13
'@types/yargs': 17.0.19
chalk: 4.1.2
dev: true
@@ -1036,8 +1040,8 @@ packages:
'@types/yargs-parser': 21.0.0
dev: true
/@types/yargs/17.0.13:
resolution: {integrity: sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==}
/@types/yargs/17.0.19:
resolution: {integrity: sha512-cAx3qamwaYX9R0fzOIZAlFpo4A+1uBVCxqpKz9D26uTF4srRXaGTTsikQmaotCtNdbhzyUH7ft6p9ktz9s6UNQ==}
dependencies:
'@types/yargs-parser': 21.0.0
dev: true

35
scripts/index.ts Normal file
View File

@@ -0,0 +1,35 @@
import { hideBin } from 'yargs/helpers'
import yargs from 'yargs/yargs'
import { getSpaces } from '../src'
const options = {
min: {
alias: 'm',
describe: 'DAO min number of followers on snapshot.org',
type: 'number',
},
size: {
alias: 's',
describe: 'number of org to fetch from snapshot.org. 0 means no limit',
type: 'number',
},
}
// @ts-expect-error
const argv = yargs(hideBin(process.argv)).options(options).help().argv as {
min: number
size: number
}
const main = async () => {
const spaces = await getSpaces({ min: argv.min, size: argv.size })()
console.log(spaces)
}
main()
.then(() => process.exit(0))
.catch((err) => {
console.error(err)
process.exit(1)
})

View File

@@ -1,27 +0,0 @@
#!/usr/bin/env bash
# https://github.com/adrian-gheorghe/demo-docker-secrets-env-vars
set -e
file_env() {
local var="$1"
local fileVar="${var}_FILE"
local def="${2:-}"
if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then
echo >&2 "error: both $var and $fileVar are set (but are exclusive)"
exit 1
fi
local val="$def"
if [ "${!var:-}" ]; then
val="${!var}"
elif [ "${!fileVar:-}" ]; then
val="$(< "${!fileVar}")"
fi
export "$var"="$val"
unset "$fileVar"
}
file_env "SECRET"
exec "$@"

1
src/constants.ts Normal file
View File

@@ -0,0 +1 @@
export const SNAPSHOT_API_URL = 'https://hub.snapshot.org/api/explore'

30
src/get-spaces.ts Normal file
View File

@@ -0,0 +1,30 @@
import { SNAPSHOT_API_URL } from './constants'
import { Space } from './types'
export const filterSpaces =
(min: number) =>
({ followers }: Space) =>
followers !== undefined && followers >= min
export const getSpaces =
({ min = 10, size = 100 }: { min: number; size: number }) =>
async () =>
fetch(SNAPSHOT_API_URL).then(async (res) =>
res.json().then((res) =>
Object.values(res.spaces as Space[])
.reduce<Space[]>((spaces, space) => {
// console.log(space)
if (filterSpaces(min)(space)) spaces.push(space)
return spaces
}, [])
// @ts-expect-error - filterSpaces already ensures that props are defined
.sort((a, b) => b.followers - a.followers)
.slice(0, size),
),
)
export const get100TopDaosWithMin10kFollowers = getSpaces({
min: 10_000,
size: 0,
})

View File

@@ -0,0 +1 @@
export * from './get-spaces'

5
src/types.ts Normal file
View File

@@ -0,0 +1,5 @@
export interface Space {
followers?: number
github?: string
name: string
}

View File

@@ -0,0 +1,24 @@
import { filterSpaces } from '../../src'
describe('filterSpaces', () => {
it('should return true if followers is greater than min', () => {
const followers = 100
const min = 10
expect(filterSpaces(min)({ followers, name: 'name' })).toBe(true)
})
it('should return false if followers is less than min', () => {
const followers = 10
const min = 100
expect(
filterSpaces(min)({ followers, github: 'github', name: 'name' }),
).toBe(false)
})
it('should return false if followers is undefined', () => {
const followers = undefined
const min = 100
expect(
filterSpaces(min)({ followers, github: 'github', name: 'name' }),
).toBe(false)
})
})

View File

@@ -0,0 +1,28 @@
import { get100TopDaosWithMin10kFollowers, getSpaces } from '../../src'
describe('getSpaces', () => {
it('should return an array of spaces', async () => {
const MIN = 20_000
const SIZE = 50
const spaces = await getSpaces({ min: MIN, size: SIZE })()
expect(spaces.length).toBeGreaterThan(0)
expect(spaces.length).toBeLessThanOrEqual(SIZE)
spaces.forEach(({ followers, name }) => {
expect(followers).toBeGreaterThanOrEqual(MIN)
expect(name).toBeTruthy()
})
})
})
describe('getTop100DaosWithMin10kFollowers', () => {
it('should return an array of spaces', async () => {
const spaces = await get100TopDaosWithMin10kFollowers()
expect(spaces.length).toBeLessThanOrEqual(100)
spaces.forEach(({ followers }) => {
expect(followers).toBeGreaterThanOrEqual(10_000)
})
})
})

View File

@@ -1,5 +1,5 @@
{
"include": ["src", "test"],
"include": ["src", "scripts", "test"],
"exclude": ["test/coverage"],
"files": ["node_modules/jest-chain/types/index.d.ts"],
"compilerOptions": {