├── .gitignore ├── CODE_OF_CONDUCT.md ├── .github └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── LICENSE ├── action.yml ├── entrypoint.sh └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # MacOS system files 2 | .DS_Store 3 | # NPM 4 | node_modules/ 5 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | Be excellent to each other. 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Request a feature! 4 | title: "[FEATURE]" 5 | labels: enhancement 6 | assignees: "" 7 | --- 8 | 9 | **What would you like to change about the program?** 10 | A clear and concise description of what the problem is. 11 | 12 | **Why do you think this is a cool idea?** 13 | A clear and concise description of why your feature would improve the program. 14 | 15 | 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Report a problem! 4 | title: "[BUG]" 5 | labels: bug 6 | assignees: "" 7 | --- 8 | 9 | **What exactly happened?** 10 | Steps to reproduce the behavior: 11 | 12 | 1. Go to '...' 13 | 2. Click on '....' 14 | 3. Scroll down to '....' 15 | 4. See error 16 | 17 | **What should've happened?** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **How did it look?** 21 | If applicable, add screenshots to help explain your problem. 22 | 23 | **Where did you encounter the problem?** 24 | 25 | - Repo: [e.g. URL to your repository] 26 | - Version [e.g. 22] 27 | 28 | 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Conrad Großer 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 NON-INFRINGEMENT. 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 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: Prettier Action 2 | description: Automatically runs prettier on all your changes. 3 | 4 | author: Conrad Großer 5 | 6 | inputs: 7 | commit_message: 8 | description: Commit message, will be ignored if used with same_commit 9 | required: false 10 | default: "Prettified Code!" 11 | commit_description: 12 | description: Extended commit message, will be ignored if used with same_commit 13 | required: false 14 | default: "" 15 | same_commit: 16 | description: Update the current commit instead of creating a new one 17 | required: false 18 | default: false 19 | commit_options: 20 | description: Commit options 21 | required: false 22 | push_options: 23 | description: Git push options 24 | required: false 25 | file_pattern: 26 | description: File pattern used for `git add`, can't be used with only_changed or only_changed_pr! 27 | required: false 28 | default: "*" 29 | prettier_options: 30 | description: Options for the `prettier` command 31 | required: false 32 | default: "--write **/*.js" 33 | dry: 34 | description: Running the script in dry mode just shows whether there are files that should be prettified or not 35 | required: false 36 | default: false 37 | no_commit: 38 | description: Can be used to avoid committing the changes (can be combined with dry mode, useful when another workflow steps commits after this commit anyways) 39 | required: false 40 | default: false 41 | prettier_version: 42 | description: Specific version of prettier (by default just use the latest version) 43 | required: false 44 | default: "latest" 45 | working_directory: 46 | description: Specify a directory to cd into before installing prettier and running it 47 | required: false 48 | default: ${{ github.action_path }} 49 | only_changed: 50 | description: Only prettify files changed in the last commit, can't be used with file_pattern! 51 | required: false 52 | default: false 53 | only_changed_pr: 54 | description: Only prettify files changed in the current PR. If specified with only_changed, only_changed will take precedent. Can't be used with file_pattern! 55 | required: false 56 | default: false 57 | prettier_plugins: 58 | description: Install Prettier plugins, i.e. `@prettier/plugin-php @prettier/plugin-other` 59 | required: false 60 | default: "" 61 | github_token: 62 | description: GitHub Token or PAT token used to authenticate against a repository 63 | required: false 64 | default: ${{ github.token }} 65 | clean_node_folder: 66 | description: Remove the node_modules folder before committing changes 67 | required: false 68 | default: true 69 | git_identity: 70 | description: Which identity is used for git name/email when committing changes. Needs to be one of "actions" or "author". 71 | required: false 72 | default: "actions" 73 | allow_other_plugins: 74 | description: Allow other plugins to be installed. By default, we are checking if the plugins are actually prettier plugins. 75 | required: false 76 | default: false 77 | 78 | runs: 79 | using: "composite" 80 | steps: 81 | - name: Prettify code! 82 | shell: bash 83 | run: >- 84 | PATH=$GITHUB_ACTION_PATH/node_modules/.bin:$PATH 85 | ${{ github.action_path }}/entrypoint.sh 86 | env: 87 | INPUT_COMMIT_MESSAGE: ${{ inputs.commit_message }} 88 | INPUT_COMMIT_DESCRIPTION: ${{ inputs.commit_description }} 89 | INPUT_SAME_COMMIT: ${{ inputs.same_commit }} 90 | INPUT_COMMIT_OPTIONS: ${{ inputs.commit_options }} 91 | INPUT_PUSH_OPTIONS: ${{ inputs.push_options }} 92 | INPUT_FILE_PATTERN: ${{ inputs.file_pattern }} 93 | INPUT_PRETTIER_OPTIONS: ${{ inputs.prettier_options }} 94 | INPUT_DRY: ${{ inputs.dry }} 95 | INPUT_NO_COMMIT: ${{ inputs.no_commit }} 96 | INPUT_PRETTIER_VERSION: ${{ inputs.prettier_version }} 97 | INPUT_ONLY_CHANGED: ${{ inputs.only_changed }} 98 | INPUT_ONLY_CHANGED_PR: ${{ inputs.only_changed_pr }} 99 | INPUT_PRETTIER_PLUGINS: ${{ inputs.prettier_plugins }} 100 | INPUT_WORKING_DIRECTORY: ${{ inputs.working_directory }} 101 | INPUT_GITHUB_TOKEN: ${{ inputs.github_token }} 102 | INPUT_CLEAN_NODE_FOLDER: ${{ inputs.clean_node_folder }} 103 | INPUT_GIT_IDENTITY: ${{ inputs.git_identity }} 104 | INPUT_ALLOW_OTHER_PLUGINS: ${{ inputs.allow_other_plugins }} 105 | 106 | branding: 107 | icon: "award" 108 | color: "green" 109 | -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # e is for exiting the script automatically if a command fails, u is for exiting if a variable is not set 3 | # x would be for showing the commands before they are executed 4 | set -eu 5 | shopt -s globstar 6 | 7 | # FUNCTIONS 8 | # Function for setting up git env in the docker container (copied from https://github.com/stefanzweifel/git-auto-commit-action/blob/master/entrypoint.sh) 9 | _git_setup ( ) { 10 | cat <<- EOF > $HOME/.netrc 11 | machine github.com 12 | login $GITHUB_ACTOR 13 | password $INPUT_GITHUB_TOKEN 14 | machine api.github.com 15 | login $GITHUB_ACTOR 16 | password $INPUT_GITHUB_TOKEN 17 | EOF 18 | chmod 600 $HOME/.netrc 19 | 20 | # If GIT_IDENTITY="actor" 21 | if [ "$INPUT_GIT_IDENTITY" = "author" ]; then 22 | git config --global user.name "$GITHUB_ACTOR" 23 | git config --global user.email "$GITHUB_ACTOR_ID+$GITHUB_ACTOR@users.noreply.github.com" 24 | elif [ "$INPUT_GIT_IDENTITY" = "actions" ]; then 25 | git config --global user.email "actions@github.com" 26 | git config --global user.name "GitHub Action" 27 | else 28 | echo "GIT_IDENTITY must be either 'author' or 'actions'"; 29 | exit 1; 30 | fi; 31 | } 32 | 33 | # Checks if any files are changed 34 | _git_changed() { 35 | [[ -n "$(git status -s)" ]] 36 | } 37 | 38 | ( 39 | # PROGRAM 40 | # Changing to the directory 41 | if [ -z "$INPUT_WORKING_DIRECTORY" ] ; then 42 | INPUT_WORKING_DIRECTORY=$GITHUB_ACTION_PATH 43 | fi 44 | cd "$INPUT_WORKING_DIRECTORY" 45 | 46 | echo "Installing prettier..." 47 | 48 | npm install --silent prettier@$INPUT_PRETTIER_VERSION 49 | 50 | # Install plugins 51 | if [ -n "$INPUT_PRETTIER_PLUGINS" ]; then 52 | if [ "$INPUT_ALLOW_OTHER_PLUGINS" != "true" ]; then 53 | for plugin in $INPUT_PRETTIER_PLUGINS; do 54 | echo "Checking plugin: $plugin" 55 | # check regex against @prettier/xyz 56 | if ! echo "$plugin" | grep -Eq '(@prettier\/plugin-|(@[a-z\-]+\/)?prettier-plugin-){1}([a-z\-]+)'; then 57 | echo "$plugin does not seem to be a valid @prettier/plugin-x plugin. Exiting." 58 | exit 1 59 | fi 60 | done 61 | fi 62 | npm install --silent $INPUT_PRETTIER_PLUGINS 63 | fi 64 | ) 65 | 66 | PRETTIER_RESULT=0 67 | echo "Prettifying files..." 68 | echo "Files:" 69 | npx prettier $INPUT_PRETTIER_OPTIONS \ 70 | || { PRETTIER_RESULT=$?; echo "Problem running prettier with $INPUT_PRETTIER_OPTIONS"; exit 1; } >> $GITHUB_STEP_SUMMARY 71 | 72 | echo "Prettier result: $PRETTIER_RESULT" 73 | 74 | # Removing the node_modules folder, so it doesn't get committed if it is not added in gitignore 75 | if $INPUT_CLEAN_NODE_FOLDER; then 76 | echo "Deleting node_modules/ folder..." 77 | if [ -d 'node_modules' ]; then 78 | rm -r node_modules/ 79 | else 80 | echo "No node_modules/ folder." 81 | fi 82 | fi 83 | 84 | if [ -f 'package-lock.json' ]; then 85 | git checkout -- package-lock.json || echo "No package-lock.json file tracked by git." 86 | else 87 | echo "No package-lock.json file." 88 | fi 89 | 90 | # If running under only_changed, reset every modified file that wasn't also modified in the last commit 91 | # This allows only_changed and dry to work together, and simplified the non-dry logic below 92 | if [ $INPUT_ONLY_CHANGED = true ] || [ $INPUT_ONLY_CHANGED_PR = true ] ; then 93 | BASE_BRANCH=origin/$GITHUB_BASE_REF 94 | if $INPUT_ONLY_CHANGED; then 95 | BASE_BRANCH=HEAD~1 96 | fi 97 | 98 | echo "Resetting changes, removing changes to files not changed since $BASE_BRANCH" 99 | # list of all files changed in the previous commit 100 | git diff --name-only HEAD $BASE_BRANCH > /tmp/prev.txt 101 | # list of all files with outstanding changes 102 | git diff --name-only HEAD > /tmp/cur.txt 103 | 104 | OLDIFS="$IFS" 105 | IFS=$'\n' 106 | # get all files that are in prev.txt that aren't also in cur.txt 107 | for file in $(comm -1 -3 /tmp/prev.txt /tmp/cur.txt) 108 | do 109 | echo "resetting: $file" 110 | git restore -- "$file" 111 | done 112 | IFS="$OLDIFS" 113 | fi 114 | 115 | # To keep runtime good, just continue if something was changed 116 | if _git_changed; then 117 | # case when --write is used with dry-run so if something is unpretty there will always have _git_changed 118 | if $INPUT_DRY; then 119 | echo "Unpretty Files Changes:" 120 | git diff 121 | if $INPUT_NO_COMMIT; then 122 | echo "There are changes that won't be commited, you can use an external job to do so." 123 | else 124 | echo "Finishing dry-run. Exiting before committing." 125 | exit 1 126 | fi 127 | else 128 | # Calling method to configure the git environemnt 129 | _git_setup 130 | 131 | # Add changes to git 132 | git add "${INPUT_FILE_PATTERN}" || echo "Problem adding your files with pattern ${INPUT_FILE_PATTERN}" 133 | 134 | if $INPUT_NO_COMMIT; then 135 | echo "There are changes that won't be commited, you can use an external job to do so." 136 | exit 0 137 | fi 138 | 139 | # Commit and push changes back 140 | if $INPUT_SAME_COMMIT; then 141 | echo "Amending the current commit..." 142 | git pull 143 | git commit --amend --no-edit --allow-empty 144 | git push origin -f 145 | else 146 | if [ "$INPUT_COMMIT_DESCRIPTION" != "" ]; then 147 | git commit -m "$INPUT_COMMIT_MESSAGE" -m "$INPUT_COMMIT_DESCRIPTION" --author="$GITHUB_ACTOR <$GITHUB_ACTOR@users.noreply.github.com>" ${INPUT_COMMIT_OPTIONS:+"$INPUT_COMMIT_OPTIONS"} || echo "No files added to commit" 148 | else 149 | git commit -m "$INPUT_COMMIT_MESSAGE" --author="$GITHUB_ACTOR <$GITHUB_ACTOR@users.noreply.github.com>" ${INPUT_COMMIT_OPTIONS:+"$INPUT_COMMIT_OPTIONS"} || echo "No files added to commit" 150 | fi 151 | git push origin ${INPUT_PUSH_OPTIONS:-} 152 | fi 153 | echo "Changes pushed successfully." 154 | fi 155 | else 156 | # case when --check is used so there will never have something to commit but there are unpretty files 157 | if [ "$PRETTIER_RESULT" -eq 1 ]; then 158 | echo "Prettier found unpretty files!" 159 | exit 1 160 | else 161 | echo "Finishing dry-run." 162 | fi 163 | echo "No unpretty files!" 164 | echo "Nothing to commit. Exiting." 165 | fi 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GitHub Prettier Action 2 | 3 | [![CodeFactor](https://www.codefactor.io/repository/github/creyd/prettier_action/badge/master)](https://www.codefactor.io/repository/github/creyd/prettier_action/overview/master) 4 | [![Codacy Badge](https://app.codacy.com/project/badge/Grade/ba5fa97677ee47e48efdc2e6f7493c49)](https://app.codacy.com/gh/creyD/prettier_action/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) 5 | [![License MIT](https://img.shields.io/github/license/creyD/prettier_action)](https://github.com/creyD/prettier_action/blob/master/LICENSE) 6 | [![Latest Release](https://img.shields.io/github/v/release/creyD/prettier_action)](https://github.com/creyD/prettier_action/releases) 7 | [![Contributors](https://img.shields.io/github/contributors-anon/creyD/prettier_action)](https://github.com/creyD/prettier_action/graphs/contributors) 8 | [![Issues](https://img.shields.io/github/issues/creyD/prettier_action)](https://github.com/creyD/prettier_action/issues) 9 | 10 | A GitHub action for styling files with [prettier](https://prettier.io). 11 | 12 | ## Usage 13 | 14 | ### Parameters 15 | 16 | | Parameter | Required | Default | Description | 17 | | - | :-: | :-: | - | 18 | | dry | :x: | `false` | Runs the action in dry mode. Files wont get changed and the action fails if there are unprettified files. Recommended to use with prettier_options --check | 19 | | no_commit | :x: | `false` | Can be used to avoid committing the changes (useful when another workflow step commits after this one anyways; can be combined with dry mode) | 20 | | prettier_version | :x: | `latest` | Specific prettier version (by default use latest) | 21 | | working_directory | :x: | `${{ github.action_path }}` | Specify a directory to cd into before installing prettier and running it, use relative file path to the repository root for example `app/` | 22 | | prettier_options | :x: | `"--write **/*.js"` | Prettier options (by default it applies to the whole repository) | 23 | | commit_options | :x: | - | Custom git commit options | 24 | | push_options | :x: | - | Custom git push options | 25 | | same_commit | :x: | `false` | Update the current commit instead of creating a new one, created by [Joren Broekema](https://github.com/jorenbroekema), this command works only with the checkout action set to fetch depth '0' (see example 2) | 26 | | commit_message | :x: | `"Prettified Code!"` | Custom git commit message, will be ignored if used with `same_commit` | 27 | | commit_description | :x: | - | Custom git extended commit message, will be ignored if used with `same_commit` | 28 | | file_pattern | :x: | `*` | Custom git add file pattern, can't be used with only_changed! | 29 | | prettier_plugins | :x: | - | Install Prettier plugins, i.e. `"@prettier/plugin-php" "@prettier/plugin-other"`. Must be wrapped in quotes since @ is a reserved character in YAML. | 30 | | clean_node_folder | :x: | `true` | Delete the node_modules folder before committing | 31 | | only_changed | :x: | `false` | Only prettify changed files, can't be used with file_pattern! This command works only with the checkout action set to fetch depth '0' (see example 2)| 32 | | github_token | :x: | `${{ github.token }}` | The default [GITHUB_TOKEN](https://docs.github.com/en/actions/reference/authentication-in-a-workflow#about-the-github_token-secret) or a [Personal Access Token](https://docs.github.com/en/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token) 33 | | git_identity | :x: | `actions` | Set to `author` to use author's user as committer. This allows triggering [further workflow runs](https://github.com/peter-evans/create-pull-request/blob/main/docs/concepts-guidelines.md#triggering-further-workflow-runs) 34 | | allow_other_plugins | :x: | `false` | Allow other plugins to be installed (prevents the @prettier-XYZ regex check) | 35 | 36 | > Note: using the same_commit option may lead to problems if other actions are relying on the commit being the same before and after the prettier action has ran. Keep this in mind. 37 | 38 | ### Example Config 39 | 40 | > Hint: if you still use the old naming convention or generally a different branch name, please replace the `main` in the following configurations. 41 | 42 | #### Example 1 (run on push in branch main) 43 | 44 | ```yaml 45 | name: Continuous Integration 46 | 47 | # This action works with pull requests and pushes 48 | on: 49 | pull_request: 50 | push: 51 | branches: 52 | - main 53 | 54 | jobs: 55 | prettier: 56 | runs-on: ubuntu-latest 57 | 58 | steps: 59 | - name: Checkout 60 | uses: actions/checkout@v4 61 | 62 | - name: Prettify code 63 | uses: creyD/prettier_action@v4.6 64 | with: 65 | # This part is also where you can pass other options, for example: 66 | prettier_options: --write **/*.{js,md} 67 | ``` 68 | 69 | #### Example 2 (using the only_changed or same_commit option on PR) 70 | 71 | ```yaml 72 | name: Continuous Integration 73 | 74 | on: 75 | pull_request: 76 | branches: [main] 77 | 78 | jobs: 79 | prettier: 80 | runs-on: ubuntu-latest 81 | 82 | steps: 83 | - name: Checkout 84 | uses: actions/checkout@v4 85 | with: 86 | # Make sure the actual branch is checked out when running on pull requests 87 | ref: ${{ github.head_ref }} 88 | # This is important to fetch the changes to the previous commit 89 | fetch-depth: 0 90 | 91 | - name: Prettify code 92 | uses: creyD/prettier_action@v4.6 93 | with: 94 | # This part is also where you can pass other options, for example: 95 | prettier_options: --write **/*.{js,md} 96 | only_changed: True 97 | ``` 98 | 99 | #### Example 3 (using a custom access token on PR) 100 | 101 | ```yaml 102 | name: Continuous Integration 103 | 104 | on: 105 | pull_request: 106 | branches: [main] 107 | 108 | jobs: 109 | prettier: 110 | runs-on: ubuntu-latest 111 | 112 | steps: 113 | - name: Checkout 114 | uses: actions/checkout@v4 115 | with: 116 | fetch-depth: 0 117 | ref: ${{ github.head_ref }} 118 | # Make sure the value of GITHUB_TOKEN will not be persisted in repo's config 119 | persist-credentials: false 120 | 121 | - name: Prettify code 122 | uses: creyD/prettier_action@v4.6 123 | with: 124 | prettier_options: --write **/*.{js,md} 125 | only_changed: True 126 | # Set your custom token 127 | github_token: ${{ secrets.PERSONAL_GITHUB_TOKEN }} 128 | ``` 129 | 130 | #### Example 4 (dry run) 131 | 132 | ```yaml 133 | name: Continuous Integration 134 | 135 | on: 136 | pull_request: 137 | branches: [main] 138 | 139 | jobs: 140 | prettier: 141 | runs-on: ubuntu-latest 142 | 143 | steps: 144 | - name: Checkout 145 | uses: actions/checkout@v4 146 | with: 147 | fetch-depth: 0 148 | ref: ${{ github.head_ref }} 149 | # Make sure the value of GITHUB_TOKEN will not be persisted in repo's config 150 | persist-credentials: false 151 | 152 | - name: Prettify code 153 | uses: creyD/prettier_action@v4.6 154 | with: 155 | dry: True 156 | github_token: ${{ secrets.PERSONAL_GITHUB_TOKEN }} 157 | ``` 158 | 159 | More documentation for writing a workflow can be found [here](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions). 160 | 161 | ## Issues 162 | 163 | Please report all bugs and feature request using the [GitHub issues function](https://github.com/creyD/prettier_action/issues/new). Thanks! 164 | 165 | ### Problem with NPM v9 (19.02.2023) 166 | 167 | This issue was discussed in https://github.com/creyD/prettier_action/issues/113. The action until release 4 uses the npm bin command, which apparently doesn't work on npm v9. A fix is introduced with v4.3 of this action. If you need an older version of the action working it works until v3.3 and between v3.3 and v4.2 you could use the workaround described in https://github.com/creyD/prettier_action/issues/113 by adding the below to your workflow file: 168 | 169 | ``` 170 | - name: Install npm v8 171 | run: npm i -g npm@8 172 | ``` 173 | 174 | ## Star History 175 | 176 | 177 | 178 | 179 | 180 | Star History Chart 181 | 182 | 183 | --------------------------------------------------------------------------------