diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..0bf931f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,22 @@ +FROM node:10 + +RUN apt-get update && \ + apt-get -y install xvfb gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 \ + libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 \ + libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 \ + libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 \ + libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget curl && \ + rm -rf /var/lib/apt/lists/* + +RUN npm install puppeteer markdown-it mustache markdown-it-named-headers cheerio +COPY makepdfs.js / +COPY package.json / +COPY template/ template/ +COPY styles/ styles/ + +RUN fc-cache -fv && \ + chmod +x /makepdfs.js && \ + mkdir /pdf && \ + chmod 777 /pdf && \ + ln -s /makepdfs.js /usr/local/bin/makepdfs +CMD [ "makepdfs" ] diff --git a/LICENSE b/LICENSE index 3cb6634..9e9def9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019 Merritt Krakowitzer +Copyright (c) 2020 Merritt Krakowitzer Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md new file mode 100644 index 0000000..b8884b6 --- /dev/null +++ b/README.md @@ -0,0 +1,33 @@ +# A github action for creating PDFs from github markdown + +This action creates PDF documents from github markdown + +## Inputs + +### `markdown_dir` + +**Required** Location of markdown files in github repository. Default `doc`. + +### `output_dir` + +**Required** Location to output PDF files to. Default `tmp`. + +## Example usage + +``` +on: [push] + +name: CreatePDFs + +jobs: + makepdfs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - uses: mkrakowitzer/actions-makepdfs@master + if: github.ref == 'refs/heads/master' + - uses: actions/upload-artifact@v1 + with: + name: platform-architecture-docs + path: tmp +``` diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..f30ca37 --- /dev/null +++ b/action.yml @@ -0,0 +1,19 @@ +# action.yml +name: 'Create PDF' +description: 'Creates PDF files from github markdown' +runs: + using: 'docker' + image: 'Dockerfile' +inputs: + markdown_dir: + description: 'Location of markdown files in github repository' + required: true + default: 'doc' + output_dir: + description: 'Location to output PDF files to' + required: true + default: 'tmp' + +branding: + icon: 'activity' + color: 'green' diff --git a/makepdfs.js b/makepdfs.js new file mode 100755 index 0000000..d9e850b --- /dev/null +++ b/makepdfs.js @@ -0,0 +1,127 @@ +#!/usr/bin/env node + +const markdown_dir = process.env.INPUT_MARKDOWN_DIR; +const output_dir = process.env.INPUT_OUTPUT_DIR; + +'use strict'; +var fs = require( 'fs' ); +var mddir = '/github/workspace/' + markdown_dir; +var dir = '/github/workspace/' + output_dir + '/'; + +/* + * Show an error message + */ +function showErrorMessage(msg, error) { + console.log('ERROR: ' + msg); + if (error) { + console.log(error); + } +} + +/* + * make html + */ +function makeHtml(data) { + try { + // read files that make up template + var style = fs.readFileSync("/styles/markdown.css", ).toString('utf-8') + fs.readFileSync("/styles/markdown-pdf.css", ).toString('utf-8'); + var template = fs.readFileSync("/template/template.html").toString('utf-8'); + // compile template + var mustache = require('mustache'); + + var view = { + style: style, + content: data + }; + return mustache.render(template, view); + } catch (error) { + showErrorMessage('makeHtml()', error); + } +} + +/* + * make PDF + */ +function makePdf(data,file) { + try { + file = file.replace('.md',''); + const puppeteer = require('puppeteer'); + (async () => { + const browser = await puppeteer.launch( { + executablePath:'/node_modules/puppeteer/.local-chromium/linux-706915/chrome-linux/chrome', + args: [ + '--headless', + '--no-sandbox', + '--disable-setuid-sandbox' + ] + } ) + const page = await browser.newPage(); + await page.goto(data, {waitUntil: 'networkidle2'}); + await page.pdf({ + path: dir + file + '.pdf', + format: 'A4', + scale: .9, + displayHeaderFooter: true, + margin: {top: 100, bottom:100, right: '50', left: '50'}, + footerTemplate: '
', + headerTemplate: '' + }); + + await browser.close(); + })(); + } catch (error) { + showErrorMessage('makeHtml()', error); + } +} + +function Slug(string) { + try { + var stg = encodeURI(string.trim() + .toLowerCase() + .replace(/[\]\[\!\"\#\$\%\&\'\(\)\*\+\,\.\/\:\;\<\=\>\?\@\\\^\_\{\|\}\~\`]/g, '') + .replace(/\s+/g, '-') + .replace(/^\-+/, '') + .replace(/\-+$/, '')); + return stg; + } catch (error) { + showErrorMessage('Slug()', error); + } +} + +var path = require('path'); + +if (!fs.existsSync(dir)){ + fs.mkdirSync(dir); +} + +fs.readdir (mddir,function(err, files) { + for (let file of files) { + if (path.extname(file) == '.md') { + var text = fs.readFileSync('doc/' + file).toString('utf-8'); + var md = require('markdown-it')({ + html: true, + breaks: true, + highlight: function (str, lang) { + if (lang && hljs.getLanguage(lang)) { + try { + str = hljs.highlight(lang, str, true).value; + } catch (error) { + str = md.utils.escapeHtml(str); + + showErrorMessage('markdown-it:highlight', error); + } + } else { + str = md.utils.escapeHtml(str); + } + return '' + str + '
';
+ }
+ });
+ var options = {
+ slugify: Slug
+ }
+ md.use(require('markdown-it-named-headers'), options);
+ var body = md.render(text);
+ makePdf('data:text/html;,' + encodeURIComponent(makeHtml(body)),file);
+ }
+ }
+});
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..309b6ef
--- /dev/null
+++ b/package.json
@@ -0,0 +1,7 @@
+{
+ "dependencies": {
+ "puppeteer": "1.15.0",
+ "commander": "2.20.0",
+ "markdown-it": "8.4.2"
+ }
+}
diff --git a/styles/markdown-pdf.css b/styles/markdown-pdf.css
new file mode 100644
index 0000000..9c34cc0
--- /dev/null
+++ b/styles/markdown-pdf.css
@@ -0,0 +1,55 @@
+/*
+ * Markdown PDF CSS
+ */
+
+ body {
+ font-family: "Meiryo", "Segoe WPC", "Segoe UI", "SFUIText-Light", "HelveticaNeue-Light", sans-serif, "Droid Sans Fallback";
+}
+
+img {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+ width: 50%;
+}
+
+pre {
+ background-color: #f8f8f8;
+ border: 1px solid #cccccc;
+ border-radius: 3px;
+ overflow-x: auto;
+ white-space: pre-wrap;
+ overflow-wrap: break-word;
+}
+
+pre:not(.hljs) {
+ padding: 23px;
+ line-height: 19px;
+}
+
+blockquote {
+ background: rgba(127, 127, 127, 0.1);
+ border-color: rgba(0, 122, 204, 0.5);
+}
+
+.emoji {
+ height: 1.4em;
+}
+
+/* for inline code */
+:not(pre):not(.hljs) > code {
+ color: #C9AE75; /* Change the old color so it seems less like an error */
+ font-size: inherit;
+}
+
+/* Page Break : use to insert page break
+-------------------------------------------------------- */
+.page {
+ page-break-after: always;
+}
+
+@media print {
+ p {page-break-inside: avoid;}
+ h1 {page-break-before: always;}
+ footer {page-break-after: always;}
+}
diff --git a/styles/markdown.css b/styles/markdown.css
new file mode 100644
index 0000000..45464f7
--- /dev/null
+++ b/styles/markdown.css
@@ -0,0 +1,155 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+body {
+ font-family: "Segoe WPC", "Segoe UI", "SFUIText-Light", "HelveticaNeue-Light", sans-serif, "Droid Sans Fallback";
+ font-size: 14px;
+ padding: 0 12px;
+ line-height: 22px;
+ word-wrap: break-word;
+}
+
+#code-csp-warning {
+ position: fixed;
+ top: 0;
+ right: 0;
+ color: white;
+ margin: 16px;
+ text-align: center;
+ font-size: 12px;
+ font-family: sans-serif;
+ background-color:#444444;
+ cursor: pointer;
+ padding: 6px;
+ box-shadow: 1px 1px 1px rgba(0,0,0,.25);
+}
+
+#code-csp-warning:hover {
+ text-decoration: none;
+ background-color:#007acc;
+ box-shadow: 2px 2px 2px rgba(0,0,0,.25);
+}
+
+
+body.scrollBeyondLastLine {
+ margin-bottom: calc(100vh - 22px);
+}
+
+body.showEditorSelection .code-line {
+ position: relative;
+}
+
+body.showEditorSelection .code-active-line:before,
+body.showEditorSelection .code-line:hover:before {
+ content: "";
+ display: block;
+ position: absolute;
+ top: 0;
+ left: -12px;
+ height: 100%;
+}
+
+body.showEditorSelection li.code-active-line:before,
+body.showEditorSelection li.code-line:hover:before {
+ left: -30px;
+}
+
+img {
+ max-width: 100%;
+ max-height: 100%;
+}
+
+a {
+ color: #4080D0;
+ text-decoration: none;
+}
+
+a:focus,
+input:focus,
+select:focus,
+textarea:focus {
+ outline: 1px solid -webkit-focus-ring-color;
+ outline-offset: -1px;
+}
+
+hr {
+ border: 0;
+ height: 2px;
+ border-bottom: 2px solid;
+}
+
+h1 {
+ padding-bottom: 0.3em;
+ line-height: 1.2;
+ border-bottom-width: 1px;
+ border-bottom-style: solid;
+}
+
+h1, h2, h3 {
+ font-weight: normal;
+}
+
+h1 code,
+h2 code,
+h3 code,
+h4 code,
+h5 code,
+h6 code {
+ font-size: inherit;
+ line-height: auto;
+}
+
+a:hover {
+ color: #4080D0;
+ text-decoration: underline;
+}
+
+table {
+ border-collapse: collapse;
+}
+
+table > thead > tr > th {
+ text-align: left;
+ border-bottom: 1px solid;
+}
+
+table > thead > tr > th,
+table > thead > tr > td,
+table > tbody > tr > th,
+table > tbody > tr > td {
+ padding: 5px 10px;
+}
+
+table > tbody > tr + tr > td {
+ border-top: 1px solid;
+}
+
+blockquote {
+ margin: 0 7px 0 5px;
+ padding: 0 16px 0 10px;
+ border-left: 5px solid;
+}
+
+code {
+ font-family: Menlo, Monaco, Consolas, "Droid Sans Mono", "Courier New", monospace, "Droid Sans Fallback";
+ font-size: 14px;
+ line-height: 19px;
+}
+
+body.wordWrap pre {
+ white-space: pre-wrap;
+}
+
+.mac code {
+ font-size: 12px;
+ line-height: 18px;
+}
+
+pre:not(.hljs),
+pre.hljs code > div {
+ padding: 16px;
+ border-radius: 3px;
+ overflow: auto;
+}
diff --git a/template/template.html b/template/template.html
new file mode 100644
index 0000000..04a4409
--- /dev/null
+++ b/template/template.html
@@ -0,0 +1,13 @@
+
+
+
+