├── docs ├── latest-release.yml └── markdown-autodocs.yml ├── .github └── workflows │ ├── markdown-autodocs.yml │ └── npm-publish.yml ├── update_release_version.py ├── package.json ├── LICENSE ├── utils ├── crud.js ├── app.js └── githubApi.js ├── index.js ├── test └── cli.test.js ├── CONTRIBUTING.md ├── action.py ├── action.yml ├── .gitignore ├── CODE_OF_CONDUCT.md └── README.md /docs/latest-release.yml: -------------------------------------------------------------------------------- 1 | uses: dineshsonachalam/markdown-autodocs@v1.0.2 2 | -------------------------------------------------------------------------------- /.github/workflows/markdown-autodocs.yml: -------------------------------------------------------------------------------- 1 | name: markdown-autodocs 2 | 3 | on: 4 | workflow_run: 5 | workflows: 6 | - integration-tests 7 | types: 8 | - completed 9 | 10 | jobs: 11 | autoupdate-readme: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - name: Markdown autodocs 17 | uses: ./ # Uses an action in the root directory 18 | -------------------------------------------------------------------------------- /docs/markdown-autodocs.yml: -------------------------------------------------------------------------------- 1 | - name: Markdown autodocs 2 | - uses: dineshsonachalam/markdown-autodocs@v1.0.2 3 | with: 4 | # Optional, defaults to author of the commit that triggered the run 5 | commit_author: Author 6 | 7 | # Optional, defaults to "actions@github.com" 8 | commit_user_email: actions@github.com 9 | 10 | # Optional, but recommended 11 | # Defaults to "Apply automatic changes" 12 | commit_message: Apply automatic changes 13 | 14 | # Optional branch name where commit should be pushed to. 15 | # Defaults to the current branch. 16 | branch: feature-123 17 | 18 | # Optional output file paths, defaults to '[./README.md]'. 19 | output_file_paths: '[./README.md]' 20 | 21 | # Categories to automatically sync or transform its contents in the markdown files. 22 | # Defaults to '[code-block,json-to-html-table,workflow-artifact-table]' 23 | categories: '[code-block,json-to-html-table,workflow-artifact-table]' 24 | -------------------------------------------------------------------------------- /update_release_version.py: -------------------------------------------------------------------------------- 1 | from ruamel.yaml import YAML 2 | import requests 3 | 4 | def update_latest_release_version(file_path, action_name): 5 | file = yaml.load(open(file_path)) 6 | if "latest-release" in file_path: 7 | file["uses"]=action_name 8 | else: 9 | file[-1]["uses"] = action_name 10 | with open(file_path, 'w') as outfile: 11 | yaml.dump(file, outfile) 12 | 13 | if __name__ == "__main__": 14 | yaml=YAML() 15 | yaml.default_flow_style = False 16 | url = "https://api.github.com/repos/dineshsonachalam/markdown-autodocs/releases/latest" 17 | response = requests.request("GET", url, headers={}, data={}) 18 | response = response.json() 19 | tag = response["tag_name"] 20 | action_name="dineshsonachalam/markdown-autodocs@{}".format(tag) 21 | files = [ 22 | './docs/latest-release.yml', 23 | './docs/markdown-autodocs.yml' 24 | ] 25 | for _, file_path in enumerate(files): 26 | update_latest_release_version(file_path, action_name) -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "markdown-autodocs", 3 | "version": "1.0.42", 4 | "repository": { 5 | "type": "git", 6 | "url": "https://github.com/dineshsonachalam/markdown-autodocs" 7 | }, 8 | "author": "Dinesh Sonachalam", 9 | "license": "MIT", 10 | "main": "index.js", 11 | "bin": { 12 | "markdown-autodocs": "index.js" 13 | }, 14 | "files": [ 15 | "index.js", 16 | "utils/*" 17 | ], 18 | "jest": { 19 | "reporters": [ 20 | "default", 21 | "jest-html-reporters" 22 | ] 23 | }, 24 | "scripts": { 25 | "test": "jest ./test/*.test.js" 26 | }, 27 | "type": "module", 28 | "dependencies": { 29 | "@actions/core": "^1.2.4", 30 | "@actions/github": "^4.0.0", 31 | "commander": "^7.2.0", 32 | "cross-fetch": "^3.1.4", 33 | "log4js": "^6.3.0", 34 | "markdown-magic": "^2.0.0", 35 | "table-builder": "^2.1.1", 36 | "yaml": "^1.10.2" 37 | }, 38 | "devDependencies": { 39 | "eslint": "^7.29.0", 40 | "jest": "^27.0.4", 41 | "jest-html-reporters": "^2.1.6" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Dinesh Sonachalam 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /utils/crud.js: -------------------------------------------------------------------------------- 1 | /* 2 | Module to perform CRUD operations. 3 | Author: Dinesh Sonachalam 4 | */ 5 | import YAML from 'yaml' 6 | import fetch from 'cross-fetch'; 7 | 8 | /** 9 | * GET Request 10 | * @param {String} url 11 | * @param {Object} headers 12 | * @returns {Object} jsonResponse 13 | */ 14 | export const get = async function(url, headers) { 15 | const requestOptions = { 16 | method: "GET", 17 | headers: headers 18 | } 19 | const response = await fetch(url, requestOptions) 20 | const jsonResponse = await response.json() 21 | return jsonResponse 22 | } 23 | 24 | /** 25 | * GET Yaml config value 26 | * @param {String} url 27 | * @param {Object} headers 28 | * @param {String} filter 29 | * @returns {String} yaml_doc[filter] 30 | */ 31 | export const getYamlConfigValue = async function(url, headers, filter) { 32 | const requestOptions = { 33 | method: "GET", 34 | headers: headers 35 | } 36 | const response = await fetch(url, requestOptions) 37 | const textResponse = await response.text() 38 | const yamlDoc = YAML.parse(textResponse); 39 | return yamlDoc[filter] 40 | } -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /** 3 | * Entry point for markdown-autodocs CLI app 4 | * Author: Dinesh Sonachalam 5 | */ 6 | 7 | import {app} from './utils/app.js' 8 | import pkg from 'log4js'; 9 | const { getLogger } = pkg; 10 | import {Command} from 'commander/esm.mjs'; 11 | 12 | export const gitCliargs = function() { 13 | const program = new Command(); 14 | program 15 | .option('-o, --outputFilePath ', 'Output file paths') 16 | .option('-c, --category ', 'code-block, json-to-html-table, workflow-artifact-table') 17 | .option('-r, --repo ', 'Repo name') 18 | .option('-b, --branch ', 'Branch name') 19 | .option('-a, --accessToken ', 'Github Access token') 20 | program.parse(process.argv) 21 | const options = program.opts() 22 | return options 23 | } 24 | 25 | export const main = async function() { 26 | const logger = getLogger(); 27 | logger.level = "info"; 28 | const options = gitCliargs() 29 | const outputFilePaths = options.outputFilePath 30 | const categories = options.category 31 | const repo = options.repo 32 | const branch = options.branch 33 | const accessToken = options.accessToken 34 | for (const outputFilePath of outputFilePaths){ 35 | for (const category of categories){ 36 | const message = await app(outputFilePath, category, repo, branch, accessToken) 37 | logger.info(message) 38 | } 39 | } 40 | } 41 | 42 | await main() -------------------------------------------------------------------------------- /test/cli.test.js: -------------------------------------------------------------------------------- 1 | const { exec } = require('child_process'); 2 | describe('Validate markdown-autodocs CLI', () => { 3 | 4 | beforeEach(() => { 5 | jest.setTimeout(60000); 6 | }); 7 | 8 | it('Autodoc workflow artifact table. Gave all the required arguments to the CLI as an input, it should now return a success message', (done) => { 9 | exec( 10 | 'node index.js -c workflow-artifact-table -o ./README.md -r $TEST_REPO -b $TEST_BRANCH -a $TEST_ACCESSTOKEN', 11 | (error, stdout, stderr) => { 12 | expect(stdout).toMatch(/([INFO] default - Added|artifacts)/i) 13 | done(); 14 | } 15 | ); 16 | }); 17 | 18 | it('Autodoc code block. Gave all the required arguments to the CLI as an input, it should now return a success message', (done) => { 19 | exec( 20 | 'node index.js -c code-block -o ./README.md -r $TEST_REPO -b $TEST_BRANCH -a $TEST_ACCESSTOKEN', 21 | (error, stdout, stderr) => { 22 | expect(stdout).toMatch(/(Auto documented code-block)/i) 23 | done(); 24 | } 25 | ); 26 | }); 27 | 28 | it('Autodoc json-to-html-table. Gave all the required arguments to the CLI as an input, it should now return a success message', (done) => { 29 | exec( 30 | 'node index.js -c json-to-html-table -o ./README.md -r $TEST_REPO -b $TEST_BRANCH -a $TEST_ACCESSTOKEN', 31 | (error, stdout, stderr) => { 32 | expect(stdout).toMatch(/(Converted JSON to HTML table.)/i) 33 | done(); 34 | } 35 | ); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # CONTRIBUTING 2 | 3 | Contributions are always welcome, no matter how large or small. Before contributing, 4 | please read the [code of conduct](CODE_OF_CONDUCT.md). 5 | 6 | ## Setup 7 | 8 | > Install node & npm on your system: [https://nodejs.org/en/download/](https://nodejs.org/en/download/) 9 | 10 | ### Install dependencies 11 | 12 | > Only required when setting up the project 13 | 14 | ```sh 15 | $ git clone git@github.com:dineshsonachalam/markdown-autodocs.git 16 | $ cd markdown-autodocs 17 | $ npm i 18 | ``` 19 | 20 | ### Run locally 21 | 22 | To run markdown-autodocs locally follow these steps: 23 | 1. Make sure you have run `npm i` to install all packages 24 | 2. Finally, you can use the markdown-autodocs cli `node index.js -c code-block -o ./README.md -r $TEST_REPO -b $TEST_BRANCH -a $TEST_ACCESSTOKEN` 25 | 26 | If you have any questions please ping [@DSonachalam](https://twitter.com/DSonachalam) on Twitter. 27 | 28 | ## Available scripts 29 | 30 | ### `test` 31 | 32 | Runs all the `markdown-autodocs` packages tests. 33 | 34 | #### Usage 35 | 36 | ```sh 37 | npm test 38 | ``` 39 | 40 | ## Pull Requests 41 | 42 | We actively welcome your pull requests! 43 | 44 | If you need help with Git or our workflow, please ask on [Dinesh on twitter](https://twitter.com/DSonachalam). We want your contributions even if you're just learning Git. Our maintainers are happy to help! 45 | 46 | Analytics uses the [Forking Workflow](https://www.atlassian.com/git/tutorials/comparing-workflows/forking-workflow) + [Feature Branches](https://www.atlassian.com/git/tutorials/comparing-workflows/feature-branch-workflow). Additionally, PR's should be [rebased](https://www.atlassian.com/git/tutorials/merging-vs-rebasing) on master when opened, and again before merging. 47 | -------------------------------------------------------------------------------- /action.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import os 3 | 4 | def get_cli_args(): 5 | parser = argparse.ArgumentParser() 6 | parser.add_argument('-repo', required=True) 7 | parser.add_argument('-access_token', required=True) 8 | parser.add_argument('-commit_author', required=True) 9 | parser.add_argument('-commit_user_email', required=True) 10 | parser.add_argument('-commit_message', required=True) 11 | parser.add_argument('-branch', required=True) 12 | parser.add_argument('-output_file_paths', required=True) 13 | parser.add_argument('-categories', required=True) 14 | return parser.parse_args() 15 | 16 | def option_processor(option): 17 | option = option.translate({ord(i):None for i in '[]" '}) 18 | option = option.split(",") 19 | option = ' '.join(option) 20 | return option 21 | 22 | if __name__ == "__main__": 23 | args = get_cli_args() 24 | repo = args.repo 25 | access_token = args.access_token 26 | commit_author = args.commit_author 27 | commit_user_email = args.commit_user_email 28 | commit_message = args.commit_message 29 | branch = (args.branch).split("/")[-1] 30 | output_file_paths = option_processor(args.output_file_paths) 31 | categories = option_processor(args.categories) 32 | ma_cli_command = "markdown-autodocs --outputFilePath {} --category {} --repo {} --branch {} --accessToken {}".format(output_file_paths, categories, repo, branch, access_token) 33 | os.system("git config user.name '{}'".format(commit_author)) 34 | os.system("git config user.email '{}'".format(commit_user_email)) 35 | os.system("sudo npm i -g markdown-autodocs") 36 | os.system(ma_cli_command) 37 | os.system("git add {}".format(output_file_paths)) 38 | os.system("git commit -m '{}' {}".format(commit_message, output_file_paths)) 39 | os.system("git push origin {}".format(branch)) 40 | 41 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: Markdown autodocs 2 | description: 'A github action that automatically format markdown files, sync external docs/src code & make better docs.' 3 | 4 | author: Dinesh Sonachalam 5 | 6 | inputs: 7 | commit_author: 8 | description: Value used for the commit author. Defaults to the username of whoever triggered this workflow run. 9 | required: false 10 | default: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com> 11 | commit_user_email: 12 | description: Email address used for the commit user 13 | required: false 14 | default: actions@github.com 15 | commit_message: 16 | description: Commit message 17 | required: false 18 | default: Apply automatic changes 19 | branch: 20 | description: Git branch name, where changes should be pushed too. 21 | required: false 22 | default: ${{ github.ref }} 23 | output_file_paths: 24 | description: Output markdown file paths. 25 | required: false 26 | default: '[./README.md]' 27 | categories: 28 | description: Categories to automatically sync or transform its contents in the markdown files. 29 | required: false 30 | default: '[code-block,json-to-html-table,workflow-artifact-table]' 31 | 32 | runs: 33 | using: composite 34 | steps: 35 | - run: wget https://raw.githubusercontent.com/dineshsonachalam/markdown-autodocs/master/action.py 36 | shell: bash 37 | - run: python3 action.py -repo '${{ github.repository }}' -access_token '${{ github.token }}' -commit_author '${{ inputs.commit_author }}' -commit_user_email '${{ inputs.commit_user_email }}' -commit_message '${{ inputs.commit_message }}' -branch '${{ inputs.branch }}' -output_file_paths '${{ inputs.output_file_paths }}' -categories '${{ inputs.categories }}' 38 | shell: bash 39 | 40 | branding: 41 | icon: 'book' 42 | color: blue 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | jspm_packages/ 43 | node_modules/ 44 | 45 | # Snowpack dependency directory (https://snowpack.dev/) 46 | web_modules/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Microbundle cache 58 | .rpt2_cache/ 59 | .rts2_cache_cjs/ 60 | .rts2_cache_es/ 61 | .rts2_cache_umd/ 62 | 63 | # Optional REPL history 64 | .node_repl_history 65 | 66 | # Output of 'npm pack' 67 | *.tgz 68 | 69 | # Yarn Integrity file 70 | .yarn-integrity 71 | 72 | # dotenv environment variables file 73 | .env 74 | .env.test 75 | .env.production 76 | 77 | # parcel-bundler cache (https://parceljs.org/) 78 | .cache 79 | .parcel-cache 80 | 81 | # Next.js build output 82 | .next 83 | out 84 | 85 | # Nuxt.js build / generate output 86 | .nuxt 87 | dist 88 | 89 | # Gatsby files 90 | .cache/ 91 | jest_html_reporters.html 92 | # Comment in the public line in if your project uses Gatsby and not Next.js 93 | # https://nextjs.org/blog/next-9-1#public-directory-support 94 | # public 95 | package-lock.json 96 | module-dependencies-license-report.csv 97 | coverage/ 98 | .nyc_output/ 99 | # vuepress build output 100 | .vuepress/dist 101 | 102 | # Serverless directories 103 | .serverless/ 104 | 105 | # FuseBox cache 106 | .fusebox/ 107 | 108 | # DynamoDB Local files 109 | .dynamodb/ 110 | 111 | # TernJS port file 112 | .tern-port 113 | 114 | # Stores VSCode versions used for testing VSCode extensions 115 | .vscode-test 116 | 117 | # yarn v2 118 | .yarn/cache 119 | .yarn/unplugged 120 | .yarn/build-state.yml 121 | .yarn/install-state.gz 122 | .pnp.* -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team [here](https://davidwells.io/contact/). All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at [http://contributor-covenant.org/version/1/4][version] 72 | 73 | [homepage]: http://contributor-covenant.org 74 | [version]: http://contributor-covenant.org/version/1/4/ -------------------------------------------------------------------------------- /utils/app.js: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | import path from 'path' 3 | import markdownMagic from 'markdown-magic' 4 | import Table from 'table-builder' 5 | import githubApi from './githubApi.js' 6 | 7 | /** 8 | * 9 | * Generate HTML table 10 | * @param {Object} tableHeaders 11 | * @param {Array} tableRows 12 | * @param {String} className 13 | * @returns {Object} htmlTable 14 | */ 15 | export const generateHtmlTable = function(tableHeaders, tableRows, className) { 16 | return ((new Table({'class': className})) 17 | .setHeaders(tableHeaders) 18 | .setData(tableRows) 19 | .render() 20 | ) 21 | } 22 | 23 | export const convertJsonToHtmlTable = function(content, options = {}, config) { 24 | const inputFilePath = options["src"] 25 | let tableRows = JSON.parse(fs.readFileSync(inputFilePath)) 26 | if(Object.keys(tableRows).length>0){ 27 | let tableHeaderData = Object.keys(tableRows[0]) 28 | let tableHeaders = {} 29 | tableHeaderData.forEach((header) => { 30 | tableHeaders[header]=header 31 | }) 32 | const htmlTable = generateHtmlTable(tableHeaders, tableRows, "JSON-TO-HTML-TABLE") 33 | return htmlTable 34 | }else { 35 | return "" 36 | } 37 | } 38 | 39 | /** 40 | * Module to generate artifacts html table. 41 | * @param {String} content 42 | * @param {Object} options 43 | * @param {Object} config 44 | * @returns {String} artifactsTable 45 | */ 46 | export const generateArtifactsTable = function(content, options = {}, config) { 47 | let workflows = config.workflows 48 | let tableRows = [] 49 | let tableHeaders = { "artifact" : "Artifact", "workflow": "Workflow" }; 50 | workflows.forEach((workflow) => { 51 | let workflow_name = `${workflow.name}` 52 | let artifacts = workflow["artifacts"] 53 | artifacts.forEach((artifact) => { 54 | let artifact_name = `${artifact.name}` 55 | tableRows.push({ 56 | "artifact": artifact_name, 57 | "workflow": workflow_name 58 | }) 59 | }) 60 | }) 61 | let artifactsTable = generateHtmlTable(tableHeaders, tableRows, "ARTIFACTS-TABLE") 62 | return artifactsTable 63 | } 64 | 65 | /** 66 | * @param {String} outputFilePath 67 | * @param {String} repo 68 | * @param {String} branch 69 | * @param {String} githubApiToken 70 | * @returns {String} message 71 | */ 72 | export const app = async function(outputFilePath, category, repo, branch, githubApiToken) { 73 | const markdownPath = path.join(outputFilePath) 74 | if(category == "code-block"){ 75 | const config = { 76 | matchWord: 'MARKDOWN-AUTO-DOCS' 77 | } 78 | markdownMagic(markdownPath, config) 79 | return `Auto documented code-block in ${outputFilePath}` 80 | }else if(category == "json-to-html-table"){ 81 | const config = { 82 | matchWord: 'MARKDOWN-AUTO-DOCS', 83 | transforms: { 84 | JSON_TO_HTML_TABLE: convertJsonToHtmlTable, 85 | }, 86 | } 87 | markdownMagic(markdownPath, config) 88 | return `Converted JSON to HTML table. Then auto-documented HTML table in ${outputFilePath}` 89 | }else if(category == "workflow-artifact-table"){ 90 | const github = new githubApi(repo, branch, githubApiToken) 91 | const workflowNames = await github.getWorkflowNames() 92 | const workflowIds = await github.getWorkflowIds(workflowNames) 93 | const workflowInfo = await github.getWorkflowArtifacts(workflowIds) 94 | const config = { 95 | matchWord: 'MARKDOWN-AUTO-DOCS', 96 | workflows: workflowInfo.workflowArtifacts, 97 | transforms: { 98 | WORKFLOW_ARTIFACT_TABLE: generateArtifactsTable, 99 | }, 100 | } 101 | markdownMagic(markdownPath, config) 102 | return `Auto documented ${workflowInfo.totalArtifacts} artifacts in artifactsTable - ${outputFilePath}` 103 | } 104 | } 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /.github/workflows/npm-publish.yml: -------------------------------------------------------------------------------- 1 | name: integration-tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | tags: 8 | - latest 9 | 10 | jobs: 11 | integration-tests: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - name: Install dependencies 17 | run: npm i 18 | 19 | - name: Start integration test 20 | env: 21 | TEST_REPO: ${{ secrets.TEST_REPO }} 22 | TEST_BRANCH: ${{ secrets.TEST_BRANCH }} 23 | TEST_ACCESSTOKEN: ${{ secrets.TEST_ACCESSTOKEN }} 24 | run: npm test 25 | 26 | - name: Upload Jest integration test report to Artifact 27 | uses: actions/upload-artifact@v2 28 | with: 29 | name: Jest-integration-test-report 30 | path: ${{ github.workspace }}/jest_html_reporters.html 31 | 32 | module-dependencies-license-checker: 33 | needs: integration-tests 34 | runs-on: ubuntu-latest 35 | steps: 36 | - uses: actions/checkout@v2 37 | 38 | - name: Install dependencies 39 | run: | 40 | sudo npm install -g license-checker 41 | npm i 42 | 43 | - name: Get all dependent module licenses 44 | run: | 45 | license-checker --summary 46 | license-checker --csv --out ./module-dependencies-license-report.csv 47 | 48 | - name: Upload module-dependencies license report to Artifact 49 | uses: actions/upload-artifact@v2 50 | with: 51 | name: module-dependencies-license-report 52 | path: ${{ github.workspace }}/module-dependencies-license-report.csv 53 | 54 | scan-for-vulnerabilities: 55 | needs: module-dependencies-license-checker 56 | runs-on: ubuntu-latest 57 | steps: 58 | - uses: actions/checkout@v2 59 | 60 | - name: Install dependencies 61 | run: | 62 | npm i 63 | sudo npm install -g npm-audit-html 64 | 65 | - name: Scan for vulnerabilities and report them in a html file 66 | run: npm audit --json | npm-audit-html --output vulnerabilities-audit-report.html 67 | 68 | - name: Upload vulnerabilities report to Artifact 69 | uses: actions/upload-artifact@v2 70 | with: 71 | name: vulnerabilities-audit-report 72 | path: ${{ github.workspace }}/vulnerabilities-audit-report.html 73 | 74 | size-of-dependencies-stats: 75 | needs: scan-for-vulnerabilities 76 | runs-on: ubuntu-latest 77 | steps: 78 | - uses: actions/checkout@v2 79 | 80 | - name: Install dependencies 81 | run: | 82 | sudo npm install -g cost-of-modules 83 | npm i 84 | 85 | - name: Get size of dependencies 86 | run: cost-of-modules | tee size-of-dependencies.log 87 | 88 | - name: Upload size of dependencies stats to Artifact 89 | uses: actions/upload-artifact@v2 90 | with: 91 | name: size-of-dependencies 92 | path: ${{ github.workspace }}/size-of-dependencies.log 93 | 94 | update_release_version: 95 | needs: size-of-dependencies-stats 96 | runs-on: ubuntu-latest 97 | steps: 98 | - uses: actions/checkout@v2 99 | - name: Update release and bump package version 100 | run: | 101 | sudo pip3 install ruamel.yaml 102 | sudo python3 update_release_version.py 103 | npm --no-git-tag-version version patch 104 | git config user.name dineshsonachalam 105 | git config user.email dineshsonachalam@gmail.com 106 | git add docs/latest-release.yml docs/markdown-autodocs.yml package.json 107 | git commit -m "Updated release version in YAML docs" docs/latest-release.yml docs/markdown-autodocs.yml package.json 108 | git push origin '${{ github.ref }}' 109 | 110 | deploy: 111 | needs: update_release_version 112 | runs-on: ubuntu-latest 113 | steps: 114 | - uses: actions/checkout@v2 115 | 116 | - uses: JS-DevTools/npm-publish@v1 117 | with: 118 | token: ${{ secrets.NPM_ACCESS_TOKEN }} -------------------------------------------------------------------------------- /utils/githubApi.js: -------------------------------------------------------------------------------- 1 | import {get, getYamlConfigValue} from './crud.js' 2 | 3 | const githubInfo = { 4 | "url": "https://github.com", 5 | "apiUrl": "https://api.github.com/repos", 6 | "workflowPath": ".github/workflows" 7 | } 8 | 9 | /** 10 | * Module to interact with Github Api 11 | * Author: Dinesh Sonachalam 12 | * @param {string} repo 13 | * @param {string} branch 14 | * @param {string} githubApiToken 15 | */ 16 | export default class githubApi { 17 | constructor(repo, branch, githubApiToken) { 18 | this.repo = repo 19 | this.branch = branch 20 | this.githubApiToken = githubApiToken 21 | this.headers = { 22 | Authorization: `Bearer ${this.githubApiToken}`, 23 | "User-Agent": "request" 24 | } 25 | } 26 | /** 27 | * Get all workflow names 28 | * @returns {Array} workflowNames 29 | */ 30 | async getWorkflowNames(){ 31 | const url = `${githubInfo.apiUrl}/${this.repo}/contents/${githubInfo.workflowPath}?ref=${this.branch}` 32 | const workflows = await get(url, this.headers) 33 | let workflowNames = [] 34 | for(var i = 0; i < workflows.length; i++) { 35 | var workflow = workflows[i]; 36 | const workflowYamlUrl = workflow.download_url 37 | let workflowName = await getYamlConfigValue(workflowYamlUrl, this.headers, "name") 38 | workflowNames.push(workflowName) 39 | } 40 | return workflowNames 41 | } 42 | 43 | /** 44 | * Get run_id and check_suite_id of a workflow run 45 | * @param {Array} workflowNames 46 | * @returns {Array} workflowIds 47 | */ 48 | async getWorkflowIds(workflowNames){ 49 | let workflowIds = [] 50 | let url = `${githubInfo.apiUrl}/${this.repo}/actions/runs?branch=${this.branch}` 51 | let workflowRuns = (await get(url, this.headers)).workflow_runs 52 | workflowRuns.forEach((workflowRun) => { 53 | let workflowName = workflowRun.name 54 | if(workflowNames.includes(workflowName)){ 55 | let runId = (workflowRun.id).toString(); 56 | let checkSuiteId = (workflowRun.check_suite_id).toString() 57 | workflowIds.push({ 58 | "name": workflowName, 59 | "run_url": `${githubInfo.url}/${this.repo}/actions/runs/${runId}`, 60 | "run_id": runId, 61 | "check_suite_id": checkSuiteId 62 | }) 63 | workflowNames = workflowNames.filter(item => item !== workflowName) 64 | if(workflowNames.length===0){ 65 | return workflowIds 66 | } 67 | } 68 | }); 69 | return workflowIds 70 | } 71 | 72 | /** 73 | * Get artifacts download URL 74 | * @param {string} runId 75 | * @param {string} checkSuiteId 76 | * @returns {array} artifactsDownloadUrl 77 | */ 78 | async getArtifactsDownloadUrl(runId, checkSuiteId){ 79 | let url = `${githubInfo.apiUrl}/${this.repo}/actions/runs/${runId}/artifacts` 80 | const artifacts = (await get(url, this.headers)).artifacts 81 | let artifactsDownloadUrl = [] 82 | for(var i = 0; i < artifacts.length; i++) { 83 | let artifact = artifacts[i] 84 | let artifactId = artifact.id 85 | let artifactName = artifact.name 86 | let artifactDownloadUrl = `${githubInfo.url}/${this.repo}/suites/${checkSuiteId}/artifacts/${artifactId}` 87 | artifactsDownloadUrl.push({ 88 | name: artifactName, 89 | url : artifactDownloadUrl 90 | }) 91 | } 92 | return artifactsDownloadUrl 93 | } 94 | 95 | /** 96 | * Get workflow artifacts 97 | * @param {Array} workflowIds 98 | * @returns {Object} workflowArtifacts, totalArtifacts 99 | */ 100 | async getWorkflowArtifacts(workflowIds){ 101 | let workflowArtifacts = [] 102 | let totalArtifacts = 0 103 | for(var i = 0; i < workflowIds.length; i++) { 104 | let workflow = workflowIds[i]; 105 | let runId = workflow['run_id'] 106 | let checkSuiteId = workflow['check_suite_id'] 107 | let artifacts = await this.getArtifactsDownloadUrl(runId, checkSuiteId) 108 | if(artifacts.length>0){ 109 | totalArtifacts = totalArtifacts + artifacts.length 110 | workflowArtifacts.push( 111 | { 112 | "name": workflow['name'], 113 | "run_url": workflow['run_url'], 114 | "run_id": runId, 115 | "check_suite_id": checkSuiteId, 116 | "artifacts": artifacts 117 | } 118 | ) 119 | } 120 | } 121 | return { 122 | "workflowArtifacts" : workflowArtifacts, 123 | "totalArtifacts" : totalArtifacts 124 | } 125 | } 126 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 |

