pierrot

1. Introduction

Pierrot is a tool which helps you to manage many GitHub repositories with single command. The typical use cases are

  • Upgrade the version of dependency or tool within the GitHub organization

  • Migrate deprecated code across many repositories

  • Batch create or delete files within the GitHub organization (license files, security documents)

  • Compare configuration files across many repositories (e.g. GitHub workflow files)

2. Installation

Pierrot can be installed using SDKMAN!

sdk update
sdk install pierrot

Once installed, you should see the following message when you run the pierrot command:

GitHub client is not authenticated. Please, set up your GitHub token
    PIERROT_TOKEN environment variable
  --token=<token> command line parameter
Alternatively, see other authentication options in the GitHub API docs:

    https://github-api.kohsuke.org

Usage: pierrot [-hsV] [--summary-file=<summaryFile>] [--token=<token>] [COMMAND]
The GitHub cross-repository governance tool
  -h, --help            Show this help message and exit.
  -s, --stacktrace      Print stack traces
      --summary-file=<summaryFile>
                        Markdown summary file path
      --token=<token>   The GitHub token
  -V, --version         Print version information and exit.
Commands:
  create   creates a file in a matching repositories and creates PRs
  delete   creates PRs to delete files
  init     initializes new workspace
  pull     pulls the matching files locally
  push     pushes the the local changes and creates PRs
  replace  replaces content in the files and creates PRs
  search   searches GitHub and prints the matching files
  status   searches GitHub Pull Requests and prints their statuses
If you plan to use Pierrot from Github Actions then you can use Setup Pierrot Action
Alternatively you can download and extract the latest binaries from the release page and add the bin folder to your PATH. Run xattr -d com.apple.quarantine pierrot to remove quarantine from the downloaded file on macOS.

3. Usage

Pierrot provides various command to batch-manipulate code in the GitHub repositories.You can see the list of available commands when you run the pierrot command without any parameters:

Usage: pierrot [-hsV] [--summary-file=<summaryFile>] [--token=<token>] [COMMAND]
The GitHub cross-repository governance tool
  -h, --help            Show this help message and exit.
  -s, --stacktrace      Print stack traces
      --summary-file=<summaryFile>
                        Markdown summary file path
      --token=<token>   The GitHub token
  -V, --version         Print version information and exit.
Commands:
  create   creates a file in a matching repositories and creates PRs
  delete   creates PRs to delete files
  init     initializes new workspace
  pull     pulls the matching files locally
  push     pushes the the local changes and creates PRs
  replace  replaces content in the files and creates PRs
  search   searches GitHub and prints the matching files
  status   searches GitHub Pull Requests and prints their statuses

Pierrot requires being authenticated to GitHub.You can either set up PIERROT_TOKEN or pass the token as --token parameter. Alternatively, see other authentication options in the GitHub API for Java documentation.

All the commands are based on GitHub search syntax. Pierrot works the best if you constrain the searches to an organization.If you don’t want to add org:myorg search term to every command then set PIERROT_ORGANIZATION environment variable to the name of your organization.

3.1. Common Parameters

The commands share common parameters depending on the action their perform.

3.1.1. Shared Parameters

The following parameters can be use with any command:

      --token=<token> The GitHub token
      --summary-file=<summaryFile>
                        Markdown summary file path
  -h, --help                 Show this help message and exit.
  -s, --stacktrace           Print stack traces
  -V, --version              Print version information and exit.
The Markdown summary is generated automatically for GitHub Actions.

3.1.2. Search Parameters

Search parameters allows you to tune the search scope and pagination of the results.

  -a, --all          Include archived and closed
  -g, --global       Do not constrain search to current organization
  -P, --no-page      Do not wait after each result

3.1.3. Pull Request Parameters

Pull request parameters will be used to create new pull requests in the affected repositories.If the values are not provided in the form of command line argument then the user will be prompted to enter them first time they are requested. The pull request message is also the message for the individual commits and can be also read from file using --mesage-from parameter.

  -b, --branch=<branch>      The pull request branch
  -m, --message=<message>    The pull request message
      --message-from=<messageFrom>
  -t, --title=<title>        The pull request title
