2020-01-10 16:48:46 +00:00
|
|
|
import Joi from '@hapi/joi';
|
|
|
|
|
import core from '@actions/core';
|
2020-01-13 15:38:23 +00:00
|
|
|
import * as http from 'http';
|
|
|
|
|
import * as https from 'https';
|
2020-01-10 16:48:46 +00:00
|
|
|
import data from '../src/data.js';
|
2020-01-10 18:44:02 +00:00
|
|
|
import flags from './flags.js';
|
2020-01-10 16:48:46 +00:00
|
|
|
|
2020-01-13 15:38:23 +00:00
|
|
|
if (process.env.CI !== 'true') {
|
|
|
|
|
core.error = console.error;
|
|
|
|
|
core.setFailed = console.error;
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-10 16:48:46 +00:00
|
|
|
const schema = Joi.object({
|
|
|
|
|
name: Joi.string().required(),
|
|
|
|
|
description: Joi.string().required(),
|
|
|
|
|
url: Joi.string()
|
|
|
|
|
.uri()
|
|
|
|
|
.required(),
|
2020-01-10 18:44:02 +00:00
|
|
|
country: Joi.string()
|
|
|
|
|
.valid(...flags)
|
|
|
|
|
.required(),
|
|
|
|
|
twitter: Joi.string().pattern(new RegExp(/^@?(\w){1,15}$/)),
|
|
|
|
|
emoji: Joi.string().allow(''),
|
2020-01-10 16:48:46 +00:00
|
|
|
computer: Joi.string().valid('apple', 'windows', 'linux'),
|
2020-01-10 18:44:02 +00:00
|
|
|
phone: Joi.string().valid('iphone', 'android'),
|
2020-01-10 16:48:46 +00:00
|
|
|
tags: Joi.array().items(Joi.string()),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const errors = data
|
|
|
|
|
.map(person => schema.validate(person))
|
|
|
|
|
.filter(v => v.error)
|
|
|
|
|
.map(v => v.error);
|
|
|
|
|
|
|
|
|
|
errors.forEach(e => {
|
|
|
|
|
core.error(e._original.name);
|
|
|
|
|
e.details.forEach(d => core.error(d.message));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (errors.length) {
|
|
|
|
|
core.setFailed('Action failed with validation errors, see logs');
|
|
|
|
|
}
|
2020-01-13 15:38:23 +00:00
|
|
|
const REQUEST_TIMEOUT = 5000;
|
|
|
|
|
|
|
|
|
|
function getStatusCode(url) {
|
|
|
|
|
const client = url.startsWith('https') ? https : http;
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
setTimeout(() => reject(new Error('Request timed out')), REQUEST_TIMEOUT);
|
|
|
|
|
client
|
|
|
|
|
.get(url, res => {
|
|
|
|
|
resolve(res.statusCode);
|
|
|
|
|
})
|
|
|
|
|
.on('error', err => {
|
|
|
|
|
reject(err);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function isWorkingUrl(url) {
|
|
|
|
|
try {
|
|
|
|
|
const statusCode = await getStatusCode(url);
|
|
|
|
|
if (statusCode < 200 || statusCode >= 300) {
|
2020-01-13 15:46:03 +00:00
|
|
|
core.error(`Ping to "${url}" failed with status: ${statusCode}`);
|
2020-01-13 15:38:23 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
} catch (e) {
|
2020-01-13 15:46:03 +00:00
|
|
|
core.error(`Ping to "${url}" failed with error: ${e}`);
|
2020-01-13 15:38:23 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
(async () => {
|
|
|
|
|
// TODO: we might need to batch these in sets instead of requesting 100+ URLs
|
|
|
|
|
// at the same time
|
|
|
|
|
const areWorkingUrls = await Promise.all(
|
|
|
|
|
data.map(p => p.url).map(url => isWorkingUrl(url))
|
|
|
|
|
);
|
|
|
|
|
const failingUrls = areWorkingUrls.filter(a => !a);
|
|
|
|
|
if (failingUrls.length > 0) {
|
|
|
|
|
core.setFailed(
|
|
|
|
|
`Action failed with ${failingUrls.length} URL fetch failures, see logs`
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
process.exit(0);
|
|
|
|
|
})();
|