[internal] Set up Danger build on PR (#3243)

* Return all error messages from checks (to be used by Danger).
* Add Danger dev dep.
* Fix danger.yml + dangerfile.ts.
* Fix root files.
* Finetune Danger message.

Co-authored-by: Catenocrypt <catenocrypt@users.noreply.github.com>
This commit is contained in:
Adam R 2020-08-12 10:03:28 +02:00 committed by GitHub
parent 0c013b91ac
commit 197613e61c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 1067 additions and 156 deletions

View File

@ -1,17 +1,23 @@
name: Danger
on:
push:
branches: [ master ]
pull_request:
branches: [ 'master' ]
workflow_dispatch:
jobs:
danger:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install gems
run: sudo gem install bundler --no-document
- name: Bundle update
run: bundle update --bundler
- name: Run Danger
run: danger --verbose
- name: Use Node.js 10.x
uses: actions/setup-node@v1
with:
node-version: 10.x
- name: install yarn
run: npm install -g yarn
- name: yarn install
run: |
yarn install --frozen-lockfile
- name: Danger
run: yarn danger ci
env:
DANGER_GITHUB_API_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -1,115 +0,0 @@
require 'find'
require 'image_size'
require 'json-schema'
blockchains_folder = './blockchains'
allowed_extensions = ['png', 'json']
allowed_file_names = ['info', 'list', 'logo', 'whitelist', 'blacklist']
maxAssetLogoSizeInKilobyte = 100
minLogoWidth = 64
minLogoHeight = 64
maxLogoWidth = 512
maxLogoHeight = 512
# Failures
# Do not allow files in this directory
Dir.foreach(blockchains_folder) \
.map { |x| File.expand_path("#{blockchains_folder}/#{x}") } \
.select { |x| File.file?(x) }
.map { |x|
fail("Not allowed to have files inside blockchains folder itself. You have to add them inside specific blockchain folder as blockchain/ethereum or blockchain/binance for file: " + x)
}
Find.find(blockchains_folder) do |file|
file_extension = File.extname(file).delete('.')
file_name = File.basename(file, File.extname(file))
# Skip if directory
if File.directory?(file)
next
end
if !allowed_extensions.include? file_extension
fail("Extension not allowed for file: " + file)
end
if !allowed_file_names.include? file_name
fail("Filename not allowed for file: " + file)
end
# Validate JSON content
if file_extension == 'json'
value = nil
begin
value = JSON.parse(File.open(file).read)
rescue JSON::ParserError, TypeError => e
fail("Wrong JSON content in file: " + file)
end
# Validate info.json
if file_name == 'info'
schema = {
"type": "object",
"required": ["name", "website", "short_description", "explorer"],
"properties": {
"name": {"type": "string"},
"website": {"type": "string"},
"short_description": {"type": "string"},
"explorer": {"type": "string"}
}
}
errors = JSON::Validator.fully_validate(schema, value)
errors.each { |error| message("#{error} in file #{file}") }
end
# Validate list.json for validators
if file_name == 'list'
schema = {
"type": "array",
"items": {
"properties": {
"id": { "type": "string" },
"name": { "type": "string" },
"description": { "type": "string" },
"website": { "type": "string" }
},
"required": ["id", "name", "description", "website"]
}
}
errors = JSON::Validator.fully_validate(schema, value)
errors.each { |error| message("#{error} in file #{file}") }
end
# Validate whitelist, blacklist files
if file_name == 'whitelist' || file_name == 'blacklist'
schema = {
"type": "array",
"items": {
"type": "string"
}
}
errors = JSON::Validator.fully_validate(schema, value)
errors.each { |error| message("#{error} in file #{file}") }
end
end
# Validate images
if file_extension == 'png'
image_size = ImageSize.path(file)
if image_size.width > maxLogoWidth || image_size.height > maxLogoHeight
fail("Image width or height is higher than 512px for file: " + file)
end
if image_size.format == 'png'
fail("Image should be PNG for file: " + file)
end
# Make sure file size only 100kb
if File.size(file).to_f / 1024 > maxAssetLogoSizeInKilobyte
fail("Image should less than 100kb for file: " + file)
end
end
end

9
dangerfile.ts Normal file
View File

@ -0,0 +1,9 @@
import { fail, markdown } from "danger";
import { sanityCheckAll } from "./script/action/update-all";
sanityCheckAll().then(errors => {
if (errors.length > 0) {
errors.forEach(err => fail(err));
markdown("Please fix the errors above. Files can be replaced/renamed in this pull request (using command-line, or GitHub Desktop). Alternatively, you may close this pull request and open a new one.");
}
});

1010
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -39,6 +39,7 @@
"bip44-constants": "^8.0.30",
"bluebird": "^3.7.2",
"chalk": "^4.1.0",
"danger": "^10.3.0",
"ethereum-checksum-address": "0.0.5",
"eztz-lib": "^0.1.2",
"image-size": "^0.8.3",

View File

@ -34,38 +34,38 @@ const actionList: ActionInterface[] = [
new Coinmarketcap()
];
async function checkStepList(steps: CheckStepInterface[]): Promise<number> {
var returnCode = 0;
async function checkStepList(steps: CheckStepInterface[]): Promise<string[]> {
var errors: string[] = [];
await bluebird.each(steps, async (step) => {
try {
//console.log(` Running check step '${step.getName()}'...`);
const error = await step.check();
if (error && error.length > 0) {
console.log(`- ${chalk.red('X')} '${step.getName()}': '${error}'`);
returnCode = 1;
errors.push(`${step.getName()}: ${error}`);
} else {
console.log(`- ${chalk.green('✓')} '${step.getName()}' OK`);
}
} catch (error) {
console.log(`- ${chalk.red('X')} '${step.getName()}': Caught error: ${error.message}`);
returnCode = 2;
errors.push(`${step.getName()}: Exception: ${error.message}`);
}
});
return returnCode;
return errors;
}
async function sanityCheckByActionList(actions: ActionInterface[]): Promise<number> {
async function sanityCheckByActionList(actions: ActionInterface[]): Promise<string[]> {
console.log("Running sanity checks...");
var returnCode = 0;
var errors: string[] = [];
await bluebird.each(actions, async (action) => {
try {
if (action.getSanityChecks) {
const steps = action.getSanityChecks();
if (steps && steps.length > 0) {
console.log(` Action '${action.getName()}' has ${steps.length} check steps`);
const ret1 = await checkStepList(steps);
if (ret1 != 0) {
returnCode = ret1;
const errors1 = await checkStepList(steps);
if (errors1.length > 0) {
errors1.forEach(e => errors.push(e));
} else {
console.log(`- ${chalk.green('✓')} Action '${action.getName()}' OK, all ${steps.length} steps`);
}
@ -73,25 +73,25 @@ async function sanityCheckByActionList(actions: ActionInterface[]): Promise<numb
}
} catch (error) {
console.log(`- ${chalk.red('X')} '${action.getName()}' Caught error: ${error.message}`);
returnCode = 3;
errors.push(`${action.getName()}: Exception: ${error.message}`);
}
});
console.log(`All sanity checks done, returnCode ${returnCode}`);
return returnCode;
console.log(`All sanity checks done, found ${errors.length} errors`);
return errors;
}
async function consistencyCheckByActionList(actions: ActionInterface[]): Promise<number> {
async function consistencyCheckByActionList(actions: ActionInterface[]): Promise<string[]> {
console.log("Running consistency checks...");
var returnCode = 0;
var errors: string[] = [];
await bluebird.each(actions, async (action) => {
try {
if (action.getConsistencyChecks) {
const steps = action.getConsistencyChecks();
if (steps && steps.length > 0) {
console.log(` Action '${action.getName()}' has ${steps.length} check steps`);
const ret1 = await checkStepList(steps);
if (ret1 != 0) {
returnCode = ret1;
const errors1 = await checkStepList(steps);
if (errors1.length > 0) {
errors1.forEach(e => errors.push(e));
} else {
console.log(`- ${chalk.green('✓')} Action '${action.getName()}' OK, all ${steps.length} steps`);
}
@ -99,11 +99,11 @@ async function consistencyCheckByActionList(actions: ActionInterface[]): Promise
}
} catch (error) {
console.log(`- ${chalk.red('X')} '${action.getName()}' Caught error: ${error.message}`);
returnCode = 3;
errors.push(`${action.getName()}: Exception: ${error.message}`);
}
});
console.log(`All consistency checks done, returnCode ${returnCode}`);
return returnCode;
console.log(`All consistency checks done, found ${errors.length} errors`);
return errors;
}
async function sanityFixByList(actions: ActionInterface[]) {
@ -151,11 +151,11 @@ async function updateByList(actions: ActionInterface[]) {
console.log("All updates done.");
}
export async function sanityCheckAll(): Promise<number> {
export async function sanityCheckAll(): Promise<string[]> {
return await sanityCheckByActionList(actionList);
}
export async function consistencyCheckAll(): Promise<number> {
export async function consistencyCheckAll(): Promise<string[]> {
return await consistencyCheckByActionList(actionList);
}

View File

@ -4,7 +4,7 @@
"image_min_logo_width": 64,
"image_min_logo_height": 64,
"image_logo_size_kb": 100,
"folders_rootdir_allowed_files": [".github", "blockchains", "dapps", "media", "node_modules", "script-old", "script", "test", ".gitignore", "azure-pipelines.yml", "jest.config.js", "LICENSE", "package-lock.json", "package.json", "README.md", ".git", "pricing", "Dangerfile", "Gemfile", "Gemfile.lock"],
"folders_rootdir_allowed_files": [".github", "blockchains", "dapps", "media", "node_modules", "script-old", "script", "test", ".gitignore", "azure-pipelines.yml", "jest.config.js", "LICENSE", "package-lock.json", "package.json", "README.md", ".git", "pricing", "dangerfile.ts", "Gemfile", "Gemfile.lock"],
"binance_url_tokens2": "https://dex-atlantic.binance.org/api/v1/tokens?limit=1000",
"binance_url_tokens8": "https://dex-atlantic.binance.org/api/v1/mini/tokens?limit=1000",
"binance_url_token_assets": "https://explorer.binance.org/api/v1/assets?page=1&rows=1000"

View File

@ -2,8 +2,8 @@ import { sanityCheckAll } from "../action/update-all";
export async function main() {
try {
const returnCode = await sanityCheckAll();
process.exit(returnCode);
const errors = await sanityCheckAll();
process.exit(errors.length);
} catch(err) {
console.error(err);
process.exit(1);

View File

@ -4,9 +4,9 @@ export async function main() {
var returnCode: number = 0;
try {
const ret1 = await sanityCheckAll();
if (ret1 != 0) {
returnCode = ret1;
const errors1 = await sanityCheckAll();
if (errors1.length > 0) {
returnCode = errors1.length;
}
} catch(err) {
console.error(err);
@ -14,9 +14,9 @@ export async function main() {
}
try {
const ret1 = await consistencyCheckAll();
if (ret1 != 0) {
returnCode = ret1;
const errors1 = await consistencyCheckAll();
if (errors1.length > 0) {
returnCode = errors1.length;
}
} catch(err) {
console.error(err);