Pull request parameters can be stored in pierrot.yml file.See Init Command and Workspace Parameter.

3.1.4. Project Parameters

The commands that can create pull request or searches pull requests such as status command can add the pull requests to the GitHub Project (board) once --project parameter is provided.The other parameters are optional.The board is created if it does not exist but the automation must be set up manually.

      --done-column=<doneColumn>
                             The name of the 'Done' column in the project
      --progress-column=<progressColumn>
                             The name of the 'In progress' column in the project
      --project=<project>    The name of the project (board)
      --todo-column=<todoColumn>
                             The name of the 'To do' column in the project
Pull request parameters can be stored in pierrot.yml file.See Init Command and Workspace Parameter.

3.1.5. Workspace Parameter

Command working with workspaces such as pull and push can point to a different directory then the current one that is the default one.

  -w, --workspace=<workspace>
                     The working directory to pull found files

You can store Pull Request Parameters and Project Parameters inside the workspace in pierrot.yml file. See Init Command.

3.2. Commands

The search command allows to search GitHub using GitHub search syntax. You can experiment with the search term online at the GitHub Search Page. This is usually the first command you will run to verify the search terms.

Examples
Find All Usages of JCenter Repository within Gradle’s Build Files
pierrot search extension:gradle jcenter

JCenter has been shut down so if you still have a references in the build files then you should remove them.

Full Syntax
Usage: pierrot search [-aghPsV] [--summary-file=<summaryFile>]
                      [--token=<token>] QUERY...
searches GitHub and prints the matching files
      QUERY...          The search term such as 'org:agorapulse filename:build.
                          gradle'
  -a, --all             Include archived and closed
  -g, --global          Do not constrain search to current organization
  -h, --help            Show this help message and exit.
  -P, --no-page         Do not wait after each result
  -s, --stacktrace      Print stack traces
      --summary-file=<summaryFile>
                        Markdown summary file path
      --token=<token>   The GitHub token
  -V, --version         Print version information and exit.

3.2.2. Init Command

The init command allows to store and manage Pull Request Parameters and Project Parameters.

Examples
Set up the Pull Request and Project Defaults
pierrot init \
  --project='Micronaut Upgrade' \
  --branch=chore/upgrade-micronaut \
  --title="Upgraded Micronaut to 3.1.x" \
  --message="Upgraded Micronaut to the latest version 3.1.x" \
  --workspace=micronaut-upgrade-3.1.x

The command will generate the new folder micronaut-upgrade-3.1.x with a file pierrot.yaml with the following content

pierrot.yml
project: Micronaut Upgrade
branch: chore/upgrade-micronaut
title: Upgraded Micronaut to 3.1.x
message: Upgraded Micronaut to the latest version 3.1.x

If pierrot command is executed within micronaut-upgrade-3.1.x folder or with --workspace pointing to that folder then the values from the pierrot.yml file will be used as default values for given parameters. For example running the following command from micronaut-upgrade-3.1.x will not prompt for the pull request details and will automatically include the pull requests into Micornaut Upgrade project:

pierrot replace \
  --pattern='micronautVersion = (.*)' \
  --replacement='micronautVersion = 3.1.0'
Full Syntax
Usage: pierrot init [-fhsV] [-b=<branch>] [--done-column=<doneColumn>]
                    [-m=<message>] [--message-from=<messageFrom>]
                    [--progress-column=<progressColumn>] [--project=<project>]
                    [--summary-file=<summaryFile>] [-t=<title>]
                    [--todo-column=<todoColumn>] [--token=<token>]
                    [-w=<workspace>]
initializes new workspace
  -b, --branch=<branch>     The pull request branch
      --done-column=<doneColumn>
                            The name of the 'Done' column in the project
  -f, --force               Deletes existing branch before pushing changes
  -h, --help                Show this help message and exit.
  -m, --message=<message>   The pull request message
      --message-from=<messageFrom>
                            The file containing the pull request message
      --progress-column=<progressColumn>
                            The name of the 'In progress' column in the project
      --project=<project>   The name of the project (board)
  -s, --stacktrace          Print stack traces
      --summary-file=<summaryFile>
                            Markdown summary file path
  -t, --title=<title>       The pull request title
      --todo-column=<todoColumn>
                            The name of the 'To do' column in the project
      --token=<token>       The GitHub token
  -V, --version             Print version information and exit.
  -w, --workspace=<workspace>
                            The workspace directory