6 |

A GitHub Action that automatically generates & updates markdown content (like your README.md) from external or remote files.

7 |

8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | npm version 16 | 17 | 18 | MIT License 19 | 20 |

21 | 22 | ## Table of contents 23 | - [Why markdown-autodocs?](#why-markdown-autodocs) 24 | - [Features](#features) 25 | - [Examples](#examples) 26 | - [CODE Block](#code-block) 27 | - [JSON to HTML table](#json-to-html-table) 28 | - [Github Workflow Artifacts table](#github-workflow-artifacts-table) 29 | - [Example Repo which uses all the markdown-autodocs feature](#example-repo-which-uses-all-the-markdown-autodocs-feature) 30 | - [Local usage without Github action](#local-usage-without-github-action) 31 | - [Usage](#usage) 32 | - [Adding markdown-autodocs in your workflow](#adding-markdown-autodocs-in-your-workflow) 33 | - [Extended example with all possible options available for this Action](#extended-example-with-all-possible-options-available-for-this-action) 34 | - [Github Workflow Artifacts](#github-workflow-artifacts) 35 | - [Contributing](#contributing) 36 | - [Used By](#-used-by) 37 | - [License](#license) 38 | 39 | ## Why markdown-autodocs? 40 | To make your repo more appealing and useful you need to provide example code snippets in your README.md. Manually copy and pasting each code snippet in their respective places in your README would be inefficient and time-consuming. 41 | 42 | This problem can be solved using markdown-autodocs a GitHub Action that automatically generates & updates markdown content (like your README.md) from external or remote files. You need to add markers in your README.md that will tell markdown-autodocs where to insert the code snippet. 43 | 44 | ## Features 45 | * Code block: Insert code snippet in your markdown file from external or remote files. 46 | * JSON to HTML table: Insert HTML Table in your markdown file by converting JSON file contents to HTML table. 47 | * Github Workflow Artifacts table: Insert the Github workflow artifacts table in your markdown file by getting the latest artifacts for a workflow run. 48 | 49 | ## Examples 50 | 51 | ### CODE Block 52 | 53 | Get code from an external file or URL and insert it in your markdown. 54 | 55 | **Options:** 56 | - `src`: The relative path to the code to pull in, or the `URL` where the raw code lives 57 | 58 |

