You've already forked dynamic-badges-action
Add save svg-badge directly to gist
This adds the posibility of saving an SVG badge generated by the same shields.io dirictly to the gist. Instead of prepering a JSON file to be sent to their service, we use their library directly, which outputs an SVG file that we can save to the user’s gist. Filenames ending in `.svg` will use this library automatically. Additionally there is a major refactoring where the older `node:http` library has been swapped out for `fetch`. Also swap from node 16 to node 20 fixes #24
This commit is contained in:
253
index.js
253
index.js
@@ -4,97 +4,82 @@
|
||||
// Copyright: (c) 2020 Simon Schneegans //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const core = require('@actions/core');
|
||||
const http = require('https');
|
||||
import core from '@actions/core';
|
||||
import { makeBadge } from 'badge-maker';
|
||||
|
||||
// Performs an HTTP request and returns a Promise accordingly. See docs of
|
||||
// http.request() for the available options.
|
||||
function doRequest(options, data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const req = http.request(options, res => {
|
||||
res.setEncoding('utf8');
|
||||
let responseBody = '';
|
||||
|
||||
res.on('data', (chunk) => {
|
||||
responseBody += chunk;
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
const {statusCode, statusMessage} = res;
|
||||
resolve({statusCode, statusMessage, body: JSON.parse(responseBody)});
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', (err) => {
|
||||
reject(err);
|
||||
});
|
||||
|
||||
req.write(data)
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
const gistUrl = new URL(
|
||||
core.getInput('gistID'),
|
||||
'https://api.github.com/gists/'
|
||||
);
|
||||
|
||||
// This uses the method above to update a gist with the given data. The user agent is
|
||||
// required as defined in https://developer.github.com/v3/#user-agent-required
|
||||
function updateGist(data) {
|
||||
const updateGistOptions = {
|
||||
host: 'api.github.com',
|
||||
path: '/gists/' + core.getInput('gistID'),
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Length': data.length,
|
||||
'User-Agent': 'Schneegans',
|
||||
'Authorization': 'token ' + core.getInput('auth'),
|
||||
}
|
||||
};
|
||||
async function updateGist(body) {
|
||||
const headers = new Headers([
|
||||
['Content-Type', 'application/json'],
|
||||
['Content-Length', body.length],
|
||||
['User-Agent', 'Schneegans'],
|
||||
['Authorization', `token ${core.getInput('auth')}`],
|
||||
]);
|
||||
|
||||
doRequest(updateGistOptions, data).then(res => {
|
||||
if (res.statusCode < 200 || res.statusCode >= 400) {
|
||||
core.setFailed(
|
||||
'Failed to create gist, response status code: ' + res.statusCode +
|
||||
', status message: ' + res.statusMessage);
|
||||
} else {
|
||||
console.log('Success!');
|
||||
}
|
||||
const response = await fetch(gistUrl, {
|
||||
method: 'POST',
|
||||
headers,
|
||||
body,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
console.log(await response.text());
|
||||
core.setFailed(
|
||||
`Failed to create gist, response status code: ${response.status} ${response.statusText}`
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Success!');
|
||||
}
|
||||
|
||||
// We wrap the entire action in a try / catch block so we can set it to "failed" if
|
||||
// something goes wrong.
|
||||
try {
|
||||
|
||||
// This object will be stringified and uploaded to the gist. The schemaVersion, label
|
||||
// and message attributes are always required. All others are optional and added to the
|
||||
// content object only if they are given to the action.
|
||||
let content = {
|
||||
schemaVersion: 1,
|
||||
let data = {
|
||||
label: core.getInput('label'),
|
||||
message: core.getInput('message')
|
||||
message: core.getInput('message'),
|
||||
};
|
||||
|
||||
const filename = core.getInput('filename');
|
||||
const isSvgFile = filename.endsWith('.svg');
|
||||
|
||||
if (!isSvgFile) {
|
||||
data.schemaVersion = 1;
|
||||
}
|
||||
|
||||
// Compute the message color based on the given inputs.
|
||||
const color = core.getInput('color');
|
||||
const valColorRange = core.getInput('valColorRange');
|
||||
const minColorRange = core.getInput('minColorRange');
|
||||
const maxColorRange = core.getInput('maxColorRange');
|
||||
const invertColorRange = core.getInput('invertColorRange');
|
||||
const color = core.getInput('color');
|
||||
const valColorRange = core.getInput('valColorRange');
|
||||
const minColorRange = core.getInput('minColorRange');
|
||||
const maxColorRange = core.getInput('maxColorRange');
|
||||
const invertColorRange = core.getInput('invertColorRange');
|
||||
const colorRangeSaturation = core.getInput('colorRangeSaturation');
|
||||
const colorRangeLightness = core.getInput('colorRangeLightness');
|
||||
const colorRangeLightness = core.getInput('colorRangeLightness');
|
||||
|
||||
if (minColorRange != '' && maxColorRange != '' && valColorRange != '') {
|
||||
const max = parseFloat(maxColorRange);
|
||||
const min = parseFloat(minColorRange);
|
||||
let val = parseFloat(valColorRange);
|
||||
let val = parseFloat(valColorRange);
|
||||
|
||||
if (val < min) val = min;
|
||||
if (val > max) val = max;
|
||||
|
||||
let hue = 0;
|
||||
if (invertColorRange == '') {
|
||||
hue = Math.floor((val - min) / (max - min) * 120);
|
||||
hue = Math.floor(((val - min) / (max - min)) * 120);
|
||||
} else {
|
||||
hue = Math.floor((max - val) / (max - min) * 120);
|
||||
hue = Math.floor(((max - val) / (max - min)) * 120);
|
||||
}
|
||||
|
||||
let sat = 100;
|
||||
@@ -107,116 +92,122 @@ try {
|
||||
lig = parseFloat(colorRangeLightness);
|
||||
}
|
||||
|
||||
content.color = 'hsl(' + hue + ', ' + sat + '%, ' + lig + '%)';
|
||||
|
||||
data.color = 'hsl(' + hue + ', ' + sat + '%, ' + lig + '%)';
|
||||
} else if (color != '') {
|
||||
|
||||
content.color = color;
|
||||
data.color = color;
|
||||
}
|
||||
|
||||
// Get all optional attributes and add them to the content object if given.
|
||||
const labelColor = core.getInput('labelColor');
|
||||
const isError = core.getInput('isError');
|
||||
const namedLogo = core.getInput('namedLogo');
|
||||
const logoSvg = core.getInput('logoSvg');
|
||||
const logoColor = core.getInput('logoColor');
|
||||
const logoWidth = core.getInput('logoWidth');
|
||||
const labelColor = core.getInput('labelColor');
|
||||
const isError = core.getInput('isError');
|
||||
const namedLogo = core.getInput('namedLogo');
|
||||
const logoSvg = core.getInput('logoSvg');
|
||||
const logoColor = core.getInput('logoColor');
|
||||
const logoWidth = core.getInput('logoWidth');
|
||||
const logoPosition = core.getInput('logoPosition');
|
||||
const style = core.getInput('style');
|
||||
const style = core.getInput('style');
|
||||
const cacheSeconds = core.getInput('cacheSeconds');
|
||||
const filename = core.getInput('filename');
|
||||
|
||||
if (labelColor != '') {
|
||||
content.labelColor = labelColor;
|
||||
data.labelColor = labelColor;
|
||||
}
|
||||
|
||||
if (isError != '') {
|
||||
content.isError = isError;
|
||||
if (!isSvgFile && isError != '') {
|
||||
data.isError = isError;
|
||||
}
|
||||
|
||||
if (namedLogo != '') {
|
||||
content.namedLogo = namedLogo;
|
||||
if (!isSvgFile && namedLogo != '') {
|
||||
data.namedLogo = namedLogo;
|
||||
}
|
||||
|
||||
if (logoSvg != '') {
|
||||
content.logoSvg = logoSvg;
|
||||
if (!isSvgFile && logoSvg != '') {
|
||||
data.logoSvg = logoSvg;
|
||||
}
|
||||
|
||||
if (logoColor != '') {
|
||||
content.logoColor = logoColor;
|
||||
if (!isSvgFile && logoColor != '') {
|
||||
data.logoColor = logoColor;
|
||||
}
|
||||
|
||||
if (logoWidth != '') {
|
||||
content.logoWidth = parseInt(logoWidth);
|
||||
if (!isSvgFile && logoWidth != '') {
|
||||
data.logoWidth = parseInt(logoWidth);
|
||||
}
|
||||
|
||||
if (logoPosition != '') {
|
||||
content.logoPosition = logoPosition;
|
||||
if (!isSvgFile && logoPosition != '') {
|
||||
data.logoPosition = logoPosition;
|
||||
}
|
||||
|
||||
if (style != '') {
|
||||
content.style = style;
|
||||
data.style = style;
|
||||
}
|
||||
|
||||
if (cacheSeconds != '') {
|
||||
content.cacheSeconds = parseInt(cacheSeconds);
|
||||
if (!isSvgFile && cacheSeconds != '') {
|
||||
data.cacheSeconds = parseInt(cacheSeconds);
|
||||
}
|
||||
|
||||
let content = '';
|
||||
|
||||
if (isSvgFile) {
|
||||
content = makeBadge(data);
|
||||
} else {
|
||||
content = JSON.stringify({ content: data });
|
||||
}
|
||||
|
||||
// For the POST request, the above content is set as file contents for the
|
||||
// given filename.
|
||||
const request =
|
||||
JSON.stringify({files: {[filename]: {content: JSON.stringify(content)}}});
|
||||
const body = JSON.stringify({ files: { [filename]: { content } } });
|
||||
|
||||
// If "forceUpdate" is set to true, we can simply update the gist. If not, we have to
|
||||
// get the gist data and compare it to the new value before.
|
||||
if (core.getBooleanInput('forceUpdate')) {
|
||||
updateGist(request);
|
||||
|
||||
updateGist(body);
|
||||
} else {
|
||||
|
||||
// Get the old gist.
|
||||
const getGistOptions = {
|
||||
host: 'api.github.com',
|
||||
path: '/gists/' + core.getInput('gistID'),
|
||||
fetch(gistUrl, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'User-Agent': 'Schneegans',
|
||||
'Authorization': 'token ' + core.getInput('auth'),
|
||||
}
|
||||
};
|
||||
headers: new Headers([
|
||||
['Content-Type', 'application/json'],
|
||||
['User-Agent', 'Schneegans'],
|
||||
['Authorization', `token ${core.getInput('auth')}`],
|
||||
]),
|
||||
})
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
// print the error, but don't fail the action.
|
||||
console.log(
|
||||
`Failed to get gist: ${response.status} ${response.statusText}`
|
||||
);
|
||||
response.text().then((text) => console.log(text));
|
||||
|
||||
doRequest(getGistOptions, JSON.stringify({})).then(oldGist => {
|
||||
if (oldGist.statusCode < 200 || oldGist.statusCode >= 400) {
|
||||
// print the error, but don't fail the action.
|
||||
console.log(
|
||||
'Failed to get gist, response status code: ' + oldGist.statusCode +
|
||||
', status message: ' + oldGist.statusMessage);
|
||||
}
|
||||
|
||||
let shouldUpdate = true;
|
||||
|
||||
if (oldGist && oldGist.body && oldGist.body.files && oldGist.body.files[filename]) {
|
||||
const oldContent = oldGist.body.files[filename].content;
|
||||
|
||||
if (oldContent === JSON.stringify(content)) {
|
||||
console.log(`Content did not change, not updating gist at ${filename}.`);
|
||||
shouldUpdate = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldUpdate) {
|
||||
if (oldGist.body.files[filename]) {
|
||||
console.log(`Content changed, updating gist at ${filename}.`);
|
||||
} else {
|
||||
console.log(`Content didn't exist, creating gist at ${filename}.`);
|
||||
return {};
|
||||
}
|
||||
|
||||
updateGist(request);
|
||||
}
|
||||
});
|
||||
return response.json();
|
||||
})
|
||||
.then((oldGist) => {
|
||||
let shouldUpdate = true;
|
||||
|
||||
if (oldGist?.body?.files?.[filename]) {
|
||||
const oldContent = oldGist.body.files[filename].content;
|
||||
|
||||
if (oldContent === content) {
|
||||
console.log(
|
||||
`Content did not change, not updating gist at ${filename}.`
|
||||
);
|
||||
shouldUpdate = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldUpdate) {
|
||||
if (oldGist?.body?.files?.[filename]) {
|
||||
console.log(`Content changed, updating gist at ${filename}.`);
|
||||
} else {
|
||||
console.log(`Content didn't exist, creating gist at ${filename}.`);
|
||||
}
|
||||
|
||||
updateGist(body);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
core.setFailed(error);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user