3.2.3. Create Command

The create command allows crate files in a repositories that contains files that matches a given search query. You have to specify the path within the repository, and you need to specify the content either on the command line as --content parameter or --from file. If the parameters are not provided then the user will be prompt for them.

New pull request are created with a specified changes.

  -c, --content=<content>    The inline content of the newly created file
      --from=<contentFrom>   The file to be uploaded to the repositories
  -p, --path=<path>          The path inside the repository
Examples
Create AsciiDoc Configuration File for Better IntelliJ Support
pierrot create \
  --path=.asciidoctorconfig \
  --content=':root-dir: {asciidoctorconfigdir}' \
  --branch=chore/asciidoctorconfig \
  --title="Added AsciiDoc Config File" \
  --message="Added AsciiDoc configuration file for better support in IntelliJ" \
  extension:adoc

AsciiDoc Plugin can provide better support if you have .asciidoctorconfig file within your repository root.

Full Syntax
Usage: pierrot create [-afghPsV] [-b=<branch>] [-c=<content>]
                      [--done-column=<doneColumn>] [--from=<contentFrom>]
                      [-m=<message>] [--message-from=<messageFrom>] [-p=<path>]
                      [--progress-column=<progressColumn>]
                      [--project=<project>] [--summary-file=<summaryFile>]
                      [-t=<title>] [--todo-column=<todoColumn>]
                      [--token=<token>] [-w=<workspace>] QUERY...
creates a file in a matching repositories and creates PRs
      QUERY...               The search term such as 'org:agorapulse filename:
                               build.gradle'
  -a, --all                  Include archived and closed
  -b, --branch=<branch>      The pull request branch
  -c, --content=<content>    The inline content of the newly created file
      --done-column=<doneColumn>
                             The name of the 'Done' column in the project
  -f, --force                Deletes existing branch before pushing changes
      --from=<contentFrom>   The file to be uploaded to the repositories
  -g, --global               Do not constrain search to current organization
  -h, --help                 Show this help message and exit.
  -m, --message=<message>    The pull request message
      --message-from=<messageFrom>
                             The file containing the pull request message
  -p, --path=<path>          The path inside the repository
  -P, --no-page              Do not wait after each result
      --progress-column=<progressColumn>
                             The name of the 'In progress' column in the project
      --project=<project>    The name of the project (board)
  -s, --stacktrace           Print stack traces
      --summary-file=<summaryFile>
                             Markdown summary file path
  -t, --title=<title>        The pull request title
      --todo-column=<todoColumn>
                             The name of the 'To do' column in the project
      --token=<token>        The GitHub token
  -V, --version              Print version information and exit.
  -w, --workspace=<workspace>
                             The workspace directory

3.2.4. Delete Command

The delete command allows you to delete all files that match the given search query.

New pull request are created with a specified changes.

Examples
Delete All Travis CI Configuration File
pierrot delete \
  --branch=chore/remove-travis \
  --title="Remove Travis CI Config File" \
  --message="Travis CI is no longer used so we can delete the configuration files" \
  filename:.travis.yml

Travis CI was once popular continuous integration server but many projects has migrated to GitHub Actions instead.

Full Syntax
Usage: pierrot delete [-afghPsV] [-b=<branch>] [--done-column=<doneColumn>]
                      [-m=<message>] [--message-from=<messageFrom>]
                      [--progress-column=<progressColumn>]
                      [--project=<project>] [--summary-file=<summaryFile>]
                      [-t=<title>] [--todo-column=<todoColumn>]
                      [--token=<token>] [-w=<workspace>] QUERY...