Get code from external file

59 | 60 | 61 | 62 | 63 | 64 |

Get code from remote file

65 | 66 | 67 | 68 | 69 | ### JSON to HTML table 70 | Get JSON contents from an external file and convert it into an HTML table and insert's it in your markdown. 71 | 72 | **Options:** 73 | - `src`: The relative path to the JSON file to pull in. 74 | 75 | 76 | 77 | 78 | 79 | ### Github Workflow Artifacts table 80 | 81 | Get the list of the latest artifacts generated from a workflow run. Generates a workflow artifacts table consists of artifacts download and workflow URL in an HTML table and inserts it in your markdown file. 82 | 83 | 84 | 85 | 86 | 87 | ### [Example Repo which uses all the markdown-autodocs feature](https://github.com/dineshsonachalam/repo-using-markdown-autodocs) 88 | 89 | ## Local usage without Github action 90 | 91 | **Install markdown-autodocs CLI:** 92 | ``` 93 | npm i -g markdown-autodocs 94 | ``` 95 | 96 | **markdown-autodocs CLI usage:** 97 | ``` 98 | dineshsonachalam@macbook ~ % markdown-autodocs --help 99 | Usage: markdown-autodocs [options] 100 | 101 | Options: 102 | -o, --outputFilePath Output file paths 103 | -c, --category code-block, json-to-html-table, workflow-artifact-table 104 | -r, --repo Repo name 105 | -b, --branch Branch name 106 | -a, --accessToken Github Access token 107 | -h, --help display help for command 108 | ``` 109 | 110 | 1. Code block 111 | ``` 112 | markdown-autodocs -c code-block -o ./README.md 113 | ``` 114 | 2. JSON to HTML table 115 | ``` 116 | markdown-autodocs -c json-to-html-table -o ./README.md 117 | ``` 118 | 3. Github workflow artifacts table 119 | ``` 120 | markdown-autodocs -c workflow-artifact-table -o ./README.md -r $REPO -b $BRANCH -a $ACCESSTOKEN 121 | ``` 122 | 123 | ## Usage 124 | 125 | ### Adding markdown-autodocs in your workflow 126 | Add the following step at the end of your job, after other steps that might add or change files. 127 | 128 | 129 | ```yml 130 | uses: dineshsonachalam/markdown-autodocs@v1.0.2 131 | ``` 132 | 133 | 134 | ### Extended example with all possible options available for this Action 135 | 136 | 137 | ```yml 138 | - name: Markdown autodocs 139 | - uses: dineshsonachalam/markdown-autodocs@v1.0.2 140 | with: 141 | # Optional, defaults to author of the commit that triggered the run 142 | commit_author: Author 143 | 144 | # Optional, defaults to "actions@github.com" 145 | commit_user_email: actions@github.com 146 | 147 | # Optional, but recommended 148 | # Defaults to "Apply automatic changes" 149 | commit_message: Apply automatic changes 150 | 151 | # Optional branch name where commit should be pushed to. 152 | # Defaults to the current branch. 153 | branch: feature-123 154 | 155 | # Optional output file paths, defaults to '[./README.md]'. 156 | output_file_paths: '[./README.md]' 157 | 158 | # Categories to automatically sync or transform its contents in the markdown files. 159 | # Defaults to '[code-block,json-to-html-table,workflow-artifact-table]' 160 | categories: '[code-block,json-to-html-table,workflow-artifact-table]' 161 | ``` 162 | 163 | 164 | ## Github Workflow Artifacts 165 | 166 | 167 | 168 | 169 | 170 |
ArtifactWorkflow
Jest-integration-test-reportintegration-tests
module-dependencies-license-reportintegration-tests
size-of-dependenciesintegration-tests
vulnerabilities-audit-reportintegration-tests
171 | 172 | 173 | ## Contributing 174 | 175 | 176 | * [Code of Conduct](CODE_OF_CONDUCT.md) 177 | * [Contributing Guideline](CONTRIBUTING.md) 178 | 179 | ## 🚀 Used By 180 | 181 | * [iro.js - 🎨 Modular color picker widget for JavaScript, with support for a bunch of color formats](https://github.com/jaames/iro.js) 182 | * [LucidDynamodb - A minimalistic wrapper to AWS DynamoDB](https://github.com/dineshsonachalam/Lucid-Dynamodb) 183 | 184 | 185 | 186 | ## License 187 | 188 | [MIT](https://choosealicense.com/licenses/mit/) © [dineshsonachalam](https://www.github.com/dineshsonachalam) 189 | --------------------------------------------------------------------------------