├── .cspell.json ├── .devcontainer ├── Dockerfile ├── devcontainer.json └── welcome.txt ├── .editorconfig ├── .eslintignore ├── .eslintrc.json ├── .github ├── dependabot.yml └── workflows │ ├── ci.yml │ ├── codeql.yml │ ├── dependabot.yml │ ├── mega-linter.yml │ ├── release.yml │ └── sonar.yml ├── .gitignore ├── .jscpd.json ├── .markdownlintignore ├── .mega-linter.yml ├── .nvmrc ├── .prettierignore ├── .trivyignore ├── .vscode ├── extensions.json └── settings.json ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── __tests__ ├── action-docs-action.test.ts ├── action-docs-workflow.test.ts ├── cli.test.ts ├── fixtures │ ├── action │ │ ├── action.yml │ │ ├── action_deprecated.input │ │ ├── action_deprecated.output │ │ ├── action_docs_action_action.yml │ │ ├── action_docs_action_readme.input │ │ ├── action_docs_action_readme.output │ │ ├── action_usage_readme.input │ │ ├── action_usage_readme.output │ │ ├── all_fields_action.output │ │ ├── all_fields_action.yml │ │ ├── all_fields_action.yml.crlf │ │ ├── all_fields_action_toc1.output │ │ ├── all_fields_action_toc3_cli.output │ │ ├── all_fields_one_annotation.input │ │ ├── all_fields_one_annotation.output │ │ ├── all_fields_readme.input │ │ ├── all_fields_readme.input.crlf │ │ ├── all_fields_readme.output │ │ ├── all_fields_readme.output.crlf │ │ ├── all_fields_readme_filled.input │ │ ├── all_fields_readme_filled.output │ │ ├── all_fields_readme_header.output │ │ ├── all_fields_usage_readme.input │ │ ├── all_fields_usage_readme.output │ │ ├── default-with-header.output │ │ ├── default.output │ │ ├── deprecated_input_action.input │ │ ├── deprecated_input_action.output │ │ ├── deprecated_input_action.yml │ │ ├── minimal_action.output │ │ ├── minimal_action.yml │ │ ├── two_actions_readme.input │ │ └── two_actions_readme.output │ └── workflow │ │ ├── action_docs_workflow.yml │ │ ├── action_docs_workflow_readme.input │ │ ├── action_docs_workflow_readme.output │ │ ├── all_fields_one_annotation.input │ │ ├── all_fields_one_annotation.output │ │ ├── all_fields_readme.input │ │ ├── all_fields_readme.input.crlf │ │ ├── all_fields_readme.output │ │ ├── all_fields_readme.output.crlf │ │ ├── all_fields_readme_filled.input │ │ ├── all_fields_readme_filled.output │ │ ├── all_fields_usage_readme.input │ │ ├── all_fields_usage_readme.output │ │ ├── all_fields_workflow.output │ │ ├── all_fields_workflow.yml │ │ ├── all_fields_workflow.yml.crlf │ │ ├── all_fields_workflow_toc1.output │ │ ├── all_fields_workflow_toc3_cli.output │ │ ├── default.output │ │ ├── minimal_workflow.output │ │ ├── minimal_workflow.yml │ │ ├── secrets_workflow.output │ │ ├── secrets_workflow.yml │ │ ├── two_workflows_readme.input │ │ ├── two_workflows_readme.output │ │ ├── workflow.yml │ │ ├── workflow_usage_readme.input │ │ └── workflow_usage_readme.output └── linebreak.test.ts ├── jest.config.js ├── package.json ├── sonar-project.properties ├── src ├── action-docs.ts ├── cli.ts ├── index.ts └── linebreak.ts ├── tsconfig.json └── yarn.lock /.cspell.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignorePaths": [ 3 | "**/node_modules/**", 4 | "**/vscode-extension/**", 5 | "**/.git/**", 6 | "**/.pnpm-lock.json", 7 | ".vscode", 8 | "megalinter", 9 | "package-lock.json", 10 | "report", 11 | ".*" 12 | ], 13 | "ignoreWords": [ 14 | "niek", 15 | "npalm", 16 | "nvmrc", 17 | "markdownlintignore", 18 | "devcontainer" 19 | ], 20 | "language": "en", 21 | "noConfigSearch": true, 22 | "words": ["linebreak", "megalinter", "oxsecurity", "REAMDE"], 23 | "version": "0.2" 24 | } 25 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG VARIANT="20-bullseye" 2 | FROM mcr.microsoft.com/vscode/devcontainers/typescript-node:1-${VARIANT} 3 | 4 | # hadolint ignore=DL3008 5 | RUN apt-get update && apt-get install bash-completion gnupg2 --no-install-recommends -y && rm -rf /var/lib/apt/lists/* 6 | 7 | USER node 8 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "GitHub Runners AWS", 3 | "build": { "dockerfile": "Dockerfile" }, 4 | "features": { 5 | "ghcr.io/devcontainers/features/github-cli:1": {}, 6 | "ghcr.io/devcontainers-contrib/features/prettier:1": {} 7 | }, 8 | "remoteEnv": { 9 | "GITHUB_TOKEN": "${localEnv:GITHUB_TOKEN}" 10 | }, 11 | "customizations": { 12 | "vscode": { 13 | "extensions": [ 14 | "editorconfig.editorconfig", 15 | "esbenp.prettier-vscode", 16 | "github.vscode-pull-request-github", 17 | "orta.vscode-jest", 18 | "yzhang.markdown-all-in-one" 19 | ] 20 | } 21 | }, 22 | "postCreateCommand": "yarn install", 23 | "waitFor": "postCreateCommand", 24 | "onCreateCommand": "sudo cp .devcontainer/welcome.txt /usr/local/etc/vscode-dev-containers/first-run-notice.txt", 25 | } 26 | -------------------------------------------------------------------------------- /.devcontainer/welcome.txt: -------------------------------------------------------------------------------- 1 | ,-----. _,-._ 2 | / \ / \_/ \ 3 | | action | >-(_)-< Generate docs 4 | \ / \_/ \_/ for your actions. 5 | `-----' `-' 6 | 7 | Welcome to action-docs 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | end_of_line = lf 3 | insert_final_newline = true 4 | 5 | [*.crlf] 6 | end_of_line = crlf 7 | tab_width = 20 8 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | lib/ 3 | node_modules/ 4 | jest.config.js 5 | __tests__/ 6 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["import", "jest", "@typescript-eslint"], 3 | "extends": ["plugin:github/recommended"], 4 | "parser": "@typescript-eslint/parser", 5 | "parserOptions": { 6 | "ecmaVersion": 9, 7 | "sourceType": "module", 8 | "project": "./tsconfig.json" 9 | }, 10 | "settings": { 11 | "import/resolver": { 12 | "typescript": {} 13 | } 14 | }, 15 | "rules": { 16 | "no-console": "off", 17 | "eslint-comments/no-use": "off", 18 | "import/no-namespace": "off", 19 | "import/no-unresolved": "error", 20 | "no-unused-vars": "off", 21 | "@typescript-eslint/no-unused-vars": "error", 22 | "@typescript-eslint/explicit-member-accessibility": [ 23 | "error", 24 | { "accessibility": "no-public" } 25 | ], 26 | "@typescript-eslint/no-require-imports": "error", 27 | "@typescript-eslint/array-type": "error", 28 | "@typescript-eslint/await-thenable": "error", 29 | "@typescript-eslint/ban-ts-comment": "error", 30 | "camelcase": "off", 31 | "@typescript-eslint/consistent-type-assertions": "error", 32 | "@typescript-eslint/explicit-function-return-type": [ 33 | "error", 34 | { "allowExpressions": true } 35 | ], 36 | "@typescript-eslint/func-call-spacing": ["error", "never"], 37 | "@typescript-eslint/no-array-constructor": "error", 38 | "@typescript-eslint/no-empty-interface": "error", 39 | "@typescript-eslint/no-explicit-any": "error", 40 | "@typescript-eslint/no-extraneous-class": "error", 41 | "@typescript-eslint/no-for-in-array": "error", 42 | "@typescript-eslint/no-inferrable-types": "error", 43 | "@typescript-eslint/no-misused-new": "error", 44 | "@typescript-eslint/no-namespace": "error", 45 | "@typescript-eslint/no-non-null-assertion": "warn", 46 | "@typescript-eslint/no-unnecessary-qualifier": "error", 47 | "@typescript-eslint/no-unnecessary-type-assertion": "error", 48 | "@typescript-eslint/no-useless-constructor": "error", 49 | "@typescript-eslint/no-var-requires": "error", 50 | "@typescript-eslint/prefer-for-of": "warn", 51 | "@typescript-eslint/prefer-function-type": "warn", 52 | "@typescript-eslint/prefer-includes": "error", 53 | "@typescript-eslint/prefer-string-starts-ends-with": "error", 54 | "@typescript-eslint/promise-function-async": "error", 55 | "@typescript-eslint/require-array-sort-compare": "error", 56 | "@typescript-eslint/restrict-plus-operands": "error", 57 | "@typescript-eslint/type-annotation-spacing": "error", 58 | "@typescript-eslint/unbound-method": "error", 59 | "no-shadow": "off", 60 | "@typescript-eslint/no-shadow": "error" 61 | }, 62 | "env": { 63 | "node": true, 64 | "es6": true, 65 | "jest/globals": true 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | # Enable version updates for npm 4 | - package-ecosystem: "npm" 5 | # Look for `package.json` and `lock` files in the `root` directory 6 | directory: "/" 7 | # Check the npm registry for updates every day (weekdays) 8 | schedule: 9 | interval: "daily" 10 | # set descriptive commit message 11 | commit-message: 12 | prefix-development: "chore(deps)" 13 | prefix: "fix(deps)" 14 | groups: 15 | octokit: 16 | patterns: 17 | - "@octokit/*" 18 | eslint: 19 | patterns: 20 | - "eslint*" 21 | jest: 22 | patterns: 23 | - "*jest*" 24 | figlet: 25 | patterns: 26 | - "*figlet*" 27 | 28 | # Maintain dependencies for GitHub Actions 29 | - package-ecosystem: "github-actions" 30 | directory: "/" 31 | schedule: 32 | interval: "weekly" 33 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: "build" 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | types: [opened, synchronize, reopened] 8 | 9 | permissions: 10 | contents: read 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | strategy: 16 | matrix: 17 | node-version: ["20"] 18 | steps: 19 | - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 20 | with: 21 | egress-policy: audit 22 | 23 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 24 | with: 25 | fetch-depth: 0 26 | 27 | - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 28 | with: 29 | node-version: ${{ matrix.node-version }} 30 | - name: Install dependencies 31 | run: yarn install --frozen-lockfile 32 | 33 | - name: Check format and lint 34 | run: yarn run format-check && yarn run lint 35 | 36 | - name: Build and package 37 | run: yarn run build 38 | 39 | - name: Run tests 40 | run: yarn test 41 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: "Code scanning" 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request_target: 7 | # The branches below must be a subset of the branches above 8 | branches: [main] 9 | 10 | jobs: 11 | CodeQL-Build: 12 | runs-on: ubuntu-latest 13 | permissions: 14 | contents: read 15 | security-events: write 16 | pull-requests: read 17 | actions: read 18 | steps: 19 | - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 20 | with: 21 | egress-policy: audit 22 | 23 | - name: Checkout repository 24 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 25 | 26 | - name: Initialize CodeQL 27 | uses: github/codeql-action/init@65c74964a9ed8c44ed9f19d4bbc5757a6a8e9ab9 # v2.16.1 28 | 29 | - name: Autobuild 30 | uses: github/codeql-action/autobuild@65c74964a9ed8c44ed9f19d4bbc5757a6a8e9ab9 # v2.16.1 31 | 32 | - name: Perform CodeQL Analysis 33 | uses: github/codeql-action/analyze@65c74964a9ed8c44ed9f19d4bbc5757a6a8e9ab9 # v2.16.1 34 | -------------------------------------------------------------------------------- /.github/workflows/dependabot.yml: -------------------------------------------------------------------------------- 1 | name: Dependabot auto approve 2 | on: pull_request_target 3 | 4 | permissions: 5 | pull-requests: write 6 | contents: write 7 | 8 | jobs: 9 | dependabot: 10 | runs-on: ubuntu-latest 11 | if: ${{ github.actor == 'dependabot[bot]' }} 12 | steps: 13 | - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 14 | with: 15 | egress-policy: audit 16 | 17 | - name: Dependabot metadata 18 | id: metadata 19 | uses: dependabot/fetch-metadata@dbb049abf0d677abbd7f7eee0375145b417fdd34 # v2.2.0 20 | with: 21 | github-token: "${{ secrets.GITHUB_TOKEN }}" 22 | 23 | - name: Checkout 24 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 25 | 26 | - name: Approve a PR 27 | run: gh pr review --approve "$PR_URL" 28 | env: 29 | PR_URL: ${{ github.event.pull_request.html_url }} 30 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 31 | -------------------------------------------------------------------------------- /.github/workflows/mega-linter.yml: -------------------------------------------------------------------------------- 1 | name: MegaLinter 2 | 3 | on: 4 | # Comment this line to trigger action only on pull-requests 5 | # (not recommended if you don't pay for GH Actions) 6 | push: 7 | branches: 8 | - main 9 | pull_request: 10 | branches: 11 | - main 12 | 13 | env: 14 | APPLY_FIXES: all 15 | APPLY_FIXES_EVENT: pull_request 16 | APPLY_FIXES_MODE: commit 17 | 18 | concurrency: 19 | group: ${{ github.ref }}-${{ github.workflow }} 20 | cancel-in-progress: true 21 | 22 | jobs: 23 | megalinter: 24 | name: MegaLinter 25 | runs-on: ubuntu-latest 26 | 27 | permissions: 28 | contents: write 29 | issues: write 30 | pull-requests: write 31 | 32 | steps: 33 | - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 34 | with: 35 | egress-policy: audit 36 | 37 | - name: Checkout Code 38 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 39 | with: 40 | token: ${{ secrets.GITHUB_TOKEN }} 41 | fetch-depth: 0 42 | 43 | - name: MegaLinter 44 | uses: oxsecurity/megalinter/flavors/javascript@f90c800040e4f84800700b27b2394d3eecc1fdad # v8.4.0 45 | id: ml 46 | 47 | env: 48 | # Validates all source when push on main, else just the git diff with 49 | # main. Override with true if you always want to lint all sources 50 | # 51 | # To validate the entire codebase, set to: 52 | # VALIDATE_ALL_CODEBASE: true 53 | # 54 | # To validate only diff with main, set to: 55 | # VALIDATE_ALL_CODEBASE: >- 56 | # ${{ 57 | # github.event_name == 'push' && 58 | # github.ref == 'refs/heads/main' 59 | # }} 60 | VALIDATE_ALL_CODEBASE: >- 61 | ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} 62 | 63 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 64 | 65 | # Upload MegaLinter artifacts 66 | - name: Archive production artifacts 67 | uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 68 | if: success() || failure() 69 | with: 70 | name: MegaLinter reports 71 | path: | 72 | megalinter-reports 73 | mega-linter.log 74 | 75 | # Create pull request if applicable 76 | # (for now works only on PR from same repository, not from forks) 77 | - name: Create Pull Request with applied fixes 78 | uses: peter-evans/create-pull-request@5e914681df9dc83aa4e4905692ca88beb2f9e91f # v7.0.5 79 | id: cpr 80 | if: >- 81 | steps.ml.outputs.has_updated_sources == 1 && 82 | ( 83 | env.APPLY_FIXES_EVENT == 'all' || 84 | env.APPLY_FIXES_EVENT == github.event_name 85 | ) && 86 | env.APPLY_FIXES_MODE == 'pull_request' && 87 | ( 88 | github.event_name == 'push' || 89 | github.event.pull_request.head.repo.full_name == github.repository 90 | ) && 91 | !contains(github.event.head_commit.message, 'skip fix') 92 | with: 93 | token: ${{ secrets.GITHUB_TOKEN }} 94 | commit-message: "[MegaLinter] Apply linters automatic fixes" 95 | title: "[MegaLinter] Apply linters automatic fixes" 96 | labels: bot 97 | 98 | - name: Create PR output 99 | if: >- 100 | steps.ml.outputs.has_updated_sources == 1 && 101 | ( 102 | env.APPLY_FIXES_EVENT == 'all' || 103 | env.APPLY_FIXES_EVENT == github.event_name 104 | ) && 105 | env.APPLY_FIXES_MODE == 'pull_request' && 106 | ( 107 | github.event_name == 'push' || 108 | github.event.pull_request.head.repo.full_name == github.repository 109 | ) && 110 | !contains(github.event.head_commit.message, 'skip fix') 111 | run: | 112 | echo "PR Number - ${{ steps.cpr.outputs.pull-request-number }}" 113 | echo "PR URL - ${{ steps.cpr.outputs.pull-request-url }}" 114 | 115 | # Push new commit if applicable 116 | # (for now works only on PR from same repository, not from forks) 117 | - name: Prepare commit 118 | if: >- 119 | steps.ml.outputs.has_updated_sources == 1 && 120 | ( 121 | env.APPLY_FIXES_EVENT == 'all' || 122 | env.APPLY_FIXES_EVENT == github.event_name 123 | ) && 124 | env.APPLY_FIXES_MODE == 'commit' && 125 | github.ref != 'refs/heads/main' && 126 | ( 127 | github.event_name == 'push' || 128 | github.event.pull_request.head.repo.full_name == github.repository 129 | ) && 130 | !contains(github.event.head_commit.message, 'skip fix') 131 | run: sudo chown -Rc $UID .git/ 132 | 133 | - name: Commit and push applied linter fixes 134 | uses: stefanzweifel/git-auto-commit-action@8621497c8c39c72f3e2a999a26b4ca1b5058a842 # v5.0.1 135 | if: >- 136 | steps.ml.outputs.has_updated_sources == 1 && 137 | ( 138 | env.APPLY_FIXES_EVENT == 'all' || 139 | env.APPLY_FIXES_EVENT == github.event_name 140 | ) && 141 | env.APPLY_FIXES_MODE == 'commit' && 142 | github.ref != 'refs/heads/main' && 143 | ( 144 | github.event_name == 'push' || 145 | github.event.pull_request.head.repo.full_name == github.repository 146 | ) && 147 | !contains(github.event.head_commit.message, 'skip fix') 148 | with: 149 | branch: >- 150 | ${{ 151 | github.event.pull_request.head.ref || 152 | github.head_ref || 153 | github.ref 154 | }} 155 | commit_message: "[MegaLinter] Apply linters fixes" 156 | commit_user_name: megalinter-bot 157 | commit_user_email: nicolas.vuillamy@ox.security 158 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: "Release" 2 | on: 3 | push: 4 | branches: 5 | - main 6 | workflow_dispatch: 7 | 8 | permissions: 9 | contents: write 10 | packages: write 11 | pull-requests: write 12 | 13 | jobs: 14 | release: 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 19 | with: 20 | egress-policy: audit 21 | 22 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 23 | with: 24 | fetch-depth: 0 25 | persist-credentials: false 26 | 27 | - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 28 | with: 29 | node-version: 20 30 | always-auth: true 31 | registry-url: "https://registry.npmjs.org" 32 | 33 | - name: Install dependencies 34 | run: yarn --frozen-lockfile 35 | 36 | - name: Run checks 37 | run: yarn run test && yarn lint && yarn build 38 | 39 | # Use an app to authenticate to trigger workflows on the repository 40 | - name: Get app installation token 41 | uses: actions/create-github-app-token@c1a285145b9d317df6ced56c09f525b5c2b6f755 # v1.11.1 42 | id: app-token 43 | with: 44 | app-id: ${{ vars.APP_ID }} 45 | private-key: ${{ secrets.APP_PRIVATE_KEY }} 46 | 47 | - uses: googleapis/release-please-action@7987652d64b4581673a76e33ad5e98e3dd56832f # v.1.3 48 | id: release 49 | with: 50 | token: ${{ steps.app-token.outputs.token }} 51 | release-type: node 52 | 53 | - name: Publish to NPM 54 | run: yarn publish 55 | if: ${{ steps.release.outputs.release_created }} 56 | env: 57 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 58 | -------------------------------------------------------------------------------- /.github/workflows/sonar.yml: -------------------------------------------------------------------------------- 1 | name: "sonar" 2 | on: 3 | push: 4 | branches: 5 | - main 6 | # See https://docs.github.com/en/actions/reference/events-that-trigger-workflows#pull_request_target for security implications. 7 | pull_request_target: 8 | types: [opened, synchronize, reopened] 9 | 10 | permissions: 11 | contents: read 12 | pull-requests: write 13 | 14 | jobs: 15 | sonr: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 19 | with: 20 | egress-policy: audit 21 | 22 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 23 | with: 24 | fetch-depth: 0 25 | 26 | - name: Get info 27 | id: info 28 | run: | 29 | echo "repo_name=$(echo "$GITHUB_REPOSITORY"| cut -d / -f 2)" >> "$GITHUB_OUTPUT" 30 | echo "repo_owner=$(echo "$GITHUB_REPOSITORY"| cut -d / -f 1)" >> "$GITHUB_OUTPUT" 31 | 32 | - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 33 | with: 34 | node-version: 20 35 | - name: Install dependencies 36 | run: yarn install --frozen-lockfile 37 | 38 | - name: Run all checks and build 39 | run: yarn run all 40 | 41 | - name: SonarCloud Scan 42 | uses: sonarsource/sonarqube-scan-action@2500896589ef8f7247069a56136f8dc177c27ccf 43 | env: 44 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 45 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} 46 | with: 47 | args: > 48 | -Dsonar.organization=${{ steps.info.outputs.repo_owner }} 49 | -Dsonar.projectKey=${{ steps.info.outputs.repo_name }} 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependency directory 2 | node_modules 3 | 4 | # Rest pulled from https://github.com/github/gitignore/blob/master/Node.gitignore 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | 13 | # Diagnostic reports (https://nodejs.org/api/report.html) 14 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 15 | 16 | # Runtime data 17 | pids 18 | *.pid 19 | *.seed 20 | *.pid.lock 21 | 22 | # Directory for instrumented libs generated by jscoverage/JSCover 23 | lib-cov 24 | 25 | # Coverage directory used by tools like istanbul 26 | coverage** 27 | *.lcov 28 | 29 | # nyc test coverage 30 | .nyc_output 31 | 32 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 33 | .grunt 34 | 35 | # Bower dependency directory (https://bower.io/) 36 | bower_components 37 | 38 | # node-waf configuration 39 | .lock-wscript 40 | 41 | # Compiled binary addons (https://nodejs.org/api/addons.html) 42 | build/Release 43 | 44 | # Dependency directories 45 | jspm_packages/ 46 | 47 | # TypeScript v1 declaration files 48 | typings/ 49 | 50 | # TypeScript cache 51 | *.tsbuildinfo 52 | 53 | # Optional npm cache directory 54 | .npm 55 | 56 | # Optional eslint cache 57 | .eslintcache 58 | 59 | # Optional REPL history 60 | .node_repl_history 61 | 62 | # Output of 'npm pack' 63 | *.tgz 64 | 65 | # Yarn Integrity file 66 | .yarn-integrity 67 | 68 | # dotenv environment variables file 69 | .env 70 | .env.test 71 | 72 | # parcel-bundler cache (https://parceljs.org/) 73 | .cache 74 | 75 | # next.js build output 76 | .next 77 | 78 | # nuxt.js build output 79 | .nuxt 80 | 81 | # vuepress build output 82 | .vuepress/dist 83 | 84 | # Serverless directories 85 | .serverless/ 86 | 87 | # FuseBox cache 88 | .fusebox/ 89 | 90 | # DynamoDB Local files 91 | .dynamodb/ 92 | 93 | # OS metadata 94 | .DS_Store 95 | Thumbs.db 96 | 97 | .npmrc 98 | lib 99 | .scannerwork/ 100 | 101 | megalinter-reports/ 102 | -------------------------------------------------------------------------------- /.jscpd.json: -------------------------------------------------------------------------------- 1 | { 2 | "threshold": 0, 3 | "reporters": ["html", "markdown"], 4 | "ignore": [ 5 | "**/node_modules/**", 6 | "**/.git/**", 7 | "**/.rbenv/**", 8 | "**/.venv/**", 9 | "**/*cache*/**", 10 | "**/.github/**", 11 | "**/.idea/**", 12 | "**/report/**", 13 | "**/*.svg" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /.markdownlintignore: -------------------------------------------------------------------------------- 1 | CHANGELOG.md 2 | -------------------------------------------------------------------------------- /.mega-linter.yml: -------------------------------------------------------------------------------- 1 | # Configuration file for MegaLinter 2 | # 3 | # See all available variables at https://megalinter.io/latest/config-file/ and in 4 | # linters documentation 5 | 6 | # all, none, or list of linter keys 7 | APPLY_FIXES: all 8 | 9 | # If you use ENABLE variable, all other languages/formats/tooling-formats will 10 | # be disabled by default 11 | # ENABLE: 12 | 13 | # If you use ENABLE_LINTERS variable, all other linters will be disabled by 14 | # default 15 | # ENABLE_LINTERS: 16 | 17 | # DISABLE: 18 | # - COPYPASTE # Uncomment to disable checks of excessive copy-pastes 19 | # - SPELL # Uncomment to disable checks of spelling mistakes 20 | 21 | SHOW_ELAPSED_TIME: true 22 | 23 | FILEIO_REPORTER: false 24 | # Uncomment if you want MegaLinter to detect errors but not block CI to pass 25 | # DISABLE_ERRORS: true 26 | 27 | DISABLE_LINTERS: 28 | - REPOSITORY_DEVSKIM 29 | - TYPESCRIPT_STANDARD 30 | - TYPESCRIPT_ES 31 | - REPOSITORY_CHECKOV 32 | - COPYPASTE_JSCPD 33 | - JAVASCRIPT_ES 34 | 35 | JSON_JSONLINT_FILTER_REGEX_EXCLUDE: (tsconfig.json) 36 | 37 | SPELL_LYCHEE_FILTER_REGEX_EXCLUDE: (CHANGELOG.md) 38 | 39 | MARKDOWN_MARKDOWN_LINK_CHECK_FILTER_REGEX_EXCLUDE: (CHANGELOG.md) 40 | 41 | EDITORCONFIG_EDITORCONFIG_CHECKER_FILTER_REGEX_EXCLUDE: (__tests__/fixtures/*.crlf) 42 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v20 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | lib/ 3 | node_modules/ 4 | -------------------------------------------------------------------------------- /.trivyignore: -------------------------------------------------------------------------------- 1 | # Healthcheck isn't necessary in a devcontainer 2 | AVD-DS-0026 3 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp 6 | "editorconfig.editorconfig", 7 | "esbenp.prettier-vscode", 8 | "github.vscode-pull-request-github", 9 | "ms-vscode-remote.remote-containers", 10 | "orta.vscode-jest", 11 | "yzhang.markdown-all-in-one" 12 | ] 13 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[typescript]": { 3 | "editor.defaultFormatter": "esbenp.prettier-vscode", 4 | "editor.formatOnSave": true 5 | }, 6 | "[md]": { 7 | "editor.defaultFormatter": "esbenp.prettier-vscode", 8 | "editor.formatOnSave": true 9 | }, 10 | "[json]": { 11 | "editor.defaultFormatter": "esbenp.prettier-vscode", 12 | "editor.formatOnSave": true 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [2.5.2](https://github.com/npalm/action-docs/compare/v2.5.1...v2.5.2) (2025-02-11) 4 | 5 | 6 | ### Bug Fixes 7 | 8 | * **deps:** bump cross-spawn from 7.0.3 to 7.0.6 in the npm_and_yarn group ([#748](https://github.com/npalm/action-docs/issues/748)) ([60329fe](https://github.com/npalm/action-docs/commit/60329fe50c75418229461e7c186e37b8eb079035)) 9 | * **deps:** bump yaml from 2.6.0 to 2.7.0 ([#770](https://github.com/npalm/action-docs/issues/770)) ([ca38507](https://github.com/npalm/action-docs/commit/ca385078bcff6f55aea72d52e0731e44ff29c0b1)) 10 | 11 | ## [2.5.1](https://github.com/npalm/action-docs/compare/v2.5.0...v2.5.1) (2024-11-10) 12 | 13 | 14 | ### Bug Fixes 15 | 16 | * **deps:** bump yaml from 2.5.1 to 2.6.0 ([#722](https://github.com/npalm/action-docs/issues/722)) ([ab3653b](https://github.com/npalm/action-docs/commit/ab3653bc9ea392cfaa3a8f33ba4b43281af60ebb)) 17 | 18 | ## [2.5.0](https://github.com/npalm/action-docs/compare/v2.4.3...v2.5.0) (2024-10-12) 19 | 20 | 21 | ### Features 22 | 23 | * add support for secrets on workflow_call ([#658](https://github.com/npalm/action-docs/issues/658)) ([f427c9a](https://github.com/npalm/action-docs/commit/f427c9ae4a461111334a2d7a6b0c05cafcff56ee)) 24 | 25 | 26 | ### Bug Fixes 27 | 28 | * **deps:** bump yaml from 2.5.0 to 2.5.1 ([#692](https://github.com/npalm/action-docs/issues/692)) ([92755ae](https://github.com/npalm/action-docs/commit/92755aeeec47a015b2dcbdfba12155b65985cfb6)) 29 | * upgrade replace-in-file and figlet depenencies ([e585c0f](https://github.com/npalm/action-docs/commit/e585c0fd9a1409e417c6bee2f62ff6d869ffa388)) 30 | 31 | ## [2.4.3](https://github.com/npalm/action-docs/compare/v2.4.2...v2.4.3) (2024-09-03) 32 | 33 | 34 | ### Bug Fixes 35 | 36 | * **deps:** bump micromatch from 4.0.5 to 4.0.8 in the npm_and_yarn group ([#689](https://github.com/npalm/action-docs/issues/689)) ([f3f9983](https://github.com/npalm/action-docs/commit/f3f9983a041d6e2b33584644cf3c0b47996afc27)) 37 | * **deps:** bump yaml from 2.4.2 to 2.5.0 ([#665](https://github.com/npalm/action-docs/issues/665)) ([de67387](https://github.com/npalm/action-docs/commit/de67387cc6a8fdb651e39bb1b8011406c55bac9a)) 38 | 39 | ## [2.4.2](https://github.com/npalm/action-docs/compare/v2.4.1...v2.4.2) (2024-07-03) 40 | 41 | 42 | ### Bug Fixes 43 | 44 | * **deps:** bump braces from 3.0.2 to 3.0.3 in the npm_and_yarn group ([#634](https://github.com/npalm/action-docs/issues/634)) ([d250deb](https://github.com/npalm/action-docs/commit/d250debd2fd5bb7ea5a36fe21f08c6b48fe8389b)) 45 | * **deps:** bump yaml from 2.4.1 to 2.4.2 ([#601](https://github.com/npalm/action-docs/issues/601)) ([abe0bff](https://github.com/npalm/action-docs/commit/abe0bff7b1f82754fbccd0ab636c9600a2c5a3d8)) 46 | * Ignore empty inputs in workflows and actions ([#620](https://github.com/npalm/action-docs/issues/620)) ([b0b7b4e](https://github.com/npalm/action-docs/commit/b0b7b4e73acbefc900e06f9cbb7854e4ea5dc68d)) 47 | 48 | ## [2.4.1](https://github.com/npalm/action-docs/compare/v2.4.0...v2.4.1) (2024-04-27) 49 | 50 | 51 | ### Bug Fixes 52 | 53 | * update tsconfig to node20 recommendations ([#579](https://github.com/npalm/action-docs/issues/579)) ([2866dcf](https://github.com/npalm/action-docs/commit/2866dcffa1a5fa41aa61633868632261dfc90a69)) 54 | 55 | ## [2.4.0](https://github.com/npalm/action-docs/compare/v2.3.0...v2.4.0) (2024-03-13) 56 | 57 | 58 | ### Features 59 | 60 | * Add support for inputs deprecationMessage ([#566](https://github.com/npalm/action-docs/issues/566)) ([e283563](https://github.com/npalm/action-docs/commit/e283563580e9f0cc0e71cd4205ef587e50845ef9)) 61 | 62 | ## [2.3.0](https://github.com/npalm/action-docs/compare/v2.2.0...v2.3.0) (2024-03-09) 63 | 64 | 65 | ### Features 66 | 67 | * add 'all' option to add all the documentation to the readme in one go ([#537](https://github.com/npalm/action-docs/issues/537)) ([dc70838](https://github.com/npalm/action-docs/commit/dc708388c4bf58c9c15c4135702a4a9f0eabc897)) 68 | 69 | 70 | ### Bug Fixes 71 | 72 | * -a option was ingored ([#561](https://github.com/npalm/action-docs/issues/561)) ([8dbd40e](https://github.com/npalm/action-docs/commit/8dbd40eb476605d90f9a0d94848015097c02198f)) 73 | * **deps:** bump yaml from 2.4.0 to 2.4.1 ([#557](https://github.com/npalm/action-docs/issues/557)) ([8c2dc15](https://github.com/npalm/action-docs/commit/8c2dc15d9f90772c93c66133ef5d4948705b3e56)) 74 | 75 | ## [2.2.0](https://github.com/npalm/action-docs/compare/v2.1.0...v2.2.0) (2024-03-06) 76 | 77 | 78 | ### Features 79 | 80 | * support document generation for workflows ([#523](https://github.com/npalm/action-docs/issues/523)) ([f043f7f](https://github.com/npalm/action-docs/commit/f043f7f0e017821cad293ebd71293127c462663b)) 81 | 82 | 83 | ### Bug Fixes 84 | 85 | * **deps:** bump yaml from 2.3.4 to 2.4.0 ([#543](https://github.com/npalm/action-docs/issues/543)) ([0c76a5e](https://github.com/npalm/action-docs/commit/0c76a5e8468fc82d71f3a70b2b277b5d366877e3)) 86 | 87 | ## [2.1.0](https://github.com/npalm/action-docs/compare/v2.0.1...v2.1.0) (2024-02-15) 88 | 89 | 90 | ### Features 91 | 92 | * support action name attribute ([#526](https://github.com/npalm/action-docs/issues/526)) ([0e99848](https://github.com/npalm/action-docs/commit/0e998480955270e4500b38e2f2aab426c955d258)) 93 | 94 | ## [2.0.1](https://github.com/npalm/action-docs/compare/v2.0.0...v2.0.1) (2024-02-14) 95 | 96 | 97 | ### Bug Fixes 98 | 99 | * vulnerabilities ([#528](https://github.com/npalm/action-docs/issues/528)) ([670af1f](https://github.com/npalm/action-docs/commit/670af1f38cd52507920bfeae0efa8d88f62616a2)) 100 | 101 | ## [2.0.0](https://github.com/npalm/action-docs/compare/v1.3.0...v2.0.0) (2024-02-04) 102 | 103 | 104 | ### ⚠ BREAKING CHANGES 105 | 106 | * support multiple actions in a single readme ([#505](https://github.com/npalm/action-docs/issues/505)) 107 | 108 | ### Features 109 | 110 | * support multiple actions in a single readme ([#505](https://github.com/npalm/action-docs/issues/505)) ([284bf3f](https://github.com/npalm/action-docs/commit/284bf3f977f4e1044368d57e7f16fad600b028b6)) 111 | 112 | 113 | ### Miscellaneous 114 | 115 | * dependencies and refactor ci ([#506](https://github.com/npalm/action-docs/issues/506)) ([44af6c0](https://github.com/npalm/action-docs/commit/44af6c0b2187140fc5e5c75c55c9168f789cc803)) 116 | * **deps:** bump yargs from 17.7.1 to 17.7.2 ([4fe7873](https://github.com/npalm/action-docs/commit/4fe7873b04979cbfd0fbf55a19eb69a8159511d2)) 117 | * fix release build ([f75d0c3](https://github.com/npalm/action-docs/commit/f75d0c30340c8ae7c6928a4871bf0c18c72e5390)) 118 | 119 | ## [1.3.0](https://github.com/npalm/action-docs/compare/v1.3.0...v1.3.0) (2023-04-07) 120 | 121 | 122 | ### Features 123 | 124 | * Allow creating of usage guide ([#401](https://github.com/npalm/action-docs/issues/401)) ([92d68be](https://github.com/npalm/action-docs/commit/92d68beb7d90f1191db7a623fb21102adbd473cf)) 125 | 126 | 127 | ### Miscellaneous 128 | 129 | * **ci:** fix release ([5b4130b](https://github.com/npalm/action-docs/commit/5b4130bbc2f77a91445d4f6ce9059bb2845f64bf)) 130 | * **ci:** fix yarn publish ([ea14467](https://github.com/npalm/action-docs/commit/ea14467ce8b0d7eda1a90a75cce436e79e9e88a2)) 131 | * **main:** release 1.3.0 ([#404](https://github.com/npalm/action-docs/issues/404)) ([78c00c9](https://github.com/npalm/action-docs/commit/78c00c986edc29c6156e16688a667aed83aa300d)) 132 | 133 | ## [1.3.0](https://github.com/npalm/action-docs/compare/1.2.0...v1.3.0) (2023-04-07) 134 | 135 | 136 | ### Features 137 | 138 | * Allow creating of usage guide ([#401](https://github.com/npalm/action-docs/issues/401)) ([92d68be](https://github.com/npalm/action-docs/commit/92d68beb7d90f1191db7a623fb21102adbd473cf)) 139 | 140 | ## [1.2.0](https://github.com/npalm/action-docs/compare/1.1.3...1.2.0) (2023-03-02) 141 | 142 | 143 | ### Features 144 | 145 | * support multi-line ([#377](https://github.com/npalm/action-docs/issues/377)) ([ec0aa99](https://github.com/npalm/action-docs/commit/ec0aa995f92fcbb97711cbbc3e9bc787b825be69)) 146 | 147 | ## [1.1.3](https://github.com/npalm/action-docs/compare/1.1.2...1.1.3) (2023-03-02) 148 | 149 | 150 | ### Bug Fixes 151 | 152 | * **deps:** bump http-cache-semantics from 4.1.0 to 4.1.1 ([#376](https://github.com/npalm/action-docs/issues/376)) ([a7ef739](https://github.com/npalm/action-docs/commit/a7ef739df207ef7390093ef72ddcc3165f7ffac0)) 153 | 154 | ## [1.1.2](https://github.com/npalm/action-docs/compare/1.1.1...1.1.2) (2023-03-02) 155 | 156 | 157 | ### Bug Fixes 158 | 159 | * **deps:** bump json5 from 1.0.1 to 1.0.2 ([#371](https://github.com/npalm/action-docs/issues/371)) ([9352507](https://github.com/npalm/action-docs/commit/9352507c7e04005e644c3f97fda9261db63ba17b)) 160 | * **deps:** bump yargs from 17.6.2 to 17.7.1 ([#372](https://github.com/npalm/action-docs/issues/372)) ([d0fbf54](https://github.com/npalm/action-docs/commit/d0fbf54cf77d00c296704ff4b03e06187a4d16a4)) 161 | 162 | ## [1.1.1](https://github.com/npalm/action-docs/compare/1.1.0...1.1.1) (2022-12-12) 163 | 164 | 165 | ### Bug Fixes 166 | 167 | * Upgrade to Node 16 ([b5e2c4e](https://github.com/npalm/action-docs/commit/b5e2c4e20ea1c460500c047d36eaac9a2855a0e8)) 168 | 169 | ## [1.1.1](https://github.com/npalm/action-docs/compare/1.1.0...1.1.1) (2022-12-12) 170 | 171 | 172 | ### Bug Fixes 173 | 174 | * Upgrade to Node 16 ([b5e2c4e](https://github.com/npalm/action-docs/commit/b5e2c4e20ea1c460500c047d36eaac9a2855a0e8)) 175 | 176 | ## [1.1.0](https://github.com/npalm/action-docs/compare/1.0.4...1.1.0) (2022-10-20) 177 | 178 | 179 | ### Features 180 | 181 | * trim output text ([#271](https://github.com/npalm/action-docs/issues/271)) ([411256a](https://github.com/npalm/action-docs/commit/411256ac3a08096aef37293316bb4171c1321526)) 182 | 183 | 184 | ### Bug Fixes 185 | 186 | * remove new lines from inputs ([#272](https://github.com/npalm/action-docs/issues/272)) ([dbdbd50](https://github.com/npalm/action-docs/commit/dbdbd50f1377f57bd6cd7878381e5260c6c8edeb)) 187 | * Update test for trim [#271](https://github.com/npalm/action-docs/issues/271) ([#297](https://github.com/npalm/action-docs/issues/297)) ([6746b95](https://github.com/npalm/action-docs/commit/6746b951bc0851a277b0854ada8d13f67510b184)) 188 | * Upgrade dependencies ([#296](https://github.com/npalm/action-docs/issues/296)) ([b2a0a32](https://github.com/npalm/action-docs/commit/b2a0a324b4adba7b2aa4b9fee1480c8c55b8e1db)) 189 | 190 | ### [1.0.4](https://github.com/npalm/action-docs/compare/1.0.3...1.0.4) (2022-05-24) 191 | 192 | 193 | ### Bug Fixes 194 | 195 | * default values not included ([#219](https://github.com/npalm/action-docs/issues/219)) ([7dc133b](https://github.com/npalm/action-docs/commit/7dc133b903811795d1441b4828d7e11d4e71aea9)) 196 | 197 | ### [1.0.3](https://github.com/npalm/action-docs/compare/1.0.2...1.0.3) (2021-10-14) 198 | 199 | 200 | ### Bug Fixes 201 | 202 | * **deps:** bump browserslist from 4.16.3 to 4.17.4 ([#140](https://github.com/npalm/action-docs/issues/140)) ([718cf3a](https://github.com/npalm/action-docs/commit/718cf3a264d1983f59146eca55428abc19eee520)) 203 | * **deps:** bump tmpl from 1.0.4 to 1.0.5 ([#139](https://github.com/npalm/action-docs/issues/139)) ([8ef5ec3](https://github.com/npalm/action-docs/commit/8ef5ec36f62bd77b7d20a5ccb34729ef2f0910b2)) 204 | 205 | ### [1.0.2](https://github.com/npalm/action-docs/compare/1.0.1...1.0.2) (2021-10-14) 206 | 207 | 208 | ### Bug Fixes 209 | 210 | * upgrade dependencies ([#131](https://github.com/npalm/action-docs/issues/131)) ([095bf99](https://github.com/npalm/action-docs/commit/095bf99ac54124db80a6373768252ee92e02989f)) 211 | * upgrade dependencies ([#132](https://github.com/npalm/action-docs/issues/132)) ([a0c5c92](https://github.com/npalm/action-docs/commit/a0c5c92aa4fd188d8319617eb5a31fe2f5da60ae)) 212 | 213 | ### [1.0.1](https://github.com/npalm/action-docs/compare/1.0.0...1.0.1) (2021-06-20) 214 | 215 | 216 | ### Bug Fixes 217 | 218 | * remove unsupported node version ([#83](https://github.com/npalm/action-docs/issues/83)) ([9c3326d](https://github.com/npalm/action-docs/commit/9c3326d7ad744319fad0ac5c2783a66abf1bedee)) 219 | 220 | ## 1.0.0 (2021-03-07) 221 | 222 | 223 | ### Features 224 | 225 | * action docs ([f6e727f](https://github.com/npalm/action-docs/commit/f6e727ff1083c7cc96fab0de12473dda2e338828)) 226 | * support CR and CRLF line breaks ([#13](https://github.com/npalm/action-docs/issues/13)) ([2fdadb3](https://github.com/npalm/action-docs/commit/2fdadb321b6fa82d2c63df4f47f2cb2c9d89e81d)) 227 | 228 | 229 | ### Bug Fixes 230 | 231 | * parsing arguments in CLI ([#12](https://github.com/npalm/action-docs/issues/12)) ([a97635c](https://github.com/npalm/action-docs/commit/a97635c9a7efc76a64d25d3ff27ed48cc3629c4a)) 232 | * type in readme ([060fa40](https://github.com/npalm/action-docs/commit/060fa40f2f5a97e34aefa5b1d86ebfb395a4dd28)) 233 | * Use action-docs- keyword ([#4](https://github.com/npalm/action-docs/issues/4)) ([e42ac2f](https://github.com/npalm/action-docs/commit/e42ac2fd1c2cc23d8c47c705a73b69cade4caf38)) 234 | -------------------------------------------------------------------------------- /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 contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | - Using welcoming and inclusive language 12 | - Being respectful of differing viewpoints and experiences 13 | - Gracefully accepting constructive criticism 14 | - Focusing on what is best for the community 15 | - Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | - The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | - Trolling, insulting/derogatory comments, and personal or political attacks 21 | - Public or private harassment 22 | - Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | - Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at . The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to this repository 2 | 3 | Please take a moment to review this document in order to make the contribution process easy and effective for everyone involved. We appreciate your thought to contribute to open source. :heart: We want to make contributing as easy as possible. You are welcome to: 4 | 5 | - Reporting a bug 6 | - Discussing the current state of the code 7 | - Submitting a fix 8 | - Proposing new features 9 | 10 | ## Getting started 11 | 12 | Before you begin: 13 | 14 | - Have you read the [code of conduct](CODE_OF_CONDUCT.md)? 15 | - Check out the [existing issues](https://github.com/npalm/action-docs/issues). 16 | 17 | 18 | ## We Develop with Github 19 | 20 | We use GitHub to host code, to track issues and feature requests, as well as accept pull requests. 21 | 22 | ## Pull Requests 23 | 24 | Pull requests are the best way to propose changes to the codebase (we use [Github Flow](https://guides.github.com/introduction/flow/index.html)). We actively welcome your pull requests: 25 | 26 | 27 | 1. [Fork](http://help.github.com/fork-a-repo/) the repo and create your branch from the default branch. 28 | 29 | ```bash 30 | # Clone your fork of the repo into the current directory 31 | git clone https://github.com// 32 | # Navigate to the newly cloned directory 33 | cd 34 | # Assign the original repo to a remote called "upstream" 35 | git remote add upstream https://github.com// 36 | 37 | # Update the upstream 38 | git checkout 39 | git pull upstream 40 | 41 | # Create your feature / fix branch 42 | git checkout -b 43 | ``` 44 | 45 | 2. If you've added code that should be tested, add tests. 46 | 3. If you've changed APIs, update the documentation. 47 | 4. Ensure the test suite passes. 48 | 5. Make sure your code lints. 49 | 6. Commit your changes, see [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/). 50 | 7. Locally merge (or rebase) the upstream development branch into your topic branch. 51 | 52 | ```bash 53 | git pull [--rebase] upstream 54 | ``` 55 | 56 | 8. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) 57 | with a clear title and description. 58 | 59 | 60 | ## Development 61 | 62 | ### Setup you local environment 63 | 64 | 1. Ensure you have the Node.js version we use, check [.nvmrc](.nvmrc). You can easily run multiple Node version with [nvm](https://github.com/nvm-sh/nvm). 65 | 66 | 2. Install dependencies `yarn install` 67 | 68 | 3. Run `yarn run` to see the scripts available e.g. `yarn run all` to build, lint and test 69 | 70 | 4. Run the CLI locally 71 | 72 | ```bash 73 | node lib/cli.js 74 | ``` 75 | 76 | ### Adding tests 77 | 78 | Please provide tests for your contribution. 79 | 80 | To generate a new fixture for Markdown output run 81 | 82 | ```bash 83 | ./lib/cli.js --no-banner -s __tests__/fixtures/.yml | \ 84 | tail -r | tail -n +2 | tail -r > .output 85 | ``` 86 | 87 | For creating a README.md fixture, first create the readme input file for the test, and copy the same file to the an output file. Next run the following command to update the output which can be used to verify the test. 88 | 89 | 90 | ```bash 91 | ./lib/cli.js --no-banner -s __tests__/fixtures/.yml -u __tests_/fixtures/.output 92 | ``` 93 | 94 | ### Use a Consistent Coding Style 95 | 96 | - we use spaces. 97 | - You can try running `yarn run lint && yarn run format` for style unification 98 | 99 | 100 | ## License 101 | 102 | By contributing, you agree that your contributions will be licensed under the MIT License. 103 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Niek Palm 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ![example workflow](https://github.com/npalm/action-docs/actions/workflows/ci.yml/badge.svg) [![npm](https://img.shields.io/npm/v/action-docs.svg)](https://npmjs.org/package/action-docs) [![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=action-docs&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=action-docs) [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=action-docs&metric=coverage)](https://sonarcloud.io/dashboard?id=action-docs) [![CodeScene Code Health](https://codescene.io/projects/49602/status-badges/code-health)](https://codescene.io/projects/49602) 4 | 5 | 6 | 7 | # Action docs 8 | 9 | A CLI to generate and update documentation for GitHub actions or workflows, based on the definition `.yml`. To update your README in a GitHub workflow you can use the [action-docs-action](https://github.com/npalm/action-docs-action). 10 | 11 | ## TL;DR 12 | 13 | ### Add the following comment blocks to your README.md 14 | 15 | ```md 16 | 17 | 18 | # applicable for actions only 19 | 20 | 21 | 22 | 23 | 24 | # applicable for actions only 25 | ``` 26 | 27 | Optionally you can also add the following section to generate a usage guide, replacing \ and \ with the name and version of your project you would like to appear in your usage guide. 28 | 29 | ```md 30 | 31 | ``` 32 | 33 | ### Generate docs via CLI 34 | 35 | ```bash 36 | npm install -g action-docs 37 | cd 38 | 39 | # write docs to console 40 | action-docs 41 | 42 | # update README 43 | action-docs --update-readme 44 | ``` 45 | 46 | ### Run the cli 47 | 48 | ``` 49 | action-docs -u 50 | ``` 51 | 52 | ## CLI 53 | 54 | ### Options 55 | 56 | The following options are available via the CLI 57 | 58 | ``` 59 | Options: 60 | --version Show version number [boolean] 61 | -t, --toc-level TOC level used for markdown [number] [default: 2] 62 | -a, --action GitHub action file 63 | [deprecated: use "source" instead] [string] [default: "action.yml"] 64 | -s, --source GitHub source file [string] [default: "action.yml"] 65 | --no-banner Print no banner 66 | -u, --update-readme Update readme file. [string] 67 | -l, --line-breaks Used line breaks in the generated docs. 68 | [string] [choices: "CR", "LF", "CRLF"] [default: "LF"] 69 | -n, --include-name-header Include a header with the action/workflow name 70 | [boolean] 71 | --help Show help [boolean] 72 | ``` 73 | 74 | ### Update the README 75 | 76 | Action-docs can update your README based on the `action.yml`. The following sections can be updated: name header, description, inputs, outputs, usage, and runs. Add the following tags to your README and run `action-docs -u`. 77 | 78 | ```md 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | ``` 91 | 92 | Or to include all of the above, use: 93 | 94 | ```md 95 | 96 | ``` 97 | 98 | For updating other Markdown files add the name of the file to the command `action-docs -u `. 99 | 100 | If you need to use `another/action.yml`: 101 | 102 | 1. write it in tags like `source="another/action.yml"`; 103 | 2. specify in a command via the `-s` option like `action-docs -s another/action.yml` 104 | 105 | ### Examples 106 | 107 | #### Print action markdown docs to console 108 | 109 | ```bash 110 | action-docs 111 | ``` 112 | 113 | #### Update README.md 114 | 115 | ```bash 116 | action-docs --update-readme 117 | ``` 118 | 119 | #### Print action markdown for non default action file 120 | 121 | ```bash 122 | action-docs --source another/action.yaml 123 | ``` 124 | 125 | #### Update readme, custom action file and set TOC level 3, custom readme 126 | 127 | ```bash 128 | action-docs --source ./some-dir/action.yml --toc-level 3 --update-readme docs.md 129 | ``` 130 | 131 | ## API 132 | 133 | ```javascript 134 | import { generateActionMarkdownDocs } from 'action-docs' 135 | 136 | await generateActionMarkdownDocs({ 137 | sourceFile: 'action.yml' 138 | tocLevel: 2 139 | updateReadme: true 140 | readmeFile: 'README.md' 141 | }); 142 | ``` 143 | 144 | ## Contribution 145 | 146 | We welcome contributions, please checkout the [contribution guide](CONTRIBUTING.md). 147 | 148 | ## License 149 | 150 | This project is released under the [MIT License](./LICENSE). 151 | -------------------------------------------------------------------------------- /__tests__/action-docs-action.test.ts: -------------------------------------------------------------------------------- 1 | import { generateActionMarkdownDocs, Options } from "../src"; 2 | import { readFileSync, writeFileSync, copyFileSync, unlink } from "fs"; 3 | import * as path from "path"; 4 | 5 | const fixtureDir = path.join("__tests__", "fixtures", "action"); 6 | 7 | // By default an 'action.yml' is expected at the runtime location. Therefore we copy one during the test. 8 | beforeAll(() => { 9 | copyFileSync(path.join(fixtureDir, "action.yml"), "action.yml"); 10 | }); 11 | 12 | afterAll(() => { 13 | return unlink("action.yml", (err) => { 14 | if (err) throw err; 15 | }); 16 | }); 17 | 18 | describe("Test output", () => { 19 | test("With defaults.", async () => { 20 | const markdown = await generateActionMarkdownDocs(); 21 | const expected = ( 22 | readFileSync(path.join(fixtureDir, "default.output"), "utf-8") 23 | ); 24 | 25 | expect(markdown).toEqual(expected); 26 | }); 27 | 28 | test("With name header included.", async () => { 29 | const markdown = await generateActionMarkdownDocs({ 30 | includeNameHeader: true, 31 | }); 32 | const expected = ( 33 | readFileSync(path.join(fixtureDir, "default-with-header.output"), "utf-8") 34 | ); 35 | 36 | expect(markdown).toEqual(expected); 37 | }); 38 | 39 | test("A minimal action definition.", async () => { 40 | const markdown = await generateActionMarkdownDocs({ 41 | sourceFile: path.join(fixtureDir, "minimal_action.yml"), 42 | }); 43 | const expected = ( 44 | readFileSync(path.join(fixtureDir, "minimal_action.output"), "utf-8") 45 | ); 46 | 47 | expect(markdown).toEqual(expected); 48 | }); 49 | 50 | test("All fields action definition.", async () => { 51 | const markdown = await generateActionMarkdownDocs({ 52 | sourceFile: path.join(fixtureDir, "all_fields_action.yml"), 53 | }); 54 | const expected = ( 55 | readFileSync(path.join(fixtureDir, "all_fields_action.output"), "utf-8") 56 | ); 57 | 58 | expect(markdown).toEqual(expected); 59 | }); 60 | }); 61 | 62 | describe("Test update readme ", () => { 63 | test("Empty readme (all fields)", async () => { 64 | await testReadme( 65 | { 66 | sourceFile: path.join(fixtureDir, "all_fields_action.yml"), 67 | originalReadme: path.join(fixtureDir, "all_fields_readme.input"), 68 | fixtureReadme: path.join(fixtureDir, "all_fields_readme.output"), 69 | }, 70 | { 71 | includeNameHeader: true, 72 | }, 73 | ); 74 | }); 75 | test("Empty readme (all fields) with header", async () => { 76 | await testReadme( 77 | { 78 | sourceFile: path.join(fixtureDir, "all_fields_action.yml"), 79 | originalReadme: path.join(fixtureDir, "all_fields_readme.input"), 80 | fixtureReadme: path.join(fixtureDir, "all_fields_readme_header.output"), 81 | }, 82 | { 83 | includeNameHeader: true, 84 | }, 85 | false, 86 | true, 87 | ); 88 | }); 89 | 90 | test("All fields one annotation", async () => { 91 | await testReadme({ 92 | sourceFile: path.join(fixtureDir, "all_fields_action.yml"), 93 | originalReadme: path.join(fixtureDir, "all_fields_one_annotation.input"), 94 | fixtureReadme: path.join(fixtureDir, "all_fields_one_annotation.output"), 95 | }); 96 | }); 97 | 98 | test("Filled readme (all fields)", async () => { 99 | await testReadme({ 100 | sourceFile: path.join(fixtureDir, "all_fields_action.yml"), 101 | originalReadme: path.join(fixtureDir, "all_fields_readme_filled.input"), 102 | fixtureReadme: path.join(fixtureDir, "all_fields_readme_filled.output"), 103 | }); 104 | }); 105 | 106 | test("Filled readme (all fields) with header", async () => { 107 | await testReadme( 108 | { 109 | sourceFile: path.join(fixtureDir, "all_fields_action.yml"), 110 | originalReadme: path.join(fixtureDir, "all_fields_readme.input"), 111 | fixtureReadme: path.join(fixtureDir, "all_fields_readme_header.output"), 112 | }, 113 | { 114 | includeNameHeader: true, 115 | }, 116 | false, 117 | true, 118 | ); 119 | }); 120 | 121 | test("Readme (all fields) with CRLF line breaks", async () => { 122 | await testReadme( 123 | { 124 | sourceFile: path.join(fixtureDir, "all_fields_action.yml.crlf"), 125 | originalReadme: path.join(fixtureDir, "all_fields_readme.input.crlf"), 126 | fixtureReadme: path.join(fixtureDir, "all_fields_readme.output.crlf"), 127 | }, 128 | { lineBreaks: "CRLF" }, 129 | ); 130 | }); 131 | 132 | test("Readme (inputs) for action-docs-action", async () => { 133 | await testReadme({ 134 | sourceFile: path.join(fixtureDir, "action_docs_action_action.yml"), 135 | originalReadme: path.join(fixtureDir, "action_docs_action_readme.input"), 136 | fixtureReadme: path.join(fixtureDir, "action_docs_action_readme.output"), 137 | }); 138 | }); 139 | 140 | test("Readme for two action.yml-s", async () => { 141 | await testReadme( 142 | { 143 | sourceFile: path.join(fixtureDir, "action_docs_action_action.yml"), 144 | originalReadme: path.join(fixtureDir, "two_actions_readme.input"), 145 | fixtureReadme: path.join(fixtureDir, "two_actions_readme.output"), 146 | }, 147 | {}, 148 | false, 149 | ); 150 | 151 | await testReadme({ 152 | sourceFile: path.join(fixtureDir, "all_fields_action.yml"), 153 | originalReadme: path.join(fixtureDir, "two_actions_readme.input"), 154 | fixtureReadme: path.join(fixtureDir, "two_actions_readme.output"), 155 | }); 156 | }); 157 | 158 | test("Readme for deprecated inputs", async () => { 159 | await testReadme({ 160 | sourceFile: path.join(fixtureDir, "deprecated_input_action.yml"), 161 | originalReadme: path.join(fixtureDir, "deprecated_input_action.input"), 162 | fixtureReadme: path.join(fixtureDir, "deprecated_input_action.output"), 163 | }); 164 | }); 165 | }); 166 | 167 | describe("Test usage format", () => { 168 | test("Multi-line descriptions.", async () => { 169 | await testReadme({ 170 | sourceFile: path.join(fixtureDir, "action.yml"), 171 | originalReadme: path.join(fixtureDir, "action_usage_readme.input"), 172 | fixtureReadme: path.join(fixtureDir, "action_usage_readme.output"), 173 | }); 174 | }); 175 | 176 | test("With and without defaults.", async () => { 177 | await testReadme({ 178 | sourceFile: path.join(fixtureDir, "all_fields_action.yml"), 179 | originalReadme: path.join(fixtureDir, "all_fields_usage_readme.input"), 180 | fixtureReadme: path.join(fixtureDir, "all_fields_usage_readme.output"), 181 | }); 182 | }); 183 | }); 184 | 185 | describe("Backwards compatibility", () => { 186 | test("Deprecated action option still works correctly", async () => { 187 | await testReadme( 188 | { 189 | sourceFile: path.join(fixtureDir, "all_fields_action.yml"), 190 | originalReadme: path.join(fixtureDir, "action_deprecated.input"), 191 | fixtureReadme: path.join(fixtureDir, "action_deprecated.output"), 192 | }, 193 | { 194 | includeNameHeader: true, 195 | }, 196 | ); 197 | }); 198 | }); 199 | 200 | interface ReadmeTestFixtures { 201 | sourceFile: string; 202 | originalReadme: string; 203 | fixtureReadme: string; 204 | } 205 | 206 | async function testReadme( 207 | files: ReadmeTestFixtures, 208 | overwriteOptions?: Options, 209 | doExpect: boolean = true, 210 | includeNameHeader: boolean = false, 211 | ) { 212 | const expected = readFileSync(files.fixtureReadme, "utf-8"); 213 | const original = readFileSync(files.originalReadme, "utf-8"); 214 | 215 | try { 216 | await generateActionMarkdownDocs({ 217 | sourceFile: files.sourceFile, 218 | updateReadme: true, 219 | includeNameHeader: includeNameHeader, 220 | readmeFile: files.originalReadme, 221 | ...overwriteOptions, 222 | }); 223 | 224 | const updated = readFileSync(files.originalReadme, "utf-8"); 225 | 226 | if (doExpect) { 227 | expect(updated).toEqual(expected); 228 | } 229 | } finally { 230 | writeFileSync(files.originalReadme, original); 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /__tests__/action-docs-workflow.test.ts: -------------------------------------------------------------------------------- 1 | import { generateActionMarkdownDocs, Options } from "../src"; 2 | import { readFileSync, writeFileSync, copyFileSync, unlink } from "fs"; 3 | import * as path from "path"; 4 | 5 | const fixtureDir = path.join("__tests__", "fixtures", "workflow"); 6 | 7 | // By default a 'workflow.yml' is expected at the runtime location. Therefore we copy one during the test. 8 | beforeAll(() => { 9 | copyFileSync(path.join(fixtureDir, "workflow.yml"), "workflow.yml"); 10 | }); 11 | 12 | afterAll(() => { 13 | return unlink("workflow.yml", (err) => { 14 | if (err) throw err; 15 | }); 16 | }); 17 | 18 | describe("Test output", () => { 19 | test("With defaults.", async () => { 20 | const markdown = await generateActionMarkdownDocs({ 21 | sourceFile: path.join(fixtureDir, "workflow.yml"), 22 | includeNameHeader: true, 23 | }); 24 | const expected = ( 25 | readFileSync(path.join(fixtureDir, "default.output"), "utf-8") 26 | ); 27 | 28 | expect(markdown).toEqual(expected); 29 | }); 30 | 31 | test("With secrets.", async () => { 32 | const markdown = await generateActionMarkdownDocs({ 33 | sourceFile: path.join(fixtureDir, "secrets_workflow.yml"), 34 | includeNameHeader: true, 35 | }); 36 | const expected = ( 37 | readFileSync(path.join(fixtureDir, "secrets_workflow.output"), "utf-8") 38 | ); 39 | 40 | expect(markdown).toEqual(expected); 41 | }); 42 | 43 | test("A minimal workflow definition.", async () => { 44 | const markdown = await generateActionMarkdownDocs({ 45 | sourceFile: path.join(fixtureDir, "minimal_workflow.yml"), 46 | includeNameHeader: true, 47 | }); 48 | const expected = ( 49 | readFileSync(path.join(fixtureDir, "minimal_workflow.output"), "utf-8") 50 | ); 51 | 52 | expect(markdown).toEqual(expected); 53 | }); 54 | 55 | test("All fields workflow definition.", async () => { 56 | const markdown = await generateActionMarkdownDocs({ 57 | sourceFile: path.join(fixtureDir, "all_fields_workflow.yml"), 58 | includeNameHeader: true, 59 | }); 60 | const expected = ( 61 | readFileSync(path.join(fixtureDir, "all_fields_workflow.output"), "utf-8") 62 | ); 63 | 64 | expect(markdown).toEqual(expected); 65 | }); 66 | }); 67 | 68 | describe("Test update readme ", () => { 69 | test("Empty readme (all fields)", async () => { 70 | await testReadme({ 71 | sourceFile: path.join(fixtureDir, "all_fields_workflow.yml"), 72 | originalReadme: path.join(fixtureDir, "all_fields_readme.input"), 73 | fixtureReadme: path.join(fixtureDir, "all_fields_readme.output"), 74 | }); 75 | }); 76 | 77 | test("All fields one annotation", async () => { 78 | await testReadme({ 79 | sourceFile: path.join(fixtureDir, "all_fields_workflow.yml"), 80 | originalReadme: path.join(fixtureDir, "all_fields_one_annotation.input"), 81 | fixtureReadme: path.join(fixtureDir, "all_fields_one_annotation.output"), 82 | }); 83 | }); 84 | 85 | test("Filled readme (all fields)", async () => { 86 | await testReadme({ 87 | sourceFile: path.join(fixtureDir, "all_fields_workflow.yml"), 88 | originalReadme: path.join(fixtureDir, "all_fields_readme_filled.input"), 89 | fixtureReadme: path.join(fixtureDir, "all_fields_readme_filled.output"), 90 | }); 91 | }); 92 | 93 | test("Readme (all fields) with CRLF line breaks", async () => { 94 | await testReadme( 95 | { 96 | sourceFile: path.join(fixtureDir, "all_fields_workflow.yml"), 97 | originalReadme: path.join(fixtureDir, "all_fields_readme.input.crlf"), 98 | fixtureReadme: path.join(fixtureDir, "all_fields_readme.output.crlf"), 99 | }, 100 | { lineBreaks: "CRLF" }, 101 | ); 102 | }); 103 | 104 | test("Readme (inputs) for action_docs_workflow", async () => { 105 | await testReadme({ 106 | sourceFile: path.join(fixtureDir, "action_docs_workflow.yml"), 107 | originalReadme: path.join( 108 | fixtureDir, 109 | "action_docs_workflow_readme.input", 110 | ), 111 | fixtureReadme: path.join( 112 | fixtureDir, 113 | "action_docs_workflow_readme.output", 114 | ), 115 | }); 116 | }); 117 | 118 | test("Readme for two workflow.yml-s", async () => { 119 | await testReadme( 120 | { 121 | sourceFile: path.join(fixtureDir, "action_docs_workflow.yml"), 122 | originalReadme: path.join(fixtureDir, "two_workflows_readme.input"), 123 | fixtureReadme: path.join(fixtureDir, "two_workflows_readme.output"), 124 | }, 125 | {}, 126 | false, 127 | ); 128 | 129 | await testReadme({ 130 | sourceFile: path.join(fixtureDir, "all_fields_workflow.yml"), 131 | originalReadme: path.join(fixtureDir, "two_workflows_readme.input"), 132 | fixtureReadme: path.join(fixtureDir, "two_workflows_readme.output"), 133 | }); 134 | }); 135 | }); 136 | 137 | describe("Test usage format", () => { 138 | test("Multi-line descriptions.", async () => { 139 | await testReadme({ 140 | sourceFile: path.join(fixtureDir, "workflow.yml"), 141 | originalReadme: path.join(fixtureDir, "workflow_usage_readme.input"), 142 | fixtureReadme: path.join(fixtureDir, "workflow_usage_readme.output"), 143 | }); 144 | }); 145 | 146 | test("With and without defaults.", async () => { 147 | await testReadme({ 148 | sourceFile: path.join(fixtureDir, "all_fields_workflow.yml"), 149 | originalReadme: path.join(fixtureDir, "all_fields_usage_readme.input"), 150 | fixtureReadme: path.join(fixtureDir, "all_fields_usage_readme.output"), 151 | }); 152 | }); 153 | }); 154 | 155 | interface ReadmeTestFixtures { 156 | sourceFile: string; 157 | originalReadme: string; 158 | fixtureReadme: string; 159 | } 160 | 161 | async function testReadme( 162 | files: ReadmeTestFixtures, 163 | overwriteOptions?: Options, 164 | doExpect: boolean = true, 165 | ) { 166 | const expected = readFileSync(files.fixtureReadme, "utf-8"); 167 | const original = readFileSync(files.originalReadme, "utf-8"); 168 | 169 | try { 170 | await generateActionMarkdownDocs({ 171 | sourceFile: files.sourceFile, 172 | updateReadme: true, 173 | readmeFile: files.originalReadme, 174 | includeNameHeader: true, 175 | ...overwriteOptions, 176 | }); 177 | 178 | const updated = readFileSync(files.originalReadme, "utf-8"); 179 | 180 | if (doExpect) { 181 | expect(updated).toEqual(expected); 182 | } 183 | } finally { 184 | writeFileSync(files.originalReadme, original); 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /__tests__/cli.test.ts: -------------------------------------------------------------------------------- 1 | import * as cp from "child_process"; 2 | import * as path from "path"; 3 | 4 | import { readFileSync, writeFileSync } from "fs"; 5 | 6 | const fixtureDir = path.join("__tests__", "fixtures", "action"); 7 | 8 | describe("CLI tests", () => { 9 | test("Update readme default", async () => { 10 | await testReadme( 11 | path.join(fixtureDir, "all_fields_action.yml"), 12 | path.join(fixtureDir, "all_fields_readme.input"), 13 | path.join(fixtureDir, "all_fields_readme.output"), 14 | "-n true", 15 | ); 16 | }); 17 | 18 | test("Update readme with CRLF line breaks.", async () => { 19 | await testReadme( 20 | path.join(fixtureDir, "all_fields_action.yml.crlf"), 21 | path.join(fixtureDir, "all_fields_readme.input.crlf"), 22 | path.join(fixtureDir, "all_fields_readme.output.crlf"), 23 | "-l CRLF", 24 | ); 25 | }); 26 | 27 | test("Console output with TOC 3 and no banner.", async () => { 28 | const result = await cli( 29 | `-s ${path.join(fixtureDir, "all_fields_action.yml")} -t 3 --no-banner`, 30 | ); 31 | 32 | const expected = ( 33 | readFileSync( 34 | path.join(fixtureDir, "all_fields_action_toc3_cli.output"), 35 | "utf-8", 36 | ) 37 | ); 38 | 39 | expect(result.code).toBe(0); 40 | expect(result.stdout).toEqual(`${expected}\n`); 41 | }); 42 | 43 | test("Console output including name header and no banner.", async () => { 44 | const result = await cli( 45 | `-s ${path.join(fixtureDir, "action.yml")} -n true --no-banner`, 46 | ); 47 | 48 | const expected = ( 49 | readFileSync(path.join(fixtureDir, "default-with-header.output"), "utf-8") 50 | ); 51 | 52 | expect(result.code).toBe(0); 53 | expect(result.stdout).toEqual(`${expected}\n`); 54 | }); 55 | }); 56 | 57 | interface CliResponse { 58 | code: number; 59 | error: cp.ExecException | null; 60 | stdout: string; 61 | stderr: string; 62 | } 63 | 64 | function cli(args: string): Promise { 65 | return new Promise((resolve) => { 66 | cp.exec( 67 | `node ${path.resolve("lib/cli.js")} ${args}`, 68 | (error, stdout, stderr) => { 69 | resolve({ 70 | code: error && error.code ? error.code : 0, 71 | error, 72 | stdout, 73 | stderr, 74 | }); 75 | }, 76 | ); 77 | }); 78 | } 79 | 80 | async function testReadme( 81 | sourceFile: string, 82 | originalReadme: string, 83 | fixtureReadme: string, 84 | extraArgs = "", 85 | exitCode = 0, 86 | ) { 87 | const expected = readFileSync(fixtureReadme, "utf-8"); 88 | const original = readFileSync(originalReadme, "utf-8"); 89 | 90 | const result = await cli( 91 | `-u ${originalReadme} -s ${sourceFile} ${extraArgs}`, 92 | ); 93 | expect(result.code).toBe(exitCode); 94 | 95 | const updated = readFileSync(originalReadme, "utf-8"); 96 | 97 | writeFileSync(originalReadme, original); 98 | expect(updated).toEqual(expected); 99 | } 100 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/action.yml: -------------------------------------------------------------------------------- 1 | name: "An Action" 2 | description: "Default test" 3 | author: "Niek Palm" 4 | inputs: 5 | inputA: 6 | required: false 7 | description: | 8 | - Item 1 9 | - foo, bar, baz 10 | - Item 2 11 | - [github](https://github.com/) 12 | - **blah** 13 | - Item 3 14 | default: test 15 | inputB: 16 | required: false 17 | description: | 18 | This is a 19 | multiline description 20 | default: test 21 | 22 | outputs: 23 | outputA: 24 | description: "A description" 25 | 26 | runs: 27 | using: "node12" 28 | main: "dist/index.js" 29 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/action_deprecated.input: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/action_deprecated.output: -------------------------------------------------------------------------------- 1 | 2 | ## An Action 3 | 4 | 5 | 6 | ### Description 7 | 8 | Default test 9 | 10 | 11 | 12 | ### Usage 13 | 14 | ```yaml 15 | - uses: npalm/action-docs@v1 16 | with: 17 | inputA: 18 | # A description A 19 | # 20 | # Required: false 21 | # Default: "" 22 | 23 | inputB: 24 | # A description B 25 | # 26 | # Required: true 27 | # Default: "" 28 | 29 | inputC: 30 | # A description C 31 | # 32 | # Required: true 33 | # Default: C 34 | 35 | inputD: 36 | # A description D 37 | # 38 | # Required: false 39 | # Default: D 40 | 41 | inputE: 42 | # A description E 43 | # 44 | # Required: false 45 | # Default: false 46 | ``` 47 | 48 | 49 | 50 | ### Inputs 51 | 52 | | name | description | required | default | 53 | | --- | --- | --- | --- | 54 | | `inputA` |

A description A

| `false` | `""` | 55 | | `inputB` |

A description B

| `true` | `""` | 56 | | `inputC` |

A description C

| `true` | `C` | 57 | | `inputD` |

A description D

| `false` | `D` | 58 | | `inputE` |

A description E

| `false` | `false` | 59 | 60 | 61 | 62 | ### Outputs 63 | 64 | | name | description | 65 | | --- | --- | 66 | | `outputA` |

A description A

| 67 | | `outputB` |

A description B

| 68 | 69 | 70 | 71 | ### Runs 72 | 73 | This action is a `node12` action. 74 | 75 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/action_docs_action_action.yml: -------------------------------------------------------------------------------- 1 | name: "Action update docs action" 2 | description: "Action updates the action documentation." 3 | author: "Niek Palm" 4 | 5 | branding: 6 | icon: book-open 7 | color: purple 8 | 9 | inputs: 10 | readme: 11 | description: "Readme file to update." 12 | required: false 13 | default: README.md 14 | sourceFile: 15 | description: "The action definition file." 16 | required: false 17 | default: action.yml 18 | tocLevel: 19 | description: "TOC level used for the headers." 20 | required: false 21 | default: 2 22 | lineBreaks: 23 | description: "Line breaks to be used in updated readme (LF|CR|CRLF)." 24 | required: false 25 | default: LF 26 | 27 | runs: 28 | using: "node16" 29 | main: "dist/index.js" 30 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/action_docs_action_readme.input: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/action_docs_action_readme.output: -------------------------------------------------------------------------------- 1 | 2 | ## Inputs 3 | 4 | | name | description | required | default | 5 | | --- | --- | --- | --- | 6 | | `readme` |

Readme file to update.

| `false` | `README.md` | 7 | | `sourceFile` |

The action definition file.

| `false` | `action.yml` | 8 | | `tocLevel` |

TOC level used for the headers.

| `false` | `2` | 9 | | `lineBreaks` |

Line breaks to be used in updated readme (LF|CR|CRLF).

| `false` | `LF` | 10 | 11 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/action_usage_readme.input: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/action_usage_readme.output: -------------------------------------------------------------------------------- 1 | 2 | ## Usage 3 | 4 | ```yaml 5 | - uses: npalm/action-docs@v1 6 | with: 7 | inputA: 8 | # - Item 1 9 | # - foo, bar, baz 10 | # - Item 2 11 | # - [github](https://github.com/) 12 | # - **blah** 13 | # - Item 3 14 | # 15 | # Required: false 16 | # Default: test 17 | 18 | inputB: 19 | # This is a 20 | # multiline description 21 | # 22 | # Required: false 23 | # Default: test 24 | ``` 25 | 26 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/all_fields_action.output: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Default test 4 | 5 | ## Inputs 6 | 7 | | name | description | required | default | 8 | | --- | --- | --- | --- | 9 | | `inputA` |

A description A

| `false` | `""` | 10 | | `inputB` |

A description B

| `true` | `""` | 11 | | `inputC` |

A description C

| `true` | `C` | 12 | | `inputD` |

A description D

| `false` | `D` | 13 | | `inputE` |

A description E

| `false` | `false` | 14 | 15 | 16 | ## Outputs 17 | 18 | | name | description | 19 | | --- | --- | 20 | | `outputA` |

A description A

| 21 | | `outputB` |

A description B

| 22 | 23 | 24 | ## Runs 25 | 26 | This action is a `node12` action. 27 | 28 | ## Usage 29 | 30 | ```yaml 31 | - uses: ***PROJECT***@***VERSION*** 32 | with: 33 | inputA: 34 | # A description A 35 | # 36 | # Required: false 37 | # Default: "" 38 | 39 | inputB: 40 | # A description B 41 | # 42 | # Required: true 43 | # Default: "" 44 | 45 | inputC: 46 | # A description C 47 | # 48 | # Required: true 49 | # Default: C 50 | 51 | inputD: 52 | # A description D 53 | # 54 | # Required: false 55 | # Default: D 56 | 57 | inputE: 58 | # A description E 59 | # 60 | # Required: false 61 | # Default: false 62 | ``` 63 | 64 | 65 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/all_fields_action.yml: -------------------------------------------------------------------------------- 1 | name: "An Action" 2 | description: "Default test" 3 | author: "Niek Palm" 4 | inputs: 5 | inputA: 6 | description: "A description A" 7 | required: false 8 | inputB: 9 | description: "A description B" 10 | required: true 11 | inputC: 12 | description: "A description C" 13 | required: true 14 | default: C 15 | inputD: 16 | description: "A description D" 17 | required: false 18 | default: D 19 | inputE: 20 | description: "A description E" 21 | required: false 22 | default: false 23 | 24 | outputs: 25 | outputA: 26 | description: "A description A" 27 | outputB: 28 | description: "A description B" 29 | 30 | runs: 31 | using: "node12" 32 | main: "dist/index.js" 33 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/all_fields_action.yml.crlf: -------------------------------------------------------------------------------- 1 | name: 'An Action' 2 | description: 'Default test' 3 | author: 'Niek Palm' 4 | inputs: 5 | inputA: 6 | description: 'A description A' 7 | required: false 8 | inputB: 9 | description: 'A description B' 10 | required: true 11 | inputC: 12 | description: 'A description C' 13 | required: true 14 | default: C 15 | inputD: 16 | description: 'A description D' 17 | required: false 18 | default: D 19 | inputE: 20 | description: 'A description E' 21 | required: false 22 | default: false 23 | 24 | outputs: 25 | outputA: 26 | description: 'A description A' 27 | outputB: 28 | description: 'A description B' 29 | 30 | runs: 31 | using: 'node12' 32 | main: 'dist/index.js' 33 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/all_fields_action_toc1.output: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | Default test 4 | 5 | ## Inputs 6 | 7 | | name | description | required | default | 8 | | --- | --- | --- | --- | 9 | |

inputA

|

A description A

|

false

|

""

| 10 | |

inputB

|

A description B

|

true

|

""

| 11 | |

inputC

|

A description C

|

true

|

C

| 12 | |

inputD

|

A description D

|

false

|

D

| 13 | |

inputE

|

A description E

|

false

|

false

| 14 | 15 | # Outputs 16 | 17 | | name | description | 18 | | --- | --- | 19 | | `outputA` |

A description A

| 20 | | `outputB` |

A description B

| 21 | 22 | 23 | # Runs 24 | 25 | This action is a `node12` action. 26 | 27 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/all_fields_action_toc3_cli.output: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Default test 4 | 5 | ### Inputs 6 | 7 | | name | description | required | default | 8 | | --- | --- | --- | --- | 9 | | `inputA` |

A description A

| `false` | `""` | 10 | | `inputB` |

A description B

| `true` | `""` | 11 | | `inputC` |

A description C

| `true` | `C` | 12 | | `inputD` |

A description D

| `false` | `D` | 13 | | `inputE` |

A description E

| `false` | `false` | 14 | 15 | 16 | ### Outputs 17 | 18 | | name | description | 19 | | --- | --- | 20 | | `outputA` |

A description A

| 21 | | `outputB` |

A description B

| 22 | 23 | 24 | ### Runs 25 | 26 | This action is a `node12` action. 27 | 28 | ### Usage 29 | 30 | ```yaml 31 | - uses: ***PROJECT***@***VERSION*** 32 | with: 33 | inputA: 34 | # A description A 35 | # 36 | # Required: false 37 | # Default: "" 38 | 39 | inputB: 40 | # A description B 41 | # 42 | # Required: true 43 | # Default: "" 44 | 45 | inputC: 46 | # A description C 47 | # 48 | # Required: true 49 | # Default: C 50 | 51 | inputD: 52 | # A description D 53 | # 54 | # Required: false 55 | # Default: D 56 | 57 | inputE: 58 | # A description E 59 | # 60 | # Required: false 61 | # Default: false 62 | ``` 63 | 64 | 65 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/all_fields_one_annotation.input: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/all_fields_one_annotation.output: -------------------------------------------------------------------------------- 1 | 2 | ## Description 3 | 4 | Default test 5 | 6 | ## Inputs 7 | 8 | | name | description | required | default | 9 | | --- | --- | --- | --- | 10 | | `inputA` |

A description A

| `false` | `""` | 11 | | `inputB` |

A description B

| `true` | `""` | 12 | | `inputC` |

A description C

| `true` | `C` | 13 | | `inputD` |

A description D

| `false` | `D` | 14 | | `inputE` |

A description E

| `false` | `false` | 15 | 16 | 17 | ## Outputs 18 | 19 | | name | description | 20 | | --- | --- | 21 | | `outputA` |

A description A

| 22 | | `outputB` |

A description B

| 23 | 24 | 25 | ## Runs 26 | 27 | This action is a `node12` action. 28 | 29 | ## Usage 30 | 31 | ```yaml 32 | - uses: npalm/action-docs@v1 33 | with: 34 | inputA: 35 | # A description A 36 | # 37 | # Required: false 38 | # Default: "" 39 | 40 | inputB: 41 | # A description B 42 | # 43 | # Required: true 44 | # Default: "" 45 | 46 | inputC: 47 | # A description C 48 | # 49 | # Required: true 50 | # Default: C 51 | 52 | inputD: 53 | # A description D 54 | # 55 | # Required: false 56 | # Default: D 57 | 58 | inputE: 59 | # A description E 60 | # 61 | # Required: false 62 | # Default: false 63 | ``` 64 | 65 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/all_fields_readme.input: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/all_fields_readme.input.crlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/all_fields_readme.output: -------------------------------------------------------------------------------- 1 | 2 | ## An Action 3 | 4 | 5 | 6 | ### Description 7 | 8 | Default test 9 | 10 | 11 | 12 | ### Usage 13 | 14 | ```yaml 15 | - uses: npalm/action-docs@v1 16 | with: 17 | inputA: 18 | # A description A 19 | # 20 | # Required: false 21 | # Default: "" 22 | 23 | inputB: 24 | # A description B 25 | # 26 | # Required: true 27 | # Default: "" 28 | 29 | inputC: 30 | # A description C 31 | # 32 | # Required: true 33 | # Default: C 34 | 35 | inputD: 36 | # A description D 37 | # 38 | # Required: false 39 | # Default: D 40 | 41 | inputE: 42 | # A description E 43 | # 44 | # Required: false 45 | # Default: false 46 | ``` 47 | 48 | 49 | 50 | ### Inputs 51 | 52 | | name | description | required | default | 53 | | --- | --- | --- | --- | 54 | | `inputA` |

A description A

| `false` | `""` | 55 | | `inputB` |

A description B

| `true` | `""` | 56 | | `inputC` |

A description C

| `true` | `C` | 57 | | `inputD` |

A description D

| `false` | `D` | 58 | | `inputE` |

A description E

| `false` | `false` | 59 | 60 | 61 | 62 | ### Outputs 63 | 64 | | name | description | 65 | | --- | --- | 66 | | `outputA` |

A description A

| 67 | | `outputB` |

A description B

| 68 | 69 | 70 | 71 | ### Runs 72 | 73 | This action is a `node12` action. 74 | 75 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/all_fields_readme.output.crlf: -------------------------------------------------------------------------------- 1 | 2 | ## Description 3 | 4 | Default test 5 | 6 | 7 | 8 | ## Inputs 9 | 10 | | name | description | required | default | 11 | | --- | --- | --- | --- | 12 | | `inputA` |

A description A

| `false` | `""` | 13 | | `inputB` |

A description B

| `true` | `""` | 14 | | `inputC` |

A description C

| `true` | `C` | 15 | | `inputD` |

A description D

| `false` | `D` | 16 | | `inputE` |

A description E

| `false` | `false` | 17 | 18 | 19 | 20 | ## Outputs 21 | 22 | | name | description | 23 | | --- | --- | 24 | | `outputA` |

A description A

| 25 | | `outputB` |

A description B

| 26 | 27 | 28 | 29 | ## Runs 30 | 31 | This action is a `node12` action. 32 | 33 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/all_fields_readme_filled.input: -------------------------------------------------------------------------------- 1 | 2 | ## Description 3 | 4 | Default test 5 | 6 | 7 | 8 | 9 | 10 | ## Inputs 11 | 12 | | name | description | required | default | 13 | | --- | --- | --- | --- | 14 | | `inputA` |

A description A

| `false` | `""` | 15 | | `inputB` |

A description B

| `true` | `""` | 16 | | `inputC` |

A description C

| `true` | `C` | 17 | | `inputD` |

A description D

| `false` | `D` | 18 | | `inputE` |

A description E

| `false` | `false` | 19 | 20 | 21 | 22 | 23 | 24 | 25 | ## Outputs 26 | 27 | | name | description | 28 | | --- | --- | 29 | | `outputA` |

A description A

| 30 | | `outputB` |

A description B

| 31 | 32 | 33 | 34 | 35 | 36 | 37 | ## Run 38 | 39 | This action is a `docker` action. 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/all_fields_readme_filled.output: -------------------------------------------------------------------------------- 1 | 2 | ## Description 3 | 4 | Default test 5 | 6 | 7 | 8 | ## Inputs 9 | 10 | | name | description | required | default | 11 | | --- | --- | --- | --- | 12 | | `inputA` |

A description A

| `false` | `""` | 13 | | `inputB` |

A description B

| `true` | `""` | 14 | | `inputC` |

A description C

| `true` | `C` | 15 | | `inputD` |

A description D

| `false` | `D` | 16 | | `inputE` |

A description E

| `false` | `false` | 17 | 18 | 19 | 20 | ## Outputs 21 | 22 | | name | description | 23 | | --- | --- | 24 | | `outputA` |

A description A

| 25 | | `outputB` |

A description B

| 26 | 27 | 28 | 29 | ## Runs 30 | 31 | This action is a `node12` action. 32 | 33 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/all_fields_readme_header.output: -------------------------------------------------------------------------------- 1 | 2 | # Test Action 3 | 4 | 5 | 6 | ## Description 7 | 8 | Default test 9 | 10 | 11 | 12 | ## Usage 13 | 14 | ```yaml 15 | - uses: npalm/action-docs@v1 16 | with: 17 | inputA: 18 | # A description A 19 | # 20 | # Required: false 21 | # Default: "" 22 | 23 | inputB: 24 | # A description B 25 | # 26 | # Required: true 27 | # Default: "" 28 | 29 | inputC: 30 | # A description C 31 | # 32 | # Required: true 33 | # Default: C 34 | 35 | inputD: 36 | # A description D 37 | # 38 | # Required: false 39 | # Default: D 40 | 41 | inputE: 42 | # A description E 43 | # 44 | # Required: false 45 | # Default: false 46 | ``` 47 | 48 | 49 | 50 | 51 | 52 | ## Inputs 53 | 54 | | name | description | required | default | 55 | | --- | --- | --- | --- | 56 | | `inputA` |

A description A

| `false` | `""` | 57 | | `inputB` |

A description B

| `true` | `""` | 58 | | `inputC` |

A description C

| `true` | `C` | 59 | | `inputD` |

A description D

| `false` | `D` | 60 | | `inputE` |

A description E

| `false` | `false` | 61 | 62 | 63 | 64 | ## Outputs 65 | 66 | | name | description | 67 | | --- | --- | 68 | | `outputA` |

A description A

| 69 | | `outputB` |

A description B

| 70 | 71 | 72 | 73 | ## Runs 74 | 75 | This action is a `node12` action. 76 | 77 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/all_fields_usage_readme.input: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/all_fields_usage_readme.output: -------------------------------------------------------------------------------- 1 | 2 | ## Usage 3 | 4 | ```yaml 5 | - uses: npalm/action-docs@v1 6 | with: 7 | inputA: 8 | # A description A 9 | # 10 | # Required: false 11 | # Default: "" 12 | 13 | inputB: 14 | # A description B 15 | # 16 | # Required: true 17 | # Default: "" 18 | 19 | inputC: 20 | # A description C 21 | # 22 | # Required: true 23 | # Default: C 24 | 25 | inputD: 26 | # A description D 27 | # 28 | # Required: false 29 | # Default: D 30 | 31 | inputE: 32 | # A description E 33 | # 34 | # Required: false 35 | # Default: false 36 | ``` 37 | 38 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/default-with-header.output: -------------------------------------------------------------------------------- 1 | ## An Action 2 | 3 | ### Description 4 | 5 | Default test 6 | 7 | ### Inputs 8 | 9 | | name | description | required | default | 10 | | --- | --- | --- | --- | 11 | | `inputA` |
  • Item 1
    • foo, bar, baz
  • Item 2
  • Item 3
| `false` | `test` | 12 | | `inputB` |

This is a multiline description

| `false` | `test` | 13 | 14 | 15 | ### Outputs 16 | 17 | | name | description | 18 | | --- | --- | 19 | | `outputA` |

A description

| 20 | 21 | 22 | ### Runs 23 | 24 | This action is a `node12` action. 25 | 26 | ### Usage 27 | 28 | ```yaml 29 | - uses: ***PROJECT***@***VERSION*** 30 | with: 31 | inputA: 32 | # - Item 1 33 | # - foo, bar, baz 34 | # - Item 2 35 | # - [github](https://github.com/) 36 | # - **blah** 37 | # - Item 3 38 | # 39 | # Required: false 40 | # Default: test 41 | 42 | inputB: 43 | # This is a 44 | # multiline description 45 | # 46 | # Required: false 47 | # Default: test 48 | ``` 49 | 50 | 51 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/default.output: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Default test 4 | 5 | ## Inputs 6 | 7 | | name | description | required | default | 8 | | --- | --- | --- | --- | 9 | | `inputA` |
  • Item 1
    • foo, bar, baz
  • Item 2
  • Item 3
| `false` | `test` | 10 | | `inputB` |

This is a multiline description

| `false` | `test` | 11 | 12 | 13 | ## Outputs 14 | 15 | | name | description | 16 | | --- | --- | 17 | | `outputA` |

A description

| 18 | 19 | 20 | ## Runs 21 | 22 | This action is a `node12` action. 23 | 24 | ## Usage 25 | 26 | ```yaml 27 | - uses: ***PROJECT***@***VERSION*** 28 | with: 29 | inputA: 30 | # - Item 1 31 | # - foo, bar, baz 32 | # - Item 2 33 | # - [github](https://github.com/) 34 | # - **blah** 35 | # - Item 3 36 | # 37 | # Required: false 38 | # Default: test 39 | 40 | inputB: 41 | # This is a 42 | # multiline description 43 | # 44 | # Required: false 45 | # Default: test 46 | ``` 47 | 48 | 49 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/deprecated_input_action.input: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/deprecated_input_action.output: -------------------------------------------------------------------------------- 1 | 2 | ## Inputs 3 | 4 | | name | description | required | default | 5 | | --- | --- | --- | --- | 6 | | `inputA` |

This is an input
Deprecated: This input has been deprecated

| `false` | `""` | 7 | | `inputB` |

This is an input
Deprecated

| `false` | `""` | 8 | 9 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/deprecated_input_action.yml: -------------------------------------------------------------------------------- 1 | name: "An Action" 2 | description: "Test of deprecated inputs" 3 | author: "Niek Palm" 4 | inputs: 5 | inputA: 6 | required: false 7 | description: This is an input 8 | deprecationMessage: This input has been deprecated 9 | inputB: 10 | required: false 11 | description: This is an input 12 | deprecationMessage: '' 13 | 14 | runs: 15 | using: "node12" 16 | main: "dist/index.js" 17 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/minimal_action.output: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Default test 4 | 5 | ## Runs 6 | 7 | This action is a `docker` action. 8 | 9 | ## Usage 10 | 11 | ```yaml 12 | - uses: ***PROJECT***@***VERSION*** 13 | ``` 14 | 15 | 16 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/minimal_action.yml: -------------------------------------------------------------------------------- 1 | name: "An Action" 2 | description: "Default test" 3 | runs: 4 | using: "docker" 5 | image: "Dockerfile" 6 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/two_actions_readme.input: -------------------------------------------------------------------------------- 1 | 2 | ## Inputs 3 | 4 | | name | description | required | default | 5 | | --- | --- | --- | --- | 6 | | `readme` |

Readme file to update.

| `false` | `README.md` | 7 | | `sourceFile` |

The action definition file.

| `false` | `action.yml` | 8 | | `tocLevel` |

TOC level used for the headers.

| `false` | `2` | 9 | | `lineBreaks` |

Line breaks to be used in updated readme (LF|CR|CRLF).

| `false` | `LF` | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /__tests__/fixtures/action/two_actions_readme.output: -------------------------------------------------------------------------------- 1 | 2 | ## Inputs 3 | 4 | | name | description | required | default | 5 | | --- | --- | --- | --- | 6 | | `readme` |

Readme file to update.

| `false` | `README.md` | 7 | | `sourceFile` |

The action definition file.

| `false` | `action.yml` | 8 | | `tocLevel` |

TOC level used for the headers.

| `false` | `2` | 9 | | `lineBreaks` |

Line breaks to be used in updated readme (LF|CR|CRLF).

| `false` | `LF` | 10 | 11 | 12 | 13 | ## Outputs 14 | 15 | | name | description | 16 | | --- | --- | 17 | | `outputA` |

A description A

| 18 | | `outputB` |

A description B

| 19 | 20 | -------------------------------------------------------------------------------- /__tests__/fixtures/workflow/action_docs_workflow.yml: -------------------------------------------------------------------------------- 1 | name: "Action update docs workflow" 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | readme: 7 | description: "Readme file to update." 8 | type: string 9 | required: false 10 | default: README.md 11 | sourceFile: 12 | description: "The action definition file." 13 | type: string 14 | required: false 15 | default: action.yml 16 | tocLevel: 17 | description: "TOC level used for the headers." 18 | type: string 19 | required: false 20 | default: 2 21 | lineBreaks: 22 | description: "Line breaks to be used in updated readme (LF|CR|CRLF)." 23 | type: string 24 | required: false 25 | default: LF 26 | 27 | secrets: 28 | notVerySecret: 29 | description: "A secret" 30 | required: true 31 | 32 | jobs: 33 | job1: 34 | runs-on: ubuntu-latest 35 | steps: 36 | - run: echo "dummy step" 37 | -------------------------------------------------------------------------------- /__tests__/fixtures/workflow/action_docs_workflow_readme.input: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /__tests__/fixtures/workflow/action_docs_workflow_readme.output: -------------------------------------------------------------------------------- 1 | 2 | ### Inputs 3 | 4 | | name | description | type | required | default | 5 | | --- | --- | --- | --- | --- | 6 | | `readme` |

Readme file to update.

| `string` | `false` | `README.md` | 7 | | `sourceFile` |

The action definition file.

| `string` | `false` | `action.yml` | 8 | | `tocLevel` |

TOC level used for the headers.

| `string` | `false` | `2` | 9 | | `lineBreaks` |

Line breaks to be used in updated readme (LF|CR|CRLF).

| `string` | `false` | `LF` | 10 | 11 | -------------------------------------------------------------------------------- /__tests__/fixtures/workflow/all_fields_one_annotation.input: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /__tests__/fixtures/workflow/all_fields_one_annotation.output: -------------------------------------------------------------------------------- 1 | 2 | ## A Workflow 3 | 4 | ### Inputs 5 | 6 | | name | description | type | required | default | 7 | | --- | --- | --- | --- | --- | 8 | | `inputA` |

A description A

| `string` | `false` | `""` | 9 | | `inputB` |

A description B

| `string` | `true` | `""` | 10 | | `inputC` |

A description C

| `string` | `true` | `C` | 11 | | `inputD` |

A description D

| `string` | `false` | `D` | 12 | | `inputE` |

A description E

| `string` | `false` | `false` | 13 | 14 | 15 | ### Secrets 16 | 17 | | name | description | required | 18 | | --- | --- | --- | 19 | | `notVerySecret` |

A secret

| `true` | 20 | 21 | 22 | ### Outputs 23 | 24 | | name | description | 25 | | --- | --- | 26 | | `outputA` |

A description A

| 27 | | `outputB` |

A description B

| 28 | 29 | 30 | ### Usage 31 | 32 | ```yaml 33 | jobs: 34 | job1: 35 | uses: npalm/action-docs@v1 36 | with: 37 | inputA: 38 | # A description A 39 | # 40 | # Type: string 41 | # Required: false 42 | # Default: "" 43 | 44 | inputB: 45 | # A description B 46 | # 47 | # Type: string 48 | # Required: true 49 | # Default: "" 50 | 51 | inputC: 52 | # A description C 53 | # 54 | # Type: string 55 | # Required: true 56 | # Default: C 57 | 58 | inputD: 59 | # A description D 60 | # 61 | # Type: string 62 | # Required: false 63 | # Default: D 64 | 65 | inputE: 66 | # A description E 67 | # 68 | # Type: string 69 | # Required: false 70 | # Default: false 71 | ``` 72 | 73 | -------------------------------------------------------------------------------- /__tests__/fixtures/workflow/all_fields_readme.input: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /__tests__/fixtures/workflow/all_fields_readme.input.crlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /__tests__/fixtures/workflow/all_fields_readme.output: -------------------------------------------------------------------------------- 1 | 2 | ## A Workflow 3 | 4 | 5 | 6 | ### Usage 7 | 8 | ```yaml 9 | jobs: 10 | job1: 11 | uses: npalm/action-docs@v1 12 | with: 13 | inputA: 14 | # A description A 15 | # 16 | # Type: string 17 | # Required: false 18 | # Default: "" 19 | 20 | inputB: 21 | # A description B 22 | # 23 | # Type: string 24 | # Required: true 25 | # Default: "" 26 | 27 | inputC: 28 | # A description C 29 | # 30 | # Type: string 31 | # Required: true 32 | # Default: C 33 | 34 | inputD: 35 | # A description D 36 | # 37 | # Type: string 38 | # Required: false 39 | # Default: D 40 | 41 | inputE: 42 | # A description E 43 | # 44 | # Type: string 45 | # Required: false 46 | # Default: false 47 | ``` 48 | 49 | 50 | 51 | ### Inputs 52 | 53 | | name | description | type | required | default | 54 | | --- | --- | --- | --- | --- | 55 | | `inputA` |

A description A

| `string` | `false` | `""` | 56 | | `inputB` |

A description B

| `string` | `true` | `""` | 57 | | `inputC` |

A description C

| `string` | `true` | `C` | 58 | | `inputD` |

A description D

| `string` | `false` | `D` | 59 | | `inputE` |

A description E

| `string` | `false` | `false` | 60 | 61 | 62 | 63 | ### Outputs 64 | 65 | | name | description | 66 | | --- | --- | 67 | | `outputA` |

A description A

| 68 | | `outputB` |

A description B

| 69 | 70 | -------------------------------------------------------------------------------- /__tests__/fixtures/workflow/all_fields_readme.output.crlf: -------------------------------------------------------------------------------- 1 | 2 | ## A Workflow 3 | 4 | 5 | 6 | ### Inputs 7 | 8 | | name | description | type | required | default | 9 | | --- | --- | --- | --- | --- | 10 | | `inputA` |

A description A

| `string` | `false` | `""` | 11 | | `inputB` |

A description B

| `string` | `true` | `""` | 12 | | `inputC` |

A description C

| `string` | `true` | `C` | 13 | | `inputD` |

A description D

| `string` | `false` | `D` | 14 | | `inputE` |

A description E

| `string` | `false` | `false` | 15 | 16 | 17 | 18 | ### Outputs 19 | 20 | | name | description | 21 | | --- | --- | 22 | | `outputA` |

A description A

| 23 | | `outputB` |

A description B

| 24 | 25 | -------------------------------------------------------------------------------- /__tests__/fixtures/workflow/all_fields_readme_filled.input: -------------------------------------------------------------------------------- 1 | 2 | ## Description 3 | 4 | Anything here 5 | 6 | 7 | 8 | 9 | 10 | ## Inputs 11 | 12 | Anything here 13 | 14 | 15 | 16 | 17 | ## Outputs 18 | 19 | Anything here 20 | 21 | 22 | -------------------------------------------------------------------------------- /__tests__/fixtures/workflow/all_fields_readme_filled.output: -------------------------------------------------------------------------------- 1 | 2 | ## A Workflow 3 | 4 | 5 | 6 | ### Inputs 7 | 8 | | name | description | type | required | default | 9 | | --- | --- | --- | --- | --- | 10 | | `inputA` |

A description A

| `string` | `false` | `""` | 11 | | `inputB` |

A description B

| `string` | `true` | `""` | 12 | | `inputC` |

A description C

| `string` | `true` | `C` | 13 | | `inputD` |

A description D

| `string` | `false` | `D` | 14 | | `inputE` |

A description E

| `string` | `false` | `false` | 15 | 16 | 17 | 18 | ### Outputs 19 | 20 | | name | description | 21 | | --- | --- | 22 | | `outputA` |

A description A

| 23 | | `outputB` |

A description B

| 24 | 25 | -------------------------------------------------------------------------------- /__tests__/fixtures/workflow/all_fields_usage_readme.input: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /__tests__/fixtures/workflow/all_fields_usage_readme.output: -------------------------------------------------------------------------------- 1 | 2 | ### Usage 3 | 4 | ```yaml 5 | jobs: 6 | job1: 7 | uses: npalm/action-docs@v1 8 | with: 9 | inputA: 10 | # A description A 11 | # 12 | # Type: string 13 | # Required: false 14 | # Default: "" 15 | 16 | inputB: 17 | # A description B 18 | # 19 | # Type: string 20 | # Required: true 21 | # Default: "" 22 | 23 | inputC: 24 | # A description C 25 | # 26 | # Type: string 27 | # Required: true 28 | # Default: C 29 | 30 | inputD: 31 | # A description D 32 | # 33 | # Type: string 34 | # Required: false 35 | # Default: D 36 | 37 | inputE: 38 | # A description E 39 | # 40 | # Type: string 41 | # Required: false 42 | # Default: false 43 | ``` 44 | 45 | -------------------------------------------------------------------------------- /__tests__/fixtures/workflow/all_fields_workflow.output: -------------------------------------------------------------------------------- 1 | ## A Workflow 2 | 3 | ### Inputs 4 | 5 | | name | description | type | required | default | 6 | | --- | --- | --- | --- | --- | 7 | | `inputA` |

A description A

| `string` | `false` | `""` | 8 | | `inputB` |

A description B

| `string` | `true` | `""` | 9 | | `inputC` |

A description C

| `string` | `true` | `C` | 10 | | `inputD` |

A description D

| `string` | `false` | `D` | 11 | | `inputE` |

A description E

| `string` | `false` | `false` | 12 | 13 | 14 | ### Secrets 15 | 16 | | name | description | required | 17 | | --- | --- | --- | 18 | | `notVerySecret` |

A secret

| `true` | 19 | 20 | 21 | ### Outputs 22 | 23 | | name | description | 24 | | --- | --- | 25 | | `outputA` |

A description A

| 26 | | `outputB` |

A description B

| 27 | 28 | 29 | ### Usage 30 | 31 | ```yaml 32 | jobs: 33 | job1: 34 | uses: ***PROJECT***@***VERSION*** 35 | with: 36 | inputA: 37 | # A description A 38 | # 39 | # Type: string 40 | # Required: false 41 | # Default: "" 42 | 43 | inputB: 44 | # A description B 45 | # 46 | # Type: string 47 | # Required: true 48 | # Default: "" 49 | 50 | inputC: 51 | # A description C 52 | # 53 | # Type: string 54 | # Required: true 55 | # Default: C 56 | 57 | inputD: 58 | # A description D 59 | # 60 | # Type: string 61 | # Required: false 62 | # Default: D 63 | 64 | inputE: 65 | # A description E 66 | # 67 | # Type: string 68 | # Required: false 69 | # Default: false 70 | ``` 71 | 72 | 73 | -------------------------------------------------------------------------------- /__tests__/fixtures/workflow/all_fields_workflow.yml: -------------------------------------------------------------------------------- 1 | name: 'A Workflow' 2 | on: 3 | workflow_call: 4 | inputs: 5 | inputA: 6 | description: 'A description A' 7 | type: string 8 | required: false 9 | inputB: 10 | description: 'A description B' 11 | type: string 12 | required: true 13 | inputC: 14 | description: 'A description C' 15 | type: string 16 | required: true 17 | default: C 18 | inputD: 19 | description: 'A description D' 20 | type: string 21 | required: false 22 | default: D 23 | inputE: 24 | description: 'A description E' 25 | type: string 26 | required: false 27 | default: false 28 | 29 | secrets: 30 | notVerySecret: 31 | description: "A secret" 32 | required: true 33 | 34 | outputs: 35 | outputA: 36 | description: 'A description A' 37 | value: ${{ jobs.job1.outputs.step_output1 }} 38 | outputB: 39 | description: 'A description B' 40 | value: ${{ jobs.job1.outputs.step_output1 }} 41 | 42 | jobs: 43 | job1: 44 | runs-on: ubuntu-latest 45 | outputs: 46 | step_output1: ${{ steps.step1.outputs.test }} 47 | steps: 48 | - name: 'Step 1' 49 | id: step1 50 | run: echo "test=some value" >> "$GITHUB_OUTPUT" 51 | -------------------------------------------------------------------------------- /__tests__/fixtures/workflow/all_fields_workflow.yml.crlf: -------------------------------------------------------------------------------- 1 | name: 'An Action' 2 | description: 'Default test' 3 | author: 'Niek Palm' 4 | inputs: 5 | inputA: 6 | description: 'A description A' 7 | required: false 8 | inputB: 9 | description: 'A description B' 10 | required: true 11 | inputC: 12 | description: 'A description C' 13 | required: true 14 | default: C 15 | inputD: 16 | description: 'A description D' 17 | required: false 18 | default: D 19 | inputE: 20 | description: 'A description E' 21 | required: false 22 | default: false 23 | 24 | outputs: 25 | outputA: 26 | description: 'A description A' 27 | outputB: 28 | description: 'A description B' 29 | 30 | runs: 31 | using: 'node12' 32 | main: 'dist/index.js' 33 | -------------------------------------------------------------------------------- /__tests__/fixtures/workflow/all_fields_workflow_toc1.output: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | Default test 4 | 5 | ## Inputs 6 | 7 | | name | description | required | default | 8 | | --- | --- | --- | --- | 9 | |

inputA

|

A description A

|

false

|

""

| 10 | |

inputB

|

A description B

|

true

|

""

| 11 | |

inputC

|

A description C

|

true

|

C

| 12 | |

inputD

|

A description D

|

false

|

D

| 13 | |

inputE

|

A description E

|

false

|

false

| 14 | 15 | # Outputs 16 | 17 | | name | description | 18 | | --- | --- | 19 | | `outputA` |

A description A

| 20 | | `outputB` |

A description B

| 21 | 22 | 23 | # Runs 24 | 25 | This action is a `node12` action. 26 | 27 | -------------------------------------------------------------------------------- /__tests__/fixtures/workflow/all_fields_workflow_toc3_cli.output: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Default test 4 | 5 | ### Inputs 6 | 7 | | name | description | required | default | 8 | | --- | --- | --- | --- | 9 | | `inputA` |

A description A

| `false` | `""` | 10 | | `inputB` |

A description B

| `true` | `""` | 11 | | `inputC` |

A description C

| `true` | `C` | 12 | | `inputD` |

A description D

| `false` | `D` | 13 | | `inputE` |

A description E

| `false` | `false` | 14 | 15 | 16 | ### Outputs 17 | 18 | | name | description | 19 | | --- | --- | 20 | | `outputA` |

A description A

| 21 | | `outputB` |

A description B

| 22 | 23 | 24 | ### Runs 25 | 26 | This action is a `node12` action. 27 | 28 | -------------------------------------------------------------------------------- /__tests__/fixtures/workflow/default.output: -------------------------------------------------------------------------------- 1 | ## A Workflow 2 | 3 | ### Inputs 4 | 5 | | name | description | type | required | default | 6 | | --- | --- | --- | --- | --- | 7 | | `inputA` |
  • Item 1
    • foo, bar, baz
  • Item 2
  • Item 3
| `string` | `false` | `This is a default` | 8 | | `inputB` |

This is a multiline description

| `number` | `true` | `""` | 9 | 10 | 11 | ### Outputs 12 | 13 | | name | description | 14 | | --- | --- | 15 | | `outputA` |

This is output A

| 16 | 17 | 18 | ### Usage 19 | 20 | ```yaml 21 | jobs: 22 | job1: 23 | uses: ***PROJECT***@***VERSION*** 24 | with: 25 | inputA: 26 | # - Item 1 27 | # - foo, bar, baz 28 | # - Item 2 29 | # - [github](https://github.com/) 30 | # - **blah** 31 | # - Item 3 32 | # 33 | # Type: string 34 | # Required: false 35 | # Default: This is a default 36 | 37 | inputB: 38 | # This is a 39 | # multiline description 40 | # 41 | # Type: number 42 | # Required: true 43 | # Default: "" 44 | ``` 45 | 46 | 47 | -------------------------------------------------------------------------------- /__tests__/fixtures/workflow/minimal_workflow.output: -------------------------------------------------------------------------------- 1 | ## A Workflow 2 | 3 | ### Usage 4 | 5 | ```yaml 6 | jobs: 7 | job1: 8 | uses: ***PROJECT***@***VERSION*** 9 | ``` 10 | 11 | 12 | -------------------------------------------------------------------------------- /__tests__/fixtures/workflow/minimal_workflow.yml: -------------------------------------------------------------------------------- 1 | name: 'A Workflow' 2 | on: 3 | workflow_call: 4 | 5 | jobs: 6 | job1: 7 | runs-on: ubuntu-latest 8 | outputs: 9 | step_output1: ${{ steps.step1.outputs.test }} 10 | steps: 11 | - name: 'Step 1' 12 | id: step1 13 | run: echo "test=some value" >> "$GITHUB_OUTPUT" 14 | -------------------------------------------------------------------------------- /__tests__/fixtures/workflow/secrets_workflow.output: -------------------------------------------------------------------------------- 1 | ## A Workflow with secrets 2 | 3 | ### Inputs 4 | 5 | | name | description | type | required | default | 6 | | --- | --- | --- | --- | --- | 7 | | `inputA` |
  • Item 1
    • foo, bar, baz
  • Item 2
  • Item 3
| `string` | `false` | `This is a default` | 8 | | `inputB` |

This is a multiline description

| `number` | `true` | `""` | 9 | 10 | 11 | ### Secrets 12 | 13 | | name | description | required | 14 | | --- | --- | --- | 15 | | `notVerySecret` |

A secret

| `true` | 16 | 17 | 18 | ### Outputs 19 | 20 | | name | description | 21 | | --- | --- | 22 | | `outputA` |

This is output A

| 23 | 24 | 25 | ### Usage 26 | 27 | ```yaml 28 | jobs: 29 | job1: 30 | uses: ***PROJECT***@***VERSION*** 31 | with: 32 | inputA: 33 | # - Item 1 34 | # - foo, bar, baz 35 | # - Item 2 36 | # - [github](https://github.com/) 37 | # - **blah** 38 | # - Item 3 39 | # 40 | # Type: string 41 | # Required: false 42 | # Default: This is a default 43 | 44 | inputB: 45 | # This is a 46 | # multiline description 47 | # 48 | # Type: number 49 | # Required: true 50 | # Default: "" 51 | ``` 52 | 53 | 54 | -------------------------------------------------------------------------------- /__tests__/fixtures/workflow/secrets_workflow.yml: -------------------------------------------------------------------------------- 1 | name: 'A Workflow with secrets' 2 | on: 3 | push: 4 | branches: 5 | - main 6 | schedule: 7 | - cron: '*/15 * * * *' 8 | workflow_call: 9 | inputs: 10 | inputA: 11 | description: | 12 | - Item 1 13 | - foo, bar, baz 14 | - Item 2 15 | - [github](https://github.com/) 16 | - **blah** 17 | - Item 3 18 | type: string 19 | default: 'This is a default' 20 | required: false 21 | inputB: 22 | description: | 23 | This is a 24 | multiline description 25 | type: number 26 | required: true 27 | 28 | secrets: 29 | notVerySecret: 30 | description: "A secret" 31 | required: true 32 | 33 | outputs: 34 | outputA: 35 | description: 'This is output A' 36 | value: ${{ jobs.job1.outputs.step_output1 }} 37 | 38 | jobs: 39 | job1: 40 | runs-on: ubuntu-latest 41 | outputs: 42 | step_output1: ${{ steps.step1.outputs.test }} 43 | steps: 44 | - name: 'Step 1' 45 | id: step1 46 | run: echo "test=some value" >> "$GITHUB_OUTPUT" 47 | -------------------------------------------------------------------------------- /__tests__/fixtures/workflow/two_workflows_readme.input: -------------------------------------------------------------------------------- 1 | 2 | ### Inputs 3 | 4 | | name | description | required | default | 5 | | --- | --- | --- | --- | 6 | | `readme` |

Readme file to update.

| `false` | `README.md` | 7 | | `sourceFile` |

The action definition file.

| `false` | `action.yml` | 8 | | `tocLevel` |

TOC level used for the headers.

| `false` | `2` | 9 | | `lineBreaks` |

Line breaks to be used in updated readme (LF|CR|CRLF).

| `false` | `LF` | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /__tests__/fixtures/workflow/two_workflows_readme.output: -------------------------------------------------------------------------------- 1 | 2 | ### Inputs 3 | 4 | | name | description | required | default | 5 | | --- | --- | --- | --- | 6 | | `readme` |

Readme file to update.

| `false` | `README.md` | 7 | | `sourceFile` |

The action definition file.

| `false` | `action.yml` | 8 | | `tocLevel` |

TOC level used for the headers.

| `false` | `2` | 9 | | `lineBreaks` |

Line breaks to be used in updated readme (LF|CR|CRLF).

| `false` | `LF` | 10 | 11 | 12 | 13 | ### Outputs 14 | 15 | | name | description | 16 | | --- | --- | 17 | | `outputA` |

A description A

| 18 | | `outputB` |

A description B

| 19 | 20 | -------------------------------------------------------------------------------- /__tests__/fixtures/workflow/workflow.yml: -------------------------------------------------------------------------------- 1 | name: 'A Workflow' 2 | on: 3 | push: 4 | branches: 5 | - main 6 | schedule: 7 | - cron: '*/15 * * * *' 8 | workflow_call: 9 | inputs: 10 | inputA: 11 | description: | 12 | - Item 1 13 | - foo, bar, baz 14 | - Item 2 15 | - [github](https://github.com/) 16 | - **blah** 17 | - Item 3 18 | type: string 19 | default: 'This is a default' 20 | required: false 21 | inputB: 22 | description: | 23 | This is a 24 | multiline description 25 | type: number 26 | required: true 27 | 28 | outputs: 29 | outputA: 30 | description: 'This is output A' 31 | value: ${{ jobs.job1.outputs.step_output1 }} 32 | 33 | jobs: 34 | job1: 35 | runs-on: ubuntu-latest 36 | outputs: 37 | step_output1: ${{ steps.step1.outputs.test }} 38 | steps: 39 | - name: 'Step 1' 40 | id: step1 41 | run: echo "test=some value" >> "$GITHUB_OUTPUT" 42 | -------------------------------------------------------------------------------- /__tests__/fixtures/workflow/workflow_usage_readme.input: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /__tests__/fixtures/workflow/workflow_usage_readme.output: -------------------------------------------------------------------------------- 1 | 2 | ### Usage 3 | 4 | ```yaml 5 | jobs: 6 | job1: 7 | uses: npalm/action-docs@v1 8 | with: 9 | inputA: 10 | # - Item 1 11 | # - foo, bar, baz 12 | # - Item 2 13 | # - [github](https://github.com/) 14 | # - **blah** 15 | # - Item 3 16 | # 17 | # Type: string 18 | # Required: false 19 | # Default: This is a default 20 | 21 | inputB: 22 | # This is a 23 | # multiline description 24 | # 25 | # Type: number 26 | # Required: true 27 | # Default: "" 28 | ``` 29 | 30 | -------------------------------------------------------------------------------- /__tests__/linebreak.test.ts: -------------------------------------------------------------------------------- 1 | import * as lb from "../src/linebreak"; 2 | 3 | describe("Verify line break utils.", () => { 4 | test("Test line break string to type conversion.", () => { 5 | expect(lb.getLineBreakType("CRLF")).toEqual("CRLF"); 6 | expect(lb.getLineBreakType("LF")).toEqual("LF"); 7 | expect(lb.getLineBreakType("CR")).toEqual("CR"); 8 | expect(lb.getLineBreakType("unknown")).toEqual("LF"); 9 | }); 10 | 11 | test("Verify line break character.", () => { 12 | expect(lb.getLineBreak("CR")).toEqual("\r"); 13 | expect(lb.getLineBreak("CRLF")).toEqual("\r\n"); 14 | expect(lb.getLineBreak("LF")).toEqual("\n"); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | const config = { 2 | // https://github.com/kulshekhar/ts-jest/issues/1057#issuecomment-1068342692 3 | transform: { 4 | "\\.[jt]sx?$": ["ts-jest", { useESM: true }], 5 | }, 6 | moduleNameMapper: { 7 | "^(\\.\\.?\\/.+)\\.jsx?$": "$1", 8 | }, 9 | extensionsToTreatAsEsm: [".ts"], 10 | coverageReporters: ["lcov", "text", "html"], 11 | collectCoverageFrom: ["src/**/*.{ts,js,jsx}", "!src/**/*cli*.ts"], 12 | testEnvironment: "node", 13 | collectCoverage: true, 14 | clearMocks: true, 15 | moduleFileExtensions: ["js", "ts"], 16 | verbose: true, 17 | coverageThreshold: { 18 | global: { 19 | statements: 100, 20 | branches: 98.14, 21 | functions: 96.66, 22 | lines: 100, 23 | }, 24 | }, 25 | }; 26 | 27 | export default config; 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "action-docs", 3 | "version": "2.5.2", 4 | "description": "Generate GitHub action docs based on action.yml", 5 | "main": "lib/index.js", 6 | "types": "lib/index.d.ts", 7 | "type": "module", 8 | "bin": { 9 | "action-docs": "lib/cli.js" 10 | }, 11 | "scripts": { 12 | "prepare": "tsc", 13 | "build": "tsc", 14 | "format": "prettier --write **/*.ts", 15 | "format-check": "prettier --check **/*.ts", 16 | "lint": "eslint src/**/*.ts", 17 | "test": "jest --runInBand --testTimeout=10000 --collect-coverage --coverage", 18 | "test-default": "jest --testTimeout=10000 --testPathIgnorePatterns=__tests__/cli.test.ts --collect-coverage --coverage", 19 | "test-cli": "nyc jest --testTimeout=10000 --silent --testMatch=**/cli*test.ts && nyc report --reporter=lcov --reporter=html --report-dir=./coverage_nyc", 20 | "test-action": "nyc jest --testTimeout=10000 --silent --testMatch=**/action-docs-action.test.ts --coverage=false", 21 | "test-workflow": "nyc jest --testTimeout=10000 --silent --testMatch=**/action-docs-workflow.test.ts --coverage=false", 22 | "dev-action": "yarn run build && node lib/cli.js -s __tests__/fixtures/action/action.yml", 23 | "dev-workflow": "yarn run build && node lib/cli.js -s __tests__/fixtures/workflow/workflow.yml", 24 | "help": "yarn run build && node lib/cli.js --help", 25 | "all": "yarn run build && yarn run format && yarn run lint && yarn test" 26 | }, 27 | "repository": { 28 | "type": "git", 29 | "url": "git+https://github.com/npalm/action-docs.git" 30 | }, 31 | "keywords": [ 32 | "actions", 33 | "node", 34 | "github", 35 | "cli", 36 | "docs" 37 | ], 38 | "author": "Niek Palm", 39 | "license": "MIT", 40 | "dependencies": { 41 | "chalk": "^5.3.0", 42 | "figlet": "^1.7.0", 43 | "replace-in-file": "^7.1.0", 44 | "showdown": "^2.1.0", 45 | "yaml": "^2.3.4", 46 | "yargs": "^17.7.2" 47 | }, 48 | "files": [ 49 | "lib", 50 | "src", 51 | "tsconfig.json", 52 | "README.md" 53 | ], 54 | "devDependencies": { 55 | "@types/figlet": "^1.5.0", 56 | "@types/jest": "^29.5.12", 57 | "@types/showdown": "^2.0.6", 58 | "@typescript-eslint/parser": "^8.8.1", 59 | "eslint": "^8.56.0", 60 | "eslint-import-resolver-typescript": "^3.6.1", 61 | "eslint-plugin-github": "^4.10.0", 62 | "eslint-plugin-jest": "^27.6.0", 63 | "eslint-plugin-prettier": "^5.1.0", 64 | "jest": "^29.7.0", 65 | "nyc": "^17.0.0", 66 | "prettier": "^3.2.5", 67 | "ts-jest": "^29.1.0", 68 | "typescript": "^5.3.0", 69 | "yaml-types": "^0.4.0", 70 | "yarn": "^1.22.0" 71 | }, 72 | "bugs": { 73 | "url": "https://github.com/npalm/action-docs/issues" 74 | }, 75 | "homepage": "https://github.com/npalm/action-docs#readme", 76 | "directories": { 77 | "dist": "lib" 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /sonar-project.properties: -------------------------------------------------------------------------------- 1 | sonar.sources=src 2 | sonar.tests=__tests__ 3 | sonar.host.url=https://sonarcloud.io/ 4 | sonar.typescript.lcov.reportPaths=./coverage/lcov.info 5 | sonar.coverage.excludePattern=**/__tests__/**, **/*cli.ts 6 | -------------------------------------------------------------------------------- /src/action-docs.ts: -------------------------------------------------------------------------------- 1 | import { LineBreakType, getLineBreak } from "./linebreak.js"; 2 | import { parse } from "yaml"; 3 | import { readFileSync } from "fs"; 4 | import replaceInFile from "replace-in-file"; 5 | import pkg from "showdown"; 6 | const { Converter } = pkg; 7 | const converter = new Converter(); 8 | 9 | export interface Options { 10 | tocLevel?: number; 11 | sourceFile?: string; 12 | updateReadme?: boolean; 13 | readmeFile?: string; 14 | lineBreaks?: LineBreakType; 15 | includeNameHeader?: boolean; 16 | } 17 | 18 | interface YmlStructure { 19 | name: string; 20 | description: string; 21 | on: Record; 22 | inputs: ActionInputsOutputs; 23 | outputs: ActionInputsOutputs; 24 | runs: RunType; 25 | } 26 | 27 | interface RunType { 28 | using: string; 29 | main: string; 30 | } 31 | 32 | interface WorkflowTriggerEvent { 33 | types: string[]; 34 | branches: string[]; 35 | cron: string[]; 36 | inputs: ActionInputsOutputs; 37 | secrets: ActionInputsOutputs; 38 | outputs: ActionInputsOutputs; 39 | } 40 | 41 | interface DefaultOptions { 42 | tocLevel: number; 43 | sourceFile: string; 44 | updateReadme: boolean; 45 | readmeFile: string; 46 | lineBreaks: LineBreakType; 47 | includeNameHeader: boolean; 48 | } 49 | 50 | export const defaultOptions: DefaultOptions = { 51 | tocLevel: 2, 52 | sourceFile: "action.yml", 53 | updateReadme: false, 54 | readmeFile: "README.md", 55 | lineBreaks: "LF", 56 | includeNameHeader: false, 57 | }; 58 | 59 | type ActionInputsOutputs = Record; 60 | 61 | enum InputType { 62 | number, 63 | string, 64 | boolean, 65 | } 66 | 67 | enum InputOutputType { 68 | actionInput, 69 | workflowInput, 70 | actionOutput, 71 | workflowSecret, 72 | } 73 | 74 | const inputOutputHeaders: Record = { 75 | [InputOutputType.actionInput]: ["name", "description", "required", "default"], 76 | [InputOutputType.workflowInput]: [ 77 | "name", 78 | "description", 79 | "type", 80 | "required", 81 | "default", 82 | ], 83 | [InputOutputType.actionOutput]: ["name", "description"], 84 | [InputOutputType.workflowSecret]: ["name", "description", "required"], 85 | }; 86 | 87 | const inputOutputDefaults: Record = { 88 | description: "", 89 | type: "", 90 | required: "false", 91 | default: '""', 92 | }; 93 | 94 | interface InputOutput { 95 | required?: boolean; 96 | description?: string; 97 | default?: string; 98 | type?: InputType; 99 | deprecationMessage?: string; 100 | } 101 | 102 | function createMdTable( 103 | data: ActionInputsOutputs, 104 | options: DefaultOptions, 105 | type: InputOutputType, 106 | ): string { 107 | const tableData = getInputOutput(data, type); 108 | 109 | const headers = tableData.headers; 110 | const filler = Array(tableData.headers.length).fill("---"); 111 | 112 | const result = [headers, filler] 113 | .concat(tableData.rows) 114 | .filter((x) => x.length > 0) 115 | .map((x) => `| ${x.join(" | ")} |${getLineBreak(options.lineBreaks)}`) 116 | .join(""); 117 | 118 | return result; 119 | } 120 | 121 | function createMdCodeBlock( 122 | data: ActionInputsOutputs, 123 | options: DefaultOptions, 124 | isAction = true, 125 | ): string { 126 | let codeBlockArray = ["```yaml"]; 127 | 128 | let indent = ""; 129 | 130 | if (isAction) { 131 | codeBlockArray.push("- uses: ***PROJECT***@***VERSION***"); 132 | indent += " "; 133 | } else { 134 | codeBlockArray.push("jobs:"); 135 | indent += " "; 136 | codeBlockArray.push(`${indent}job1:`); 137 | indent += " "; 138 | codeBlockArray.push(`${indent}uses: ***PROJECT***@***VERSION***`); 139 | } 140 | 141 | const inputs = getInputOutput( 142 | data, 143 | isAction ? InputOutputType.actionInput : InputOutputType.workflowInput, 144 | false, 145 | ); 146 | 147 | if (data) { 148 | codeBlockArray.push(`${indent}with:`); 149 | indent += " "; 150 | 151 | for (const row of inputs.rows) { 152 | const inputName = row[0]; 153 | const inputDescCommented = row[1] 154 | .split(/(\r\n|\n|\r)/gm) 155 | .filter((l) => !["", "\r", "\n", "\r\n"].includes(l)) 156 | .map((l) => `# ${l}`); 157 | const type = isAction ? undefined : row[2]; 158 | const isRequired = isAction ? row[2] : row[3]; 159 | const defaultVal = isAction ? row[3] : row[4]; 160 | 161 | const inputBlock = [`${inputName}:`]; 162 | inputBlock.push(...inputDescCommented); 163 | inputBlock.push("#"); 164 | if (type) { 165 | inputBlock.push(`# Type: ${type}`); 166 | } 167 | inputBlock.push(`# Required: ${isRequired}`); 168 | if (defaultVal) { 169 | inputBlock.push(`# Default: ${defaultVal}`); 170 | } 171 | 172 | codeBlockArray.push(...inputBlock.map((l) => `${indent}${l}`)); 173 | codeBlockArray.push(""); 174 | } 175 | if (inputs.rows.length > 0) { 176 | codeBlockArray = codeBlockArray.slice(0, -1); 177 | } 178 | } 179 | 180 | codeBlockArray.push("```"); 181 | 182 | // Create final resulting code block 183 | let result = ""; 184 | for (const line of codeBlockArray) { 185 | result = `${result}${line}${getLineBreak(options.lineBreaks)}`; 186 | } 187 | return result; 188 | } 189 | 190 | function getToc(tocLevel: number): string { 191 | let result = ""; 192 | for (let i = 0; i < tocLevel; i++) { 193 | result = `${result}#`; 194 | } 195 | return result; 196 | } 197 | 198 | export async function generateActionMarkdownDocs( 199 | inputOptions?: Options, 200 | ): Promise { 201 | const options: DefaultOptions = { 202 | ...defaultOptions, 203 | ...inputOptions, 204 | }; 205 | 206 | const docs = generateDocs(options); 207 | let outputString = ""; 208 | 209 | for (const key in docs) { 210 | const value = docs[key]; 211 | 212 | if (options.updateReadme) { 213 | await updateReadme(options, value, key, options.sourceFile); 214 | } 215 | 216 | outputString += value; 217 | } 218 | 219 | if (options.updateReadme) { 220 | await updateReadme(options, outputString, "all", options.sourceFile); 221 | } 222 | 223 | return outputString; 224 | } 225 | 226 | function generateDocs(options: DefaultOptions): Record { 227 | const yml = parse(readFileSync(options.sourceFile, "utf-8")) as YmlStructure; 228 | 229 | if (yml.runs === undefined) { 230 | return generateWorkflowDocs(yml, options); 231 | } else { 232 | return generateActionDocs(yml, options); 233 | } 234 | } 235 | 236 | function generateActionDocs( 237 | yml: YmlStructure, 238 | options: DefaultOptions, 239 | ): Record { 240 | return { 241 | header: generateHeader(yml, options), 242 | description: createMarkdownSection(options, yml.description, "Description"), 243 | inputs: generateInputs(yml.inputs, options, InputOutputType.actionInput), 244 | outputs: generateOutputs(yml.outputs, options), 245 | runs: createMarkdownSection( 246 | options, 247 | // eslint-disable-next-line i18n-text/no-en 248 | `This action is a \`${yml.runs.using}\` action.`, 249 | "Runs", 250 | ), 251 | usage: generateUsage(yml.inputs, options), 252 | }; 253 | } 254 | 255 | function generateWorkflowDocs( 256 | yml: YmlStructure, 257 | options: DefaultOptions, 258 | ): Record { 259 | return { 260 | header: generateHeader(yml, options), 261 | inputs: generateInputs( 262 | yml.on.workflow_call?.inputs, 263 | options, 264 | InputOutputType.workflowInput, 265 | ), 266 | secrets: generateSecrets(yml.on.workflow_call?.secrets, options), 267 | outputs: generateOutputs(yml.on.workflow_call?.outputs, options), 268 | runs: "", 269 | usage: generateUsage(yml.on.workflow_call?.inputs, options, false), 270 | }; 271 | } 272 | 273 | function generateHeader(yml: YmlStructure, options: DefaultOptions): string { 274 | let header = ""; 275 | if (options.includeNameHeader) { 276 | header = createMarkdownHeader(options, yml.name); 277 | options.tocLevel++; 278 | } 279 | 280 | return header; 281 | } 282 | 283 | function generateInputs( 284 | data: ActionInputsOutputs, 285 | options: DefaultOptions, 286 | type: InputOutputType, 287 | ): string { 288 | const inputMdTable = createMdTable(data, options, type); 289 | return createMarkdownSection(options, inputMdTable, "Inputs"); 290 | } 291 | 292 | function generateSecrets( 293 | data: ActionInputsOutputs, 294 | options: DefaultOptions, 295 | ): string { 296 | const secretMdTable = createMdTable( 297 | data, 298 | options, 299 | InputOutputType.workflowSecret, 300 | ); 301 | return createMarkdownSection(options, secretMdTable, "Secrets"); 302 | } 303 | 304 | function generateOutputs( 305 | data: ActionInputsOutputs, 306 | options: DefaultOptions, 307 | ): string { 308 | const outputMdTable = createMdTable( 309 | data, 310 | options, 311 | InputOutputType.actionOutput, 312 | ); 313 | return createMarkdownSection(options, outputMdTable, "Outputs"); 314 | } 315 | 316 | function generateUsage( 317 | data: ActionInputsOutputs, 318 | options: DefaultOptions, 319 | isAction = true, 320 | ): string { 321 | const usageMdCodeBlock = createMdCodeBlock(data, options, isAction); 322 | return createMarkdownSection(options, usageMdCodeBlock, "Usage"); 323 | } 324 | 325 | function escapeRegExp(x: string): string { 326 | return x.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string 327 | } 328 | 329 | async function updateReadme( 330 | options: DefaultOptions, 331 | text: string, 332 | section: string, 333 | sourceFile: string, 334 | ): Promise { 335 | const lineBreak = getLineBreak(options.lineBreaks); 336 | 337 | const readmeFileText = String(readFileSync(options.readmeFile, "utf-8")); 338 | const sourceOrActionMatches = readmeFileText.match( 339 | new RegExp(`.?`, 347 | ), 348 | ) as string[]; 349 | 350 | let commentExpression = ``; 351 | commentExpression = commentExpression.replace( 352 | "PROJECT_VERSION", 353 | matchProjectVersion 354 | ? `project="${matchProjectVersion[1]}" version="${matchProjectVersion[2]}" ` 355 | : "", 356 | ); 357 | 358 | const regexp = new RegExp( 359 | `${escapeRegExp(commentExpression)}(?:(?:\r\n|\r|\n.*)+${escapeRegExp(commentExpression)})?`, 360 | ); 361 | 362 | const processedText = text 363 | .trim() 364 | .replace( 365 | "***PROJECT***", 366 | matchProjectVersion ? matchProjectVersion[1] : "", 367 | ) 368 | .replace( 369 | "***VERSION***", 370 | matchProjectVersion ? matchProjectVersion[2] : "", 371 | ); 372 | 373 | await replaceInFile.replaceInFile({ 374 | files: options.readmeFile, 375 | from: regexp, 376 | to: 377 | commentExpression + 378 | lineBreak + 379 | processedText + 380 | lineBreak + 381 | commentExpression, 382 | }); 383 | } 384 | } 385 | 386 | function createMarkdownSection( 387 | options: DefaultOptions, 388 | data: string, 389 | header: string, 390 | ): string { 391 | const lineBreak = getLineBreak(options.lineBreaks); 392 | 393 | return data === "" || data === undefined 394 | ? "" 395 | : `${createMarkdownHeader(options, header)}${data}` + 396 | `${lineBreak}` + 397 | `${lineBreak}`; 398 | } 399 | 400 | function createMarkdownHeader(options: DefaultOptions, header: string): string { 401 | const lineBreak = getLineBreak(options.lineBreaks); 402 | 403 | return `${getToc(options.tocLevel)} ${header}${lineBreak}${lineBreak}`; 404 | } 405 | 406 | function isHtmlColumn(columnName: string): boolean { 407 | return columnName === "description"; 408 | } 409 | 410 | function stripNewLines(value: string): string { 411 | return value.replace(/\r\n|\r|\n/g, " "); 412 | } 413 | 414 | function getInputOutput( 415 | data: ActionInputsOutputs, 416 | type: InputOutputType, 417 | format = true, 418 | ): { headers: string[]; rows: string[][] } { 419 | let headers: string[] = []; 420 | const rows: string[][] = []; 421 | 422 | if (data === undefined) { 423 | return { headers, rows }; 424 | } 425 | 426 | headers = inputOutputHeaders[type]; 427 | 428 | for (let i = 0; i < Object.keys(data).length; i++) { 429 | const key = Object.keys(data)[i]; 430 | const value = data[key] as Record; 431 | rows[i] = []; 432 | 433 | for (const columnName of headers) { 434 | let rowValue = ""; 435 | 436 | if (columnName === "name") { 437 | rowValue = key; 438 | } else if (columnName === "description") { 439 | rowValue = value[columnName]; 440 | if (value["deprecationMessage"] !== undefined) { 441 | rowValue += "
_Deprecated"; 442 | if (value["deprecationMessage"] !== "") { 443 | rowValue += `: ${value["deprecationMessage"]}`; 444 | } 445 | rowValue += "_"; 446 | } 447 | } else if (columnName === "default") { 448 | rowValue = 449 | value[columnName] !== undefined && value[columnName] !== "" 450 | ? stripNewLines(String(value[columnName])) 451 | : inputOutputDefaults[columnName]; 452 | } else { 453 | rowValue = value[columnName] 454 | ? value[columnName] 455 | : inputOutputDefaults[columnName]; 456 | } 457 | 458 | if (format) { 459 | if (isHtmlColumn(columnName)) { 460 | rowValue = stripNewLines(converter.makeHtml(rowValue)).trim(); 461 | } else { 462 | rowValue = `\`${rowValue}\``; 463 | } 464 | } 465 | 466 | rows[i].push(rowValue); 467 | } 468 | } 469 | return { headers, rows }; 470 | } 471 | -------------------------------------------------------------------------------- /src/cli.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import { defaultOptions, generateActionMarkdownDocs } from "./index.js"; 4 | import chalk from "chalk"; 5 | import figlet from "figlet"; 6 | import { getLineBreakType } from "./linebreak.js"; 7 | import yargs from "yargs"; 8 | 9 | const args = await yargs(process.argv.slice(2)) 10 | .options({ 11 | "toc-level": { 12 | description: "TOC level used for markdown", 13 | type: "number", 14 | default: defaultOptions.tocLevel, 15 | demandOption: false, 16 | alias: "t", 17 | }, 18 | action: { 19 | description: "GitHub action file", 20 | type: "string", 21 | default: defaultOptions.sourceFile, 22 | demandOption: false, 23 | alias: "a", 24 | deprecated: 'use "source" instead', 25 | }, 26 | source: { 27 | description: "GitHub source file", 28 | type: "string", 29 | default: defaultOptions.sourceFile, 30 | demandOption: false, 31 | alias: "s", 32 | }, 33 | "no-banner": { 34 | description: "Print no banner", 35 | requiresArg: false, 36 | }, 37 | "update-readme": { 38 | description: "Update readme file.", 39 | requiresArg: false, 40 | type: "string", 41 | alias: "u", 42 | }, 43 | "line-breaks": { 44 | description: "Used line breaks in the generated docs.", 45 | default: "LF", 46 | choices: ["CR", "LF", "CRLF"], 47 | demandOption: false, 48 | type: "string", 49 | alias: "l", 50 | }, 51 | "include-name-header": { 52 | description: "Include a header with the action/workflow name", 53 | type: "boolean", 54 | alias: "n", 55 | }, 56 | }) 57 | .help().argv; 58 | 59 | args.banner === undefined && 60 | console.info( 61 | chalk.blue(figlet.textSync("ACTION-DOCS", { horizontalLayout: "full" })), 62 | ); 63 | 64 | const updateReadme = args["update-readme"] !== undefined; 65 | 66 | const sourceFile = 67 | args.source === defaultOptions.sourceFile ? args.action : args.source; 68 | 69 | const options = { 70 | sourceFile, 71 | tocLevel: args["toc-level"], 72 | updateReadme, 73 | readmeFile: 74 | args["update-readme"] === undefined || args["update-readme"] === "" 75 | ? defaultOptions.readmeFile 76 | : args["update-readme"], 77 | lineBreaks: getLineBreakType(args["line-breaks"]), 78 | includeNameHeader: 79 | args["include-name-header"] === undefined 80 | ? defaultOptions.includeNameHeader 81 | : args["include-name-header"], 82 | }; 83 | 84 | /* eslint-disable github/no-then */ 85 | generateActionMarkdownDocs(options) 86 | .then((r) => { 87 | if (!updateReadme) { 88 | console.info(r); 89 | } 90 | }) 91 | .catch((e) => console.error(e.message)); 92 | /* eslint-enable */ 93 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | generateActionMarkdownDocs, 3 | Options, 4 | defaultOptions, 5 | } from "./action-docs.js"; 6 | -------------------------------------------------------------------------------- /src/linebreak.ts: -------------------------------------------------------------------------------- 1 | export type LineBreakType = "CR" | "LF" | "CRLF"; 2 | 3 | export function getLineBreak(lineBreakType: LineBreakType): string { 4 | switch (lineBreakType) { 5 | case "CR": 6 | return "\r"; 7 | case "LF": 8 | return "\n"; 9 | case "CRLF": 10 | return "\r\n"; 11 | } 12 | } 13 | 14 | export function getLineBreakType(value: string): LineBreakType { 15 | if (isLineBreakType(value)) { 16 | return value; 17 | } else { 18 | return "LF" as LineBreakType; 19 | } 20 | } 21 | 22 | function isLineBreakType(value: string): value is LineBreakType { 23 | return value === "CR" || value === "LF" || value === "CRLF"; 24 | } 25 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2022" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */, 4 | "module": "NodeNext" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */, 5 | "moduleResolution": "NodeNext", 6 | "outDir": "./lib" /* Redirect output structure to the directory. */, 7 | "rootDir": "./src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */, 8 | "strict": true /* Enable all strict type-checking options. */, 9 | "noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */, 10 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, 11 | "declaration": true 12 | }, 13 | "exclude": ["node_modules", "**/*.test.ts", "lib"] 14 | } 15 | --------------------------------------------------------------------------------