creates PRs to delete files
      QUERY...              The search term such as 'org:agorapulse filename:
                              build.gradle'
  -a, --all                 Include archived and closed
  -b, --branch=<branch>     The pull request branch
      --done-column=<doneColumn>
                            The name of the 'Done' column in the project
  -f, --force               Deletes existing branch before pushing changes
  -g, --global              Do not constrain search to current organization
  -h, --help                Show this help message and exit.
  -m, --message=<message>   The pull request message
      --message-from=<messageFrom>
                            The file containing the pull request message
  -P, --no-page             Do not wait after each result
      --progress-column=<progressColumn>
                            The name of the 'In progress' column in the project
      --project=<project>   The name of the project (board)
  -s, --stacktrace          Print stack traces
      --summary-file=<summaryFile>
                            Markdown summary file path
  -t, --title=<title>       The pull request title
      --todo-column=<todoColumn>
                            The name of the 'To do' column in the project
      --token=<token>       The GitHub token
  -V, --version             Print version information and exit.
  -w, --workspace=<workspace>
                            The workspace directory

3.2.5. Pull Command

The pull command pulls the files from multiple repositories into a workspace. You can then make local changes and use push command to create new pull requests for changes.

The workspace layout is in a format organization/repository/files:

Workspace Layout Example
pierrot-workspace
└── myorg
    ├── repo1
    │   └── build.gradle
    └── repo2
        └── build.gradle

You can use --workspace-repositories-only flag to only search within the exisiting workspace repositories.

  -o, --workspace-repositories-only
                     Search only within the existing workspace repositories
Examples
Find All Usages of JCenter Repository within Gradle’s Build Files and Pull the Files Locally
pierrot pull extension:gradle jcenter

JCenter has been shut down so if you still have a references in the build files then you should remove them.

Full Syntax
Usage: pierrot pull [-aghoPsV] [--summary-file=<summaryFile>] [--token=<token>]
                    [-w=<workspace>] QUERY...
pulls the matching files locally
      QUERY...          The search term such as 'org:agorapulse filename:build.
                          gradle'
  -a, --all             Include archived and closed
  -g, --global          Do not constrain search to current organization
  -h, --help            Show this help message and exit.
  -o, --workspace-repositories-only
                        Search only within the existing workspace repositories
  -P, --no-page         Do not wait after each result
  -s, --stacktrace      Print stack traces
      --summary-file=<summaryFile>
                        Markdown summary file path
      --token=<token>   The GitHub token
  -V, --version         Print version information and exit.
  -w, --workspace=<workspace>
                        The workspace directory

3.2.6. Push Command

The push command creates new pull requests for changes performed in a local workspace.

The workspace layout is in a format organization/repository/files:

Workspace Layout Example
pierrot-workspace
└── myorg
    ├── repo1
    │   └── build.gradle
    └── repo2
        └── build.gradle
Examples
Push Local Changes to GitHub
pierrot push \
  --branch=chore/removed-jcenter \
  --title="Removed JCenter from the Gradle Files" \
  --message="JCenter has been shut down so we need to delete all references"

JCenter has been shut down so if you still have a references in the build files then you should remove them.

Full Syntax
Usage: pierrot push [-fhsV] [-b=<branch>] [--done-column=<doneColumn>]
                    [-m=<message>] [--message-from=<messageFrom>]
                    [--progress-column=<progressColumn>] [--project=<project>]
                    [--summary-file=<summaryFile>] [-t=<title>]
                    [--todo-column=<todoColumn>] [--token=<token>]
                    [-w=<workspace>]
pushes the the local changes and creates PRs
  -b, --branch=<branch>     The pull request branch
      --done-column=<doneColumn>
                            The name of the 'Done' column in the project
  -f, --force               Deletes existing branch before pushing changes
  -h, --help                Show this help message and exit.
  -m, --message=<message>   The pull request message
      --message-from=<messageFrom>
                            The file containing the pull request message
      --progress-column=<progressColumn>
                            The name of the 'In progress' column in the project
      --project=<project>   The name of the project (board)
  -s, --stacktrace          Print stack traces
      --summary-file=<summaryFile>
                            Markdown summary file path
  -t, --title=<title>       The pull request title
      --todo-column=<todoColumn>
                            The name of the 'To do' column in the project
      --token=<token>       The GitHub token
  -V, --version             Print version information and exit.
  -w, --workspace=<workspace>
                            The workspace directory

3.2.7. Replace Command

The replace command allows you to find and replace text in the all files that match the given search query.

You need to specify Java-style pattern with the --pattern parameter and the replacement with --replacement parameter.

New pull request are created with a specified changes.

  -p, --pattern=<pattern>   The Java-style regular expression pattern to
                              execute on the matched files
  -r, --replacement=<replacement>
                            The Java-style regular expression replacement
Examples
Update Micronaut Version
pierrot replace \
  --pattern='micronautVersion = (.*)' \
  --replacement='micronautVersion = 3.1.0' \
  --branch=chore/upgrade-micronaut \
  --title="Upgraded Micronaut to 3.1.0" \
  --message="Upgraded Micronaut to the latest version 3.1.0" \
  filename:gradle.properties micronautVersion

Versions declared in gradle.properties files are not well handled by the tools like Snyk or Dependabot.

Full Syntax
Usage: pierrot replace [-afghPsV] [-b=<branch>] [--done-column=<doneColumn>]
                       [-m=<message>] [--message-from=<messageFrom>]
                       -p=<pattern> [--progress-column=<progressColumn>]
                       [--project=<project>] -r=<replacement>
                       [--summary-file=<summaryFile>] [-t=<title>]
                       [--todo-column=<todoColumn>] [--token=<token>]
                       [-w=<workspace>] QUERY...
replaces content in the files and creates PRs
      QUERY...              The search term such as 'org:agorapulse filename:
                              build.gradle'
  -a, --all                 Include archived and closed
  -b, --branch=<branch>     The pull request branch
      --done-column=<doneColumn>
                            The name of the 'Done' column in the project
  -f, --force               Deletes existing branch before pushing changes
  -g, --global              Do not constrain search to current organization
  -h, --help                Show this help message and exit.
  -m, --message=<message>   The pull request message
      --message-from=<messageFrom>
                            The file containing the pull request message
  -p, --pattern=<pattern>   The Java-style regular expression pattern to
                              execute on the matched files
  -P, --no-page             Do not wait after each result
      --progress-column=<progressColumn>
                            The name of the 'In progress' column in the project
      --project=<project>   The name of the project (board)
  -r, --replacement=<replacement>
                            The Java-style regular expression replacement
  -s, --stacktrace          Print stack traces
      --summary-file=<summaryFile>
                            Markdown summary file path
  -t, --title=<title>       The pull request title
      --todo-column=<todoColumn>
                            The name of the 'To do' column in the project
      --token=<token>       The GitHub token
  -V, --version             Print version information and exit.
  -w, --workspace=<workspace>
                            The workspace directory

3.2.8. Status Command

The status command allows search pull requests and display their status. If the project name is defined using --project then the PRs are also added from the given project.

You can also batch-close the pull request that matches given search terms using --close or --delete flags. If the project name is defined using --project then the PRs are also removed from the given project.

  -c, --close               Close the pull requests
  -d, --delete              Also delete PR branches, implies --close
Examples
Display Update Micronaut Version Pull Requests and Assign Them to the Project
pierrot status \
  --all \
  --project='Micronaut Upgrade' \
  "Micronaut Upgrade 3.1.0"

Adding to the project will allow displaying all the running PRs in a status board.

Full Syntax
Usage: pierrot status [-acdghPsV] [--done-column=<doneColumn>]
                      [--progress-column=<progressColumn>]
                      [--project=<project>] [--summary-file=<summaryFile>]
                      [--todo-column=<todoColumn>] [--token=<token>] QUERY...
searches GitHub Pull Requests and prints their statuses
      QUERY...              The search term such as 'org:agorapulse filename:
                              build.gradle'
  -a, --all                 Include archived and closed
  -c, --close               Close the pull requests
  -d, --delete              Also delete PR branches, implies --close
      --done-column=<doneColumn>
                            The name of the 'Done' column in the project
  -g, --global              Do not constrain search to current organization
  -h, --help                Show this help message and exit.
  -P, --no-page             Do not wait after each result
      --progress-column=<progressColumn>
                            The name of the 'In progress' column in the project
      --project=<project>   The name of the project (board)
  -s, --stacktrace          Print stack traces
      --summary-file=<summaryFile>
                            Markdown summary file path
      --todo-column=<todoColumn>
                            The name of the 'To do' column in the project
      --token=<token>       The GitHub token
  -V, --version             Print version information and exit.