Giter Club home page Giter Club logo

git-xargs's Introduction

Go Report Card gruntwork-io Homebrew

Table of contents

Introduction

Overview

git-xargs CLI

git-xargs is a command-line tool (CLI) for making updates across multiple GitHub repositories with a single command. You give git-xargs:

  1. a script or a command to run
  2. a list of repos

and git-xargs will:

  1. clone each repo
  2. run your specified script or command against it
  3. commit any changes
  4. open pull requests
  5. provide a detailed report of everything that happened

Git-xargs leverages goroutines to perform the repo-updating work in parallel, so it is very fast.

For example, have you ever needed to add a particular file across many repos at once? Or to run a search and replace to change your company or product name across 150 repos with one command? What about upgrading Terraform modules to all use the latest syntax? How about adding a CI/CD configuration file, if it doesn't already exist, or modifying it in place if it does, but only on a subset of repositories you select? You can handle these use cases and many more with a single git-xargs command.

Example: writing a new file to every repo in your GitHub organization

As an example, let's use git-xargs to create a new file in every repo:

git-xargs \
  --branch-name test-branch \
  --github-org <your-github-org> \
  --commit-message "Create hello-world.txt" \
  touch hello-world.txt

Here's what it looks like in action:

git-xargs to the rescue!

In this example, every repo in your org will have a new file named hello-world.txt written to it with the contents "Hello, World!". You'll then receive an easy-to-read printout of exactly what happened on STDOUT:

*****************************************************************
  GIT-XARGS RUN SUMMARY @ 2021-04-12 23:05:18.478435534 +0000 UTC
  Runtime in seconds: 4
*****************************************************************


COMMAND SUPPLIED

[touch hello-world.txt]

 REPOS SUPPLIED VIA --repos FILE FLAG
│────────────────────────│────────────────────────│
│ ORGANIZATION NAME (5)  │ URL                    │
│────────────────────────│────────────────────────│
│ zack-test-org          │ terraform-aws-asg      │
│ zack-test-org          │ terraform-aws-vpc      │
│ zack-test-org          │ terraform-aws-security │
│ zack-test-org          │ terraform-aws-eks      │
│ zack-test-org          │ circleci-test-1        │
│────────────────────────│────────────────────────│

 ALL REPOS THAT WERE TARGETED FOR PROCESSING AFTER FILTERING MISSING / MALFORMED REPOS
│───────────────────│────────────────────────────────────────────────────│
│ REPO NAME         │ REPO URL                                           │
│───────────────────│────────────────────────────────────────────────────│
│ terraform-aws-vpc │ https://github.com/zack-test-org/terraform-aws-vpc │
│ terraform-aws-eks │ https://github.com/zack-test-org/terraform-aws-eks │
│ circleci-test-1   │ https://github.com/zack-test-org/circleci-test-1   │
│───────────────────│────────────────────────────────────────────────────│


 REPOS THAT WERE SUCCESSFULLY CLONED TO THE LOCAL FILESYSTEM
│───────────────────│────────────────────────────────────────────────────│
│ REPO NAME         │ REPO URL                                           │
│───────────────────│────────────────────────────────────────────────────│
│ terraform-aws-eks │ https://github.com/zack-test-org/terraform-aws-eks │
│ circleci-test-1   │ https://github.com/zack-test-org/circleci-test-1   │
│ terraform-aws-vpc │ https://github.com/zack-test-org/terraform-aws-vpc │
│───────────────────│────────────────────────────────────────────────────│


 REPOS THAT SHOWED FILE CHANGES TO THEIR WORKING DIRECTORY FOLLOWING COMMAND EXECUTION
│───────────────────│────────────────────────────────────────────────────│
│ REPO NAME         │ REPO URL                                           │
│───────────────────│────────────────────────────────────────────────────│
│ terraform-aws-eks │ https://github.com/zack-test-org/terraform-aws-eks │
│ terraform-aws-vpc │ https://github.com/zack-test-org/terraform-aws-vpc │
│ circleci-test-1   │ https://github.com/zack-test-org/circleci-test-1   │
│───────────────────│────────────────────────────────────────────────────│


 REPOS THAT WERE SUPPLIED BY USER BUT DON'T EXIST (404'D) VIA GITHUB API
│────────────────────────│──────────│
│ REPO NAME              │ REPO URL │
│────────────────────────│──────────│
│ terraform-aws-asg      │          │
│ terraform-aws-security │          │
│────────────────────────│──────────│


 REPOS WHOSE SPECIFIED BRANCHES DID NOT EXIST ON THE REMOTE, AND SO WERE FIRST CREATED LOCALLY
│───────────────────│────────────────────────────────────────────────────│
│ REPO NAME         │ REPO URL                                           │
│───────────────────│────────────────────────────────────────────────────│
│ terraform-aws-eks │ https://github.com/zack-test-org/terraform-aws-eks │
│ terraform-aws-vpc │ https://github.com/zack-test-org/terraform-aws-vpc │
│ circleci-test-1   │ https://github.com/zack-test-org/circleci-test-1   │
│───────────────────│────────────────────────────────────────────────────│


*****************************************************
  PULL REQUESTS OPENED
*****************************************************
│───────────────────│────────────────────────────────────────────────────────────│
│ REPO NAME         │ PR URL                                                     │
│───────────────────│────────────────────────────────────────────────────────────│
│ circleci-test-1   │ https://github.com/zack-test-org/circleci-test-1/pull/82   │
│ terraform-aws-eks │ https://github.com/zack-test-org/terraform-aws-eks/pull/81 │
│ terraform-aws-vpc │ https://github.com/zack-test-org/terraform-aws-vpc/pull/77 │
│───────────────────│────────────────────────────────────────────────────────────│

Getting started

Installation option 1: Homebrew

If you are Homebrew user, you can install by running

$ brew install git-xargs

Installation option 2: Installing published binaries

  1. Download the correct binary for your platform. Visit the releases page and download the correct binary depending on your system. Save it to somewhere on your PATH, such as /usr/local/bin/git-xargs.

  2. Set execute permissions. For example, on Linux or Mac, you'd run:

    chmod u+x /usr/local/bin/git-xargs
  3. Check it's working. Run the version command to ensure everything is working properly:

    git-xargs --version

Installation option 3: Run go install or go get

  1. Ensure you have Golang installed and working properly on your system. Follow the official Golang install guide to get started.

  2. Run go install to install the latest release of git-xargs:

    go install github.com/gruntwork-io/git-xargs@latest
  3. Alternatively, use go install to select a specific release of git-xargs:

    go install github.com/gruntwork-io/[email protected]
  4. If you have Go 1.16 or earlier, you can use get

    go get github.com/gruntwork-io/git-xargs
    go get github.com/gruntwork-io/[email protected]

Try it out!

  1. Export a valid GitHub token. See the guide on Github personal access tokens for information on how to generate one. For example, on Linux or Mac, you'd run:

    export GITHUB_OAUTH_TOKEN=<your-secret-github-oauth-token>
  2. Setup authentication with your Github Enterprise server. To use a Github Enterprise server, set the GITHUB_HOSTNAME environment variable:

    export GITHUB_HOSTNAME=<your-ghe-hostname.your-domain.com>
  3. Provide a script or command and target some repos. Here's a simple example of running the touch command in every repo in your GitHub organization. Follow the same pattern to start running your own scripts and commands against your own repos!

    git-xargs \
      --branch-name "test-branch" \
      --commit-message "Testing git-xargs" \
      --github-org <enter-your-github-org-name> \
      touch git-xargs-is-awesome.txt

Reference

How to supply commands or scripts to run

The API for git-xargs is:

git-xargs [-flags] <CMD>

Where CMD is either the full path to a (Bash, Python, Ruby, etc) script on your local system or a binary. Note that, because the tool supports Bash scripts, Ruby scripts, Python scripts, etc, you must include the full filename for any given script, including its file extension.

In other words, all the following usages are valid:

git-xargs --repo gruntwork-io/cloud-nuke \
   --repo gruntwork-io/terraform-aws-eks \
   --branch-name my-branch \
   /usr/local/bin/my-bash-script.sh
git-xargs --repos ./my-repos.txt \
  --branch-name my-other-branch \
  touch file1.txt file2.txt
git-xargs --github-org my-github-org \
  --branch-name my-new-branch \
  "$(pwd)/scripts/my-ruby-script.rb"

Using git-xargs environment variables in commands or scripts

When executing commands or scripts, git-xargs will register the following environment variables for use by commands or scripts based on the arguments and flags provided:

Env var Value
XARGS_DRY_RUN Whether the --dry-run flag was provided to git-xargs; options are true, false
XARGS_REPO_NAME Name of the target repository being processed
XARGS_REPO_OWNER Owner of the target repository being processed

Debugging runtime errors

By default, git-xargs will conceal runtime errors as they occur because its log level setting is INFO if not overridden by the --loglevel flag.

To see all errors your script or command may be generating, be sure to pass --loglevel DEBUG when running your git-xargs command, like so:

git-xargs --loglevel DEBUG \
	--repo zack-test-org/terraform-aws-eks \
	--branch-name master \
	--commit-message "add blank file" \
	--skip-pull-requests touch foo.txt

When the log level is set to debug you should see new error output similar to the following:

Total 195 (delta 159), reused 27 (delta 11), pack-reused 17  Repo=terraform-aws-eks
[git-xargs] DEBU[2021-06-29T12:11:31-04:00] Created branch                                Branc
h Name=refs/heads/master Repo=terraform-aws-eks
[git-xargs] DEBU[2021-06-29T12:11:31-04:00] Error creating new branch                     Error
="a branch named \"refs/heads/master\" already exists" Repo=terraform-aws-eks
[git-xargs] DEBU[2021-06-29T12:11:31-04:00] Error encountered while processing repo       Error
="a branch named \"refs/heads/master\" already exists" Repo name=terraform-aws-eks

Rate Limiting

git-xargs attempts to be a good citizen as regards consumption of the GitHub API. git-xargs conforms to GitHub's API integration guidelines.

In addition, git-xargs includes several features and flags to help you:

  1. run jobs without tripping GitHub's rate limits
  2. recover when rate limited by automatically retrying failed pull requests again, all while honoring the GitHub rate limits

Distinct processing channels for expensive and non-expensive work

git-xargs distinguishes between work that is safe to perform in parallel, such as certain git operations, and work that must be done with consideration of resource constraints, such as issuing open pull requests to GitHub's API. Therefore, git-xargs is able to perform all concurrency-safe work as quickly as possible by leveraging goroutines, while treating the more expensive open pull request API calls separately.

Pull requests are handled on a separate channel so that they can be buffered and retried in accordance with rate limiting feedback git-xargs is receiving from GitHub's API.

This means that git-xargs performs all the work upfront that it can as quickly as possible, and then moves on to serially process the pull request jobs that have resulted from the concurrency-safe work of cloning repositories, making file changes, checking the git worktree, etc.

Automatic pull request retries when rate limited

By default, git-xargs will re-attempt opening a pull request that failed due to rate limiting. The --max-pr-retries flag allows you to specify how many times you'd like a given pull request to be re-attempted in case of failure due to rate limiting. By default, the value is 3, meaning that if you do not pass this flag, git-xargs will retry all rate-limit-blocked pull requests 3 times.

Automatic backoff when rate limiting is detected

When git-xargs detects that it has been rate limited by GitHub, it begins requeuing failed pull requests for retry, but with an additional, larger buffer of time in between the next attempt. This larger buffer of time is intended to allow GitHub rate limit status to return to baseline for the git-xargs client. The --seconds-to-wait-when-ratelimited flag specifies the number of seconds to wait when git-xargs detects it has been rate limited. Note that this extra buffer of time is in addition to the value specified by the --seconds-between-prs flag.

When they are provided by GitHub, git-xargs will instead use the values of any Retry-After header, or the delta of seconds between the current time and the rate limit error's reset time. When these two values are not available, git-xargs falls back to the user-specified value of --seconds-to-wait-when-ratelimited, if the flag was passed, or the default value, which is 60 seconds.

Specifying the pause between pull requests

The GitHub's API integration guidelines specify that clients should pause at least 1 second in between consecutive requests against expensive endpoints, such as the one for opening a new pull request. As a result, git-xargs defaults to pausing 1 second in between each pull request that is opened. The flag --seconds-between-prs allows you to modify this value. For example, if you were to pass --seconds-between-prs 30, then git-xargs will sleep for half a minute between issuing pull request API calls to GitHub.

Guidelines and observations from testing

In local testing, the actual thresholds for when GitHub's secondary rate limits kick in can vary depending on the number of repos you're targeting and how long your script or command takes to complete. Secondary rate limits have been observed on jobs targeting as few as 10 repositories. If you are using the rate limiting flags with reasonable values, your job should never be rate-limited in the first place.

If your job is consistently being rate-limited, try incrementally increasing the value you pass with the --seconds-between-prs flag. Passing a higher value will increase the overall time your job takes to complete, but it will also greatly decrease the likelihood of your job tripping GitHub's rate limits at all. Passing a lower value, or not passing the flag at all, will greatly increase the likelihood that your job is rate limited by GitHub.

Branch behavior

Passing the --branch-name (-b) flag is required when running git-xargs. If you specify the name of a branch that exists on your remote, its latest changes will be pulled locally prior to your command or script being run. If you specify the name of a new branch that does not yet exist on your remote, it will be created locally and pushed once your changes are committed.

Default repository branch

Any pull requests opened will be opened against the repository's default branch (whether that's main, or master or something else). You can supply an additional --base-branch-name flag to change the target for your pull requests. Be aware that this will override the base branch name for ALL targeted repositories.

Git file staging behavior

Currently, git-xargs will find and add any and all new files, as well as any existing files that were modified, within your repo and stage them prior to committing. If your script or command creates a new file, it will be committed. If your script or command edits an existing file, that change will also be committed.

Paths and script locations

Scripts may be placed anywhere on your system, but you are responsible for providing absolute paths to your scripts when invoking git-xargs:

git-xargs \
  --branch-name upgrade-tf-14 \
  --commit-message "Update modules to Terraform 0.14" \
  --repos data/batch3.txt \
  $(pwd)/scripts/my-ruby-script.rb

or

git-xargs \
  --branch-name upgrade-tf-14 \
  --commit-message "Update modules to Terraform 0.14" \
  --repos data/batch3.txt \
  /usr/local/bin/my-ruby-script.rb

If you need to compose more complex behavior into a single pull request, write a wrapper script that executes all your commands, or place all your logic into one script.

How to target repos to run your scripts against

git-xargs supports four methods of targeting repos to run your selected scripts against. They are processed in the order listed below, with whichever option is found first being used, and all others after it being ignored.

Option #1: GitHub organization lookup

If you want the tool to find and select every repo in your GitHub organization, you can pass the name of your organization via the --github-org flag:

git-xargs \
  --commit-message "Update copyright year" \
  --github-org <your-github-org> \
  "$(pwd)/scripts/update-copyright-year.sh"

This will signal the tool to look up, and page through, every repository in your GitHub organization and execute the scripts you passed.

Option #2: Flat file of repository names

Oftentimes, you want finer-grained control over the exact repos you are going to run your script against. In this case, you can use the --repos flag and supply the path to a file defining the exact repos you want the tool to run your selected scripts against, like so:

git-xargs \
  --commit-message "Update copyright year" \
  --repos data/batch2.txt \
  "$(pwd)/scripts/update-copyright-year.sh"

In this example, batch2.txt looks like this:

gruntwork-io/infrastructure-as-code-training
gruntwork-io/infrastructure-live-acme
gruntwork-io/infrastructure-live-multi-account-acme
gruntwork-io/infrastructure-modules-acme
gruntwork-io/infrastructure-modules-multi-account-acme

Flat files contain one repo per line, each repository in the format of <github-organization>/<repo-name>. Commas, trailing or preceding spaces, and quotes are all filtered out at runtime. This is done in case you end up copying your repo list from a JSON list or CSV file.

Option #3: Pass in repos via command line args

Another way to get fine-grained control is to pass in the individual repos you want to use via one or more --repo arguments:

git-xargs \
  --commit-message "Update copyright year" \
  --repo gruntwork-io/terragrunt \
  --repo gruntwork-io/terratest \
  --repo gruntwork-io/cloud-nuke \
  "$(pwd)/scripts/update-copyright-year.sh"

Option #4: Pass in repos via stdin

And one more (Unix-philosophy friendly) way to get fine-grained control is to pass in the individual repos you want to use by piping them in via stdin, separating repo names with whitespace or newlines:

echo "gruntwork-io/terragrunt gruntwork-io/terratest" | git-xargs \
  --commit-message "Update copyright year" \
  "$(pwd)/scripts/update-copyright-year.sh"

Notable flags

git-xargs exposes several flags that allow you to customize its behavior to better suit your needs. For the latest info on flags, you should run git-xargs --help. However, a couple of the flags are worth explaining more in depth here:

Flag Description Type Required
--branch-name You must specify the name of the branch to make your local and remote changes on. You can further control branching behavior via --skip-pull-requests as explained below. String Yes
--loglevel Specify the log level of messages git-xargs should print to STDOUT at runtime. By default, this is INFO - so only INFO level messages will be visible. Pass DEBUG to see runtime errors encountered by your scripts or commands. Accepted levels are TRACE, DEBUG, INFO, WARNING, ERROR, FATAL and PANIC. Default: INFO. String No
--repos If you want to specify many repos and manage them in files (which makes batching and testing easier) then use this flag to pass the filepath to a repos file. See the repos file format for more information. String No
--repo Use this flag to specify a single repo, e.g., --repo gruntwork-io/cloud-nuke. Can be passed multiple times to target several repos. String No
--github-org If you want to target every repo in a Github org that your GITHUB_OAUTH_TOKEN has access to, pass the name of the Organization with this flag, to page through every repo via the Github API and target it. String No
--commit-message The commit message to use when creating commits. If you supply this flag, but neither the optional --pull-request-title or --pull-request-description flags, then the commit message value will be used for all three. Default: [skip ci] git-xargs programmatic commit. Note that, by default, git-xargs will prepend "[skip ci]" to commit messages unless you pass the --no-skip-ci flag. If you wish to use an alternative prefix other than [skip ci], you can add the literal string to your --commit-message value. String No
--skip-pull-requests If you don't want any pull requests opened, but would rather have your changes committed directly to your specified branch, pass this flag. Note that it won't work if your Github repo is configured with branch protections on the branch you're trying to commit directly to! Default: false. Boolean No
--skip-archived-repos If you want to exclude archived (read-only) repositories from the list of targeted repos, pass this flag. Default: false. Boolean No
--dry-run If you are in the process of testing out git-xargs or your initial set of targeted repos, but you don't want to make any changes via the Github API (pushing your local changes or opening pull requests) you can pass the dry-run flag. This is useful because the output report will still tell you which repos would have been affected, without actually making changes via the Github API to your remote repositories. Default: false. Boolean No
--draft Whether to open pull requests in draft mode. Draft pull requests are available for public GitHub repositories and private repositories in GitHub tiered accounts. See Draft Pull Requests for more details. Default: false. Boolean No
--seconds-between-prs The number of seconds to wait between opening serial pull requests. If you are being rate limited, continue to increase this value until rate limiting eases. Note, this value cannot be negative, so if you pass a value less than 1, the seconds to wait between pull requests will be set to 1 second. Default: 1 second. Integer No
--max-pr-retries The number of times to retry a pull request that failed due to rate limiting. Default: 3. Integer No
--seconds-to-wait-when-rate-limited The number of seconds to pause once git-xargs has detected it has been rate limited. Note that this buffer is in addition to the value of --seconds-between-prs. If you are regularly being rate limited, increase this value until rate limiting eases. Default: 60 seconds. Integer No
--no-skip-ci By default, git-xargs will prepend "[skip ci]" to its commit messages to prevent large git-xargs jobs from creating expensive CI jobs excessively. If you pass the --no-skip-ci flag, then git-xargs will not prepend "[skip ci]". Default: false, meaning that "[skip ci]" will be prepended to commit messages. Bool No
--reviewers An optional slice of GitHub usernames, separated by commas, to request reviews from after a pull request is successfully opened. Default: empty slice, meaning that no reviewers will be requested. String No
--team-reviewers An optional slice of GitHub team names, separated by commas, to request reviews from after a pull request is successfully opened. Default: empty slice, meaning that no team reviewers will be requested. IMPORTANT: Please read and understand the GitHub restrictions on this functionality before using it! Only certain GitHub organizations / payment plans support this functionality. String No
--keep-cloned-repositories By default, git-xargs will delete the repositories it clones to your temporary file directory once it has completed processing that repo, to save space on your machine. If you wish to retain the local repositories, pass this flag. Bool No

Best practices, tips and tricks

Write your script to run against a single repo

Write your script as if it's operating on a single repo, then target many repos with git-xargs. Remember that at runtime, each of the scripts you select will be run, in the order you specify, once per repo that you've targeted.

Handling prerequisites and third party binaries

It is currently assumed that bash script authors will be responsible for checking for prerequisites within their own scripts. If you are adding a new bash script to accomplish some new task across repos, consider using the Gruntwork bash-commons assert_is_installed pattern to ensure the operator has any required binaries installed.

Grouping your repos into separate batches

This is a pattern that ended up working out well for us as we wrote and executed more and more ambitious scripts across our many repos as a team: By breaking your target repos into separate batches, (batch1.txt, batch2.txt, batch3.txt) and starting with a few repos (or even one repo!) in the initial batches, and then gradually expanding the batches in size, you can easily test your new scripts against a few repos and double check the generated pull requests for any issues prior to widening your target batches.

How git-xargs works

This section provides a more in-depth look at how the git-xargs tool works under the hood.

  1. git-xargs will clone each of your selected repos to your machine to the /tmp/ directory of your local machine. The name of each repo, plus a random number each run, are concatenated together to form the local clone name to make the local repo easier to find in case you need to debug your script locally, e.g., terraform-aws-module-security3978298.
  2. it will checkout a local branch (whose name you must specify with the --branch-name flag)
  3. it will run all your selected scripts against your selected repos
  4. it will commit any changes in each of the repos (with a commit message you can optionally specify via the --commit-message flag)
  5. it will push your local branch with your new commits to your repo's remote
  6. it will call the GitHub API to open a pull request with a title and description that you can optionally specify via the --pull-request-title and --pull-request-description flags, respectively, unless you pass the --skip-pull-requests flag
  7. it will print out a detailed run summary to STDOUT that explains exactly what happened with each repo and provide links to successfully opened pull requests that you can quickly follow from your terminal. If any repos encountered errors at runtime (whether they weren't able to be cloned, or script errors were encountered during processing, etc) all of this will be spelled out in detail in the final report, so you know exactly what succeeded and what went wrong.

Tasks this tool is well-suited for

The following is a non-exhaustive list of potential use cases for git-xargs:

  • Add a LICENSE file to all of your GitHub repos, interpolating the correct year and company name into the file
  • For every existing LICENSE file across all your repos, update their copyright date to the current year
  • Update the CI build configuration in all of your repos by modifying the .circleci/config.yml file in each repo using a tool such as yq
  • Run sed commands to update or replace information across README files
  • Add new files to repos
  • Delete specific files, when present, from repos
  • Modify package.json files in-place across repos to bump a node.js dependency using jq https://stedolan.github.io/jq/
  • Update your Terraform module library from Terraform 0.13 to 0.14.
  • Remove stray files of any kind, when found, across repos using find and its exec option
  • Add baseline tests to repos that are missing them by copying over a common local folder where they are defined
  • Refactor multiple Golang tools to use new libraries by executing go get to install and uninstall packages, and modify the source code files' import references

If you can instrument the logic in a script, you can use git-xargs to run it across your repos!

Contributing

Contributing scripts to this project

We hope that this tool will help save you some time as you apply it to your own automations and maintenance tasks. We also welcome the community to contribute back scripts that everyone can use and benefit from.

Initially, we'll add these scripts to the ./scripts directory in this repository and will eventually organize them into sub-folders depending on their purposes / use cases. If you would like to have your script considered for inclusion in this repo, please first ensure that it is:

  • High quality: meaning free of typos, any obvious bugs or security issues
  • Generic: meaning that it is likely to be of general use to many different people and organizations, and free of any proprietary tooling or secrets

Once you've done this, please feel free to open a pull request adding your script to the ./scripts directory for consideration.

Thanks for contributing back! Our hope is that eventually this repo will contain many useful generic scripts for common maintenance and upgrading tasks that everyone can leverage to save time.

Building the binary from source

Clone this repository and then run the following command from the root of the repository:

go build

The git-xargs binary will be present in the repository root.

Running the tool without building the binary

Alternatively, you can run the tool directly without building the binary, like so:

./go run main.go \
  --branch-name test-branch \
  --commit-message "Add MIT License" \
  --repos data/test-repos.txt \
  $(pwd)/scripts/add-license.sh

This is especially helpful if you are developing against the tool and want to quickly verify your changes.

Running tests

Tests are included within their respective packages.

go test -v ./...

License

This code is released under the Apache 2.0 License. See LICENSE.txt

git-xargs's People

Contributors

andyfeller avatar briandfoy avatar brikis98 avatar chenrui333 avatar denis256 avatar eak12913 avatar infraredgirl avatar james03160927 avatar jdimatteo avatar jphuynh avatar kennyg avatar marinalimeira avatar nirnanaaa avatar rhoboat avatar robmorgan avatar ryanwholey avatar sc250024 avatar zackproser avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

git-xargs's Issues

Unknown escape sequence (and XX more errors)

Describe the bug

Executing the touch command (as in the example) on any of my git repositories results in an error "208:22: unknown escape sequence (and 29 more errors)".

To Reproduce

My command:

git-xargs --loglevel debug  --repo hsf-training/organization --branch-name "test-branch"   --commit-message "Testing git-xargs"  touch "test123.test"   

The output is:

[git-xargs] INFO[2022-07-13T17:44:09-04:00] git-xargs running...
[git-xargs] DEBU[2022-07-13T17:44:09-04:00] Looking up filename provided repo             Name=organization Organization=hsf-training
[git-xargs] DEBU[2022-07-13T17:44:09-04:00] Successfully fetched repo                     Name=organization Organization=hsf-training
[git-xargs] DEBU[2022-07-13T17:44:09-04:00] Repo will have all targeted scripts run against it  Repository=organization
[git-xargs] DEBU[2022-07-13T17:44:09-04:00] Attempting to clone repository using GITHUB_OAUTH_TOKEN  Repo=organization
[git-xargs] DEBU[2022-07-13T17:44:10-04:00] Enumerating objects: 6, done.
Counting objects: 100% (6/6), done.
Compressing objects: 100% (4/4), done.
Total 6 (delta 1), reused 0 (delta 0), pack-reused 0  Repo=organization
[git-xargs] DEBU[2022-07-13T17:44:10-04:00] Created branch                                Branch Name=refs/heads/test-branch Repo=organization
[git-xargs] DEBU[2022-07-13T17:44:10-04:00]                                               Repo=organization
[git-xargs] DEBU[2022-07-13T17:44:10-04:00] Executing command against local clone of repo...  Command="[touch test123.test]" Directory=/var/folders/g3/1y2_hl1j16scls01cxqm76s80000gn/T/git-xargs-organization653630454 Repo=organization
[git-xargs] DEBU[2022-07-13T17:44:10-04:00] Output of command [touch test123.test] for repo organization in directory /var/folders/g3/1y2_hl1j16scls01cxqm76s80000gn/T/git-xargs-organization653630454:
[git-xargs] DEBU[2022-07-13T17:44:10-04:00] Local repository worktree no longer clean, will stage and add new files and commit changes  Repo=organization
[git-xargs] DEBU[2022-07-13T17:44:10-04:00] Found untracked file. Adding to stage         Filepath=test123.test
[git-xargs] DEBU[2022-07-13T17:44:10-04:00] Error encountered while processing repo       Error="208:22: unknown escape sequence (and 29 more errors)" Repo name=organization


*****************************************************************
  GIT-XARGS RUN SUMMARY @ 2022-07-13 21:44:10.167923 +0000 UTC
  Runtime in seconds: 0
*****************************************************************


COMMAND SUPPLIED

[touch test123.test]

REPO SELECTION METHOD USED FOR THIS RUN - (see README.md for more information)

and this happens for me for all repositories that I have tried.

Versions:

  • git-xargs 0.0.16

Ability to read repository information per repository

Describe the solution you'd like
I would like to create a Backstage catalog-info.yaml file for each repository in an organization. This file needs to be unique for each repository. I would be helpful to be able to read name, description, owner.login, nameWithOwner for each repository while generating this file.

Describe alternatives you've considered
I'm not really sure what information is available while executing the script.

Additional context
Thank you

Move main binary into cmd/git-xargs

Would you accept a PR to move cmd/* into cmd/git-xargs/* ? This way a simple go get .../cmd/git-xargs is all that is needed (once #14 is merged) to get the git-xargs binary.

git-xargs: consider more unix-y approach, decomposing into pipelines

Jim's thinking:

"Should this tool do more to be "unix philosophy friendly"? E.g., Normally, you pipe things into the real xargs. Does that make sense to do here?

I'm just thinking out loud if there is some pattern like:

git-xargs list-repos gruntwork-io | xargs <SOME SCRIPT TO RUN IN EACH REPO> | git-xargs open-prs

In the Unix Philosophy spirit of “do one thing and do it well” and handling output via stdin/stdout, would it make sense to have:
A CLI tool called something like multi-git which can perform Git operations on multiple repos.
You run multi-git clone-to-temp and give it a GitHub org or list of repos to clone. It clones them to temp folders and writes the folder paths to stdout.
Pipe the output from multi-git into plain old xargs to execute some script in each of those folders.
Pipe the output from that—actually, I’m not sure what xargs produces as stdout, but let’s assume it’s the same list of temp folder paths—to multi-git commit-and-pr-if-necessary.

Advantages:
clone-to-temp and commit-and-pr-if-necessary might be useful in and of themselves in a variety of contexts.
More Unix-like approach to solving this problem.
Drawbacks:
Much harder to get started with this
Prob doesn’t work on Windows
Prob harder to handle certain corner cases

git-xargs should open PRs even if it did not commit any changes

I think, git-xargs should always open PRs even if the given command did not change anything locally or if the push returns already up-to-date.
The reason why I use your great tool, is that I want to merge some changes in to my main-branch. I don't care if the tool does these changes, commit them and push them to the branch I passed to the tool, or if these changes already exists in the remote branch, as long as a PR is opened so I can merge my changes into main.

git-xargs: accept repo names via stdin

Follow-up from #146

Per Jim's recommendation:

stdin: alternatively, git-xargs can read the list of repos, one per line, from stdin. This is similar to xargs itself.

I was thinking more along the lines of git-xargs getting the list of repos (but not the command to run) via either --repo / --repos flags:

git-xargs --repo gruntwork-io/foo --repo gruntwork-io/bar touch license.txt

Or via stdin:

echo -e "gruntwork-io/foo\ngruntwork-io/bar" | git-xargs touch license.txt

[FEATURE REQUEST] Gitlab API integration

Is there an interest for having this as a gitlab integration as well?

Formulated differently, is there a need and/or interest for a PR extending the functionality to gitlab (on premise or SaaS). I might be able to scramble something together regarding knowledge of the API but I'm not very well versed in Go atm.

git-xargs not respecting .gitignore

git-xargs version
What does git-xargs --version show?

git-xargs version v0.0.11

Describe the bug
git-xargs is not respecting .gitignore

To Reproduce
Steps to reproduce the behavior:

#!/usr/bin/env bash

git-xargs \
    --commit-message "Update Yarn Berry to latest canary" \
    --repos ../repos.txt \
    --branch-name chore/update-yarn-berry-canary \
    --loglevel debug \
    "$(pwd)/update-yarn-berry-canary.sh"
#!/usr/bin/env bash

# update-yarn-berry-canary.sh

yarn set version canary
yarn

That results in files being added to node_modules when, in my .gitignore in those projects, I have node_modules/ listed.

Expected behavior

Respect the .gitignore (in this case, node_modules/)

Screenshots
If applicable, add screenshots to help explain your problem.

image

Additional context
Add any other context about the problem here.

The name of the Pull Request have the description when it's provided

Describe the bug

When using the git-xargs with a very big commit message, that includes \n characters (to create the description) the name the PR seems to ignore the \n.

I think the title should be only the name of the commit, and the description should be out of the title.

To Reproduce

Run the command of git-xargs with a very big commit message, that includes \n.

git-xargs --skip-archived-repos --loglevel DEBUG --dry-run --repo=foo/bar --branch-name \"branch/change_x_y_z\" --commit-message "Add x y z\n**X:** is to allow this\n **Y:** is to allow that\n **Z:** idk\n> OK this comment shouldn't appear in the PR name" python main.py

Expected behavior

The title of the PR for the command above should be: "Add x y z"

Nice to have

Screen Shot 2021-12-08 at 16 19 43

Screen Shot 2021-12-08 at 16 20 57

No PR opened, if branch is up to date

Hello,

found something which is probably a bug or at least unexpected behavior.

If, for some reason the changes I made with git-xargs exists already in the branch on github, the tool prints the following errors and does not open a PR.

[git-xargs] DEBU[2021-04-27T08:45:41+02:00] Error pushing new branch to remote origin     Error="already up-to-date" Repo=room-management-example
[git-xargs] DEBU[2021-04-27T08:45:41+02:00] Error encountered while processing repo       Error="already up-to-date" Repo name=room-management-example

I run into this error, because I run my git-xargs command two times. The first time I run into an error on opening the PR. After fixing this, I run the command a second time and failed on the update. I had to delete the remote branch first.
I think it the tool should not break on an "already up-to-date" message, because the state of the repository is like it should be, only the way to achived was different.

Think this is an edge case and nothing urgent.

Feature Request: Consider moving git clone progress from stdout to logger

Is your feature request related to a problem? Please describe.

I run git-xargs on a list of 500+ repositories and also from Github Actions. Running it on that scale logs a lot of information when cloning repositories.

For example:

Compressing objects: 100% (39/39)
Compressing objects: 100% (39/39), done.
Total 59 (delta 21), reused 35 (delta 12), pack-reused 0
Enumerating objects: 20, done.
Counting objects: 20% (1/5)
Counting objects: 40% (2/5)
Counting objects: 60% (3/5)
Counting objects: 80% (4/5)
Counting objects: 100% (5/5)
Counting objects: 100% (5/5), done.
Compressing objects: 33% (1/3)
Compressing objects: 66% (2/3)
Compressing objects: 100% (3/3)
Compressing objects: 100% (3/3), done.
Total 20 (delta 0), reused 0 (delta 0), pack-reused 15
Enumerating objects: 835, done.
Counting objects: 0% (1/111)
Counting objects: 1% (2/111)
Counting objects: 2% (3/111)
Counting objects: 3% (4/111)

Describe the solution you'd like

Would it be possible to move that information to a debug log for example or add a --quiet option? (I think the former solution is preferable because --quiet would have a much bigger scope for the tool in general.)

Describe alternatives you've considered

Send progress to the logger instead of stdout

Progress: os.Stdout,

Additional context
N/A

Respect GitHub Secondary Rate Limits

Is your feature request related to a problem? Please describe.
GitHub's secondary rate limits prevent the creation of many resources in a short time frame. For example, creating PRs is capped in a period and GitHub's limits kick in. git-xargs will report an error and failure to create a PR when this happens with a HTTP 503 error.

git-xargs should respect the rate-limiting headers that GitHub returns and pause/sleep for that amount of time before continuing. The secondary rate limiting prevents the use of git-xargs against large amounts of repos (dozens to hundreds) because of these limits. The update scripts need to add a long pause that kills any performance (i.e. 30s) and concurrency when dealing with many repos.

https://docs.github.com/en/rest/guides/best-practices-for-integrators#dealing-with-secondary-rate-limits

Describe the solution you'd like
It would be great if git-xargs respected the GitHub X-RateLimit-* headers and automatically slept for that duration before continuing with the API requests.

https://docs.github.com/en/rest/overview/resources-in-the-rest-api#secondary-rate-limits

Describe alternatives you've considered
The workaround is to put a fixed pause in the update script, up to 30s to avoid being throttled and having the batch job fail.

Additional context

Feature request: auto-create new branch if no --branch-name flag is supplied

Describe the solution you'd like
Add functionality to create a new random branch name if one was not provided via the --branch-name command. This could make it easier to use git-xargs because many new users get tripped up on needing to iterate against new branch names when testing out their jobs.

The branch name generation could use a UUID-like string algorithm to avoid collisions with existing branch names.

Using `--github-org` only returns 25 repositories

Last time I used git-xargs was in May of this year, with the v0.0.14. And everything was fine.
I recently upgraded all my brew packages and nothing seems to works with the v0.0.16.

Describe the bug

When using --github-org to scan my company's org, git-xargs resolves only 25 of the few hundreds we have.

$ git-xargs --version
git-xargs version v0.0.16

$ git-xargs --loglevel DEBUG \
            --pull-request-title "Some title" \
            --commit-message "Doing things" \
            --branch-name "fix/my-things" \
            --max-concurrent-repos 1 \
            --github-org <ORG> --skip-archived-repos --dry-run touch helloworld.txt

[git-xargs] INFO[2022-07-20T16:56:14+02:00] git-xargs running...                         
[git-xargs] INFO[2022-07-20T16:56:14+02:00] Dry run setting enabled. No local branches will be pushed and no PRs will be opened in Github 
[git-xargs] DEBU[2022-07-20T16:56:15+02:00] Skipping archived repository                  Name=<ORG>/***
[git-xargs] DEBU[2022-07-20T16:56:15+02:00] Skipping archived repository                  Name=<ORG>/***
[git-xargs] DEBU[2022-07-20T16:56:15+02:00] Skipping archived repository                  Name=<ORG>/***
[git-xargs] DEBU[2022-07-20T16:56:15+02:00] Fetched repos from Github organization: <ORG>  Repo count=25
[git-xargs] DEBU[2022-07-20T16:56:15+02:00] Using Github org: <ORG> as source of repositories. Paging through Github API for repos. 
[...]
*****************************************************************
  GIT-XARGS RUN SUMMARY @ 2022-07-20 15:07:32.722381 +0000 UTC
  Runtime in seconds: 51
*****************************************************************


COMMAND SUPPLIED

[touch helloworld.txt]

REPO SELECTION METHOD USED FOR THIS RUN - (see README.md for more information)

github-org

 REPOS SUCCESSFULLY FETCHED VIA GITHUB API
| REPO NAME (22)          | REPO URL                                          |
|-------------------------|---------------------------------------------------|

To Reproduce

  • Generate Personal Token
    • With repo:*, read:org, write:org, and read:project
  • Execute git-xargs with the --github-org flag

Expected behavior

For git-xargs to actually follow up on the API pagination.

Nice to have

  • Terminal output
  • Screenshots

Additional context

Edit: ℹ️ This one was coming from an improper permission set on the token
I also tried supplying a list via --repos but every call ends up in a 404.

$ cat repos.txt | wc -l
      81
$ git-xargs --loglevel DEBUG \
            --pull-request-title "Some title" \
            --commit-message "Doing things" \
            --branch-name "fix/my-things" \
            --max-concurrent-repos 1 \
            --repos repos.txt --skip-archived-repos --dry-run touch helloworld.txt
[git-xargs] INFO[2022-07-20T17:17:02+02:00] git-xargs running...                         
[git-xargs] INFO[2022-07-20T17:17:02+02:00] Dry run setting enabled. No local branches will be pushed and no PRs will be opened in Github 
[...]
[git-xargs] DEBU[2022-07-20T17:17:02+02:00] Looking up filename provided repo             Name=documents Organization=<ORG>
[git-xargs] DEBU[2022-07-20T17:17:04+02:00] error getting single repo                     AllowedRepoName=documents AllowedRepoOwner=PayFit Error="GET https://api.github.com/repos/<ORG>/documents: 404 Not Found []" Response Status Code=404
[...]


$ gh repo view <ORG>/documents 
<ORG>/documents

[SHOWS THE README]

If both --github-org and --repo are specified, git-xargs is still cloning all the repos in the org

git-xargs version
v0.0.11

Describe the bug
If both --github-org and --repo are specified, git-xargs is still cloning all the repos in the org.

To Reproduce

$ git-xargs --branch-name=test-branch --github-org=git-xargs-test  --repo=test-repo-4  touch git-xargs-is-awesome.txt
[git-xargs] INFO[2021-09-21T15:43:26+02:00] git-xargs running...
[git-xargs] INFO[2021-09-21T15:43:27+02:00] Repository successfully processed             Repo name=test-repo-3
[git-xargs] INFO[2021-09-21T15:43:27+02:00] Repository successfully processed             Repo name=test-repo-2
[git-xargs] INFO[2021-09-21T15:43:27+02:00] Repository successfully processed             Repo name=test-repo-1


*****************************************************************
  GIT-XARGS RUN SUMMARY @ 2021-09-21 13:43:27.755367 +0000 UTC
  Runtime in seconds: 1
*****************************************************************


COMMAND SUPPLIED

[touch git-xargs-is-awesome.txt]


 REPOS SUCCESSFULLY FETCHED VIA GITHUB API
│────────────────│───────────────────────────────────────────────│
│ REPO NAME (4)  │ REPO URL                                      │
│────────────────│───────────────────────────────────────────────│
│ test-repo-1    │ https://github.com/git-xargs-test/test-repo-1 │
│ test-repo-2    │ https://github.com/git-xargs-test/test-repo-2 │
│ test-repo-3    │ https://github.com/git-xargs-test/test-repo-3 │
│ test-repo-4    │ https://github.com/git-xargs-test/test-repo-4 │
│────────────────│───────────────────────────────────────────────│


 ALL REPOS THAT WERE TARGETED FOR PROCESSING AFTER FILTERING MISSING / MALFORMED REPOS
│────────────────│───────────────────────────────────────────────│
│ REPO NAME (4)  │ REPO URL                                      │
│────────────────│───────────────────────────────────────────────│
│ test-repo-1    │ https://github.com/git-xargs-test/test-repo-1 │
│ test-repo-2    │ https://github.com/git-xargs-test/test-repo-2 │
│ test-repo-3    │ https://github.com/git-xargs-test/test-repo-3 │
│ test-repo-4    │ https://github.com/git-xargs-test/test-repo-4 │
│────────────────│───────────────────────────────────────────────│


 REPOS THAT WERE SUCCESSFULLY CLONED TO THE LOCAL FILESYSTEM
│─────────────│───────────────────────────────────────────────│
│ REPO NAME   │ REPO URL                                      │
│─────────────│───────────────────────────────────────────────│
│ test-repo-3 │ https://github.com/git-xargs-test/test-repo-3 │
│ test-repo-2 │ https://github.com/git-xargs-test/test-repo-2 │
│ test-repo-1 │ https://github.com/git-xargs-test/test-repo-1 │
│─────────────│───────────────────────────────────────────────│


 REPOS THAT WERE UNABLE TO BE CLONED TO THE LOCAL FILESYSTEM
│─────────────│───────────────────────────────────────────────│
│ REPO NAME   │ REPO URL                                      │
│─────────────│───────────────────────────────────────────────│
│ test-repo-4 │ https://github.com/git-xargs-test/test-repo-4 │
│─────────────│───────────────────────────────────────────────│


 REPOS THAT SHOWED NO FILE CHANGES TO THEIR WORKING DIRECTORY FOLLOWING COMMAND EXECUTION
│─────────────│───────────────────────────────────────────────│
│ REPO NAME   │ REPO URL                                      │
│─────────────│───────────────────────────────────────────────│
│ test-repo-3 │ https://github.com/git-xargs-test/test-repo-3 │
│ test-repo-2 │ https://github.com/git-xargs-test/test-repo-2 │
│ test-repo-1 │ https://github.com/git-xargs-test/test-repo-1 │
│─────────────│───────────────────────────────────────────────│

Expected behavior
Only repos supplied with the --repo flag get cloned/processed, even if the --github-org flag is used as well.

Template support for Pull Request Description and Title

Describe the solution you'd like
When specifying the --pull-request-title and --pull-request-description it isn't clear to me that you can do anything other than copy or paste in a string of your choosing. It would be useful to allow a file to be specified, and beyond that, a template that can be given with prompts and/or options to enter variables to fill in the template for it.

Describe alternatives you've considered
I have a script to generate the git-xargs command runs, but it lacks some of the features that a multi-line description would offer, as well as just making it hard to parse the command.

Additional context

Does git-xargs support only 10 PRs?

Describe the bug
Using git-xargs with 10+ repositories, I end up with only 10 PRs (consistently between runs, I tried running the command multiple times)

To Reproduce
Steps to reproduce the behavior including the relevant Terraform/Terragrunt/Packer version number and any code snippets and module inputs you used.
Running the git-xargs command with default settings produces only 10 PRs.
For example I ran the following:

git-xargs \
  --repos $PWD/tools/git-xargs/dbt_v1/repos \
  --branch-name branch-name-here \
  --loglevel DEBUG \
  --commit-message "My Commit Message" \
  --pull-request-description "DESCRIPTION HERE" \
  --draft \
  --dry-run \
  -- $PWD/tools/git-xargs/dbt_v1/script.sh

The output looks like this:

REPOS AGAINST WHICH PULL REQUESTS FAILED TO BE OPENED
│──────────────────────────────│────────────────────────────────────────────────────────────│
│ REPO NAME │ REPO URL │
│──────────────────────────────│────────────────────────────────────────────────────────────│
│ my-11th-repo │ my-11th-repo-url │
│──────────────────────────────│────────────────────────────────────────────────────────────│

REPOS WHOSE SPECIFIED BRANCHES DID NOT EXIST ON THE REMOTE, AND SO WERE FIRST CREATED LOCALLY
│──────────────────────────────────────│────────────────────────────────────────────────────────────────────│
│ REPO NAME (11) │ REPO URL │
│──────────────────────────────────────│────────────────────────────────────────────────────────────────────│
...I omitted content here...
│──────────────────────────────────────│────────────────────────────────────────────────────────────────────│


PULL REQUESTS OPENED


│──────────────────────────────────────│────────────────────────────────────────────────────────────────────────────│
│ REPO NAME (10) │ PR URL │
│──────────────────────────────────────│────────────────────────────────────────────────────────────────────────────│
...I omitted content here...
│──────────────────────────────────────│────────────────────────────────────────────────────────────────────────────│

// paste code snippets here

Expected behavior
I'm expecting 10+ PRs to be created, however only 10 were created. I can see that on the 11th repository a branch was created with the right content, however no PR.

Can it be related to the tool itself or a policy I have in my organization?

Nice to have

  • Terminal output
  • Screenshots

Additional context
Add any other context about the problem here.

THANKS!!!
Eyal

Refactor GitHub error messages used to determine status into constants

In some places, git-xargs is forced to fall back to reading the error message value from GitHub's API responses, since the GitHub API can be inconsistent in what headers, status codes, etc it actually returns under various conditions.

Per this comment we should refactor all such instances, of error messages that we're keying off to determine some runtime status, into a new constants.go file so that they will be Easier to Change in the future.

Prepend [skip ci] to commit messages by default

Describe the solution you'd like
To prevent large git-xargs jobs from generating excessive and potentially expensive continuous integration (CI) jobs, we should prepend [skip ci] to every commit message. We should also provide a new flag --no-skip-ci that allows users to opt-out of this behavior for the given run.

Question: Can the target branch be specified for the generated PRs?

git-xargs seems to be exactly what I need to use. I've been testing it to update files and automatically generate pull requests.

What I have seen is that the pull requests generated are always between the branch specified with "--branch-name" and "master".

Is it possible to specify that target branch to be different to "master"? Or a way to specify that the target should be the default branch (which is not always "master" on some of our repos).

Thanks.

Shell expansion

From Jim:

feature request that will most likely come up in the future is support for shell expansion. That is, given a command foo, the actual command you'd run here is something like bash -c "foo" (on *nix, at least). And then, of course, users will want to be able to configure the shell, and so on... Not worth tackling now. Perhaps just file a bug and come back to it.

Possible error when running repeated attempts on single repo

The PR was opened successfully: https://github.com/gruntwork-io/terraform-aws-ci/pull/448, but this error was still thrown. Also the report didn't get generated correctly.

git-xargs \
--loglevel debug \
--repo gruntwork-io/terraform-aws-ci \
--branch-name update-pr-template9 \
--seconds-between-prs 3 \
~/Development/repos/prototypes/git-xargs-assets/scripts/pull-request-template.sh
[git-xargs] INFO[2022-05-25T10:40:03-07:00] git-xargs running...
[git-xargs] DEBU[2022-05-25T10:40:03-07:00] Looking up filename provided repo             Name=terraform-aws-ci Organization=gruntwork-io
[git-xargs] DEBU[2022-05-25T10:40:03-07:00] Successfully fetched repo                     Name=terraform-aws-ci Organization=gruntwork-io
[git-xargs] DEBU[2022-05-25T10:40:03-07:00] Repo will have all targeted scripts run against it  Repository=terraform-aws-ci
[git-xargs] DEBU[2022-05-25T10:40:03-07:00] Attempting to clone repository using GITHUB_OAUTH_TOKEN  Repo=terraform-aws-ci
[git-xargs] DEBU[2022-05-25T10:40:05-07:00] Enumerating objects: 10181, done.
Counting objects: 100% (231/231), done.
Compressing objects: 100% (136/136), done.
Total 10181 (delta 105), reused 199 (delta 89), pack-reused 9950  Repo=terraform-aws-ci
[git-xargs] DEBU[2022-05-25T10:40:05-07:00] Created branch                                Branch Name=refs/heads/update-pr-template9 Repo=terraform-aws-ci
[git-xargs] DEBU[2022-05-25T10:40:05-07:00]                                               Repo=terraform-aws-ci
[git-xargs] DEBU[2022-05-25T10:40:05-07:00] Executing command against local clone of repo...  Command="[/Users/rhozen/Development/repos/prototypes/git-xargs-assets/scripts/pull-request-template.sh]" Directory=/var/folders/l0/nr3fgm0j39zchyhxy4gpsyz80000gn/T/git-xargs-terraform-aws-ci385613384 Repo=terraform-aws-ci
[git-xargs] DEBU[2022-05-25T10:40:05-07:00] Output of command [/Users/rhozen/Development/repos/prototypes/git-xargs-assets/scripts/pull-request-template.sh] for repo terraform-aws-ci in directory /var/folders/l0/nr3fgm0j39zchyhxy4gpsyz80000gn/T/git-xargs-terraform-aws-ci385613384:
[git-xargs] DEBU[2022-05-25T10:40:05-07:00] Local repository worktree no longer clean, will stage and add new files and commit changes  Repo=terraform-aws-ci
[git-xargs] DEBU[2022-05-25T10:40:06-07:00] Successfully pushed local branch to remote origin  Repo=terraform-aws-ci
[git-xargs] INFO[2022-05-25T10:40:06-07:00] Repository successfully processed             Repo name=terraform-aws-ci
ERROR: sync: WaitGroup is reused before previous Wait has returned

Command that was run:

#!/usr/bin/env bash 

set -e

readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

cp -r "$SCRIPT_DIR/../data/github-templates/pr-template.md" "./.github/pull_request_template.md"

Add option to create new PRs in draft mode

It would be great to have an option that make git-xargs open the PRs in draft mode. Sadly the GitHub Rest-API does not provide a resource to change the draft-state after creating a PR, so the only possibility is to do this at creation time.

Repos fail to commit with error "author field is required" when using git config includes for [user] section

git-xargs version
git-xargs version v0.0.11

Describe the bug

Logs here. When running git-xargs, I get the error "author field is required" during the commit step. This seems to be true of any repo I try with git-xargs.

It looks related to my git config includes. I use a different email addresses for git at work and use includes to specify my user.name and user.email on different machines. My ~/.gitconfig contains:

# ~/.gitconfig

[include]
    path = ~/.gitconfig.local

# no [user] section exists

and

# ~/.gitconfig.local
[user]
    name = ...
    email = ...

I've never had any issue with this before, but notice this in the git-config man pages. It implies that git-config might not honor includes in some cases and that you might have to include an explicit option.

       --[no-]includes
           Respect include.*  directives in config files when looking up values.
           Defaults to off when a specific file is given (e.g., using --file,
           --global, etc) and on when searching all config files.

Just to make sure the includes are read properly by git:

$ git config --get user.name
Aaron D Borden
$ git config --global --get user.name
# exit 1
$ git config --global --includes --get user.name
Aaron D Borden

To Reproduce
Steps to reproduce the behavior:

  1. Move your user.name and user.email from your ~/.gitconfig, to ~/.gitconfig.local
  2. Add an [includes] section as above in ~/.gitconfig to include ~/.gitconfig.local
  3. I'm using a script to generate templates for git-xargs, it looks similar to this:
git-xargs \
  --branch-name tts-bot/update-templates \
  --loglevel "${LOGLEVEL}" \
  --repos "${template_dir}/repo_list" \
  --skip-archived-repos \
  --pull-request-title "${pull_request_title}" \
  --pull-request-description "$(template pull_request_description)" \
  --commit-message "$(template commit_message)" \
  $(pwd)/bin/ci_update_templates.sh "${canonical_repository}" "${template_dir}/template_files"

repos file contains the single repo 18F/ghad.

Expected behavior
git-xargs respects the git config include and attributes the author correctly AND git-xargs warns when it cannot identify the author for the commit.

Screenshots
Logs https://gist.github.com/adborden/f0000d75107e1971940d48b58bc710be

Additional context
To work-around, I confirmed that you can set the user.name and user.email in the main config and git-xargs works as expected.

PR auto-merge flag

Is your feature request related to a problem? Please describe.
We'd like the safety and communication benefits of using Pull Requests while reducing the burden as much as possible

Describe the solution you'd like
I'd like a switch when calling git-xargs that will turn on the GitHub auto-merge PR feature on the PRs that it creates.

Describe alternatives you've considered
I guess we could use a GitHub action that does it somehow but then we'd need to roll that out everywhere too (there is obviously a nice tool that can do that :))

Additional context
Unfortunately the GitHub v3 API doesn't appear to expose the auto-merge feature, only the GraphQL v4 API does, so you'd need to use a library like https://github.com/shurcooL/githubv4 since go-github doesn't support v4 API.

--skip-pull-requests not working

Docs seem to suggest that you can skip pull request and commit straight to master. --skip-pull-requests with branch name as master give the following error

Error="a branch named \"refs/heads/master\" already exists"

Support for re-running scripts on only failed repos

Describe the solution you'd like
I was using git-xargs for a set of small changes on a number of repositories, but discovered a few of them have different behavior than anticipated, and I wanted to re-run a modified script against only those failed runs. Is that possible?

Describe alternatives you've considered
Manually editing a repos.txt file with the repos and re-running seems to be the answer, but it's clunky (imo).

Additional context

Implement test coverage for draft pull requests

Describe the solution you'd like
With #49 , we'll have introduced support for draft pull requests. Ideally, we'd have test coverage for this feature as well, using any mocks that make sense.

Describe alternatives you've considered
The alternative is to live without test coverage for this feature 😄

Additional context
N/A.

Error on one repository : worktree contains unstaged changes

Describe the bug
When I try to apply a "command" to a list of reporitories it works perfectly on all of them except for one that return the error in attached.

Error="worktree contains unstaged changes"

To Reproduce

I can't reproduce it manually, I try to clone the project and checkout a new branch with this command git checkout -b "core/update" but I can't reproduce the error "manually".

Screenshot 2022-04-19 at 10 09 44

Expected behavior

Normal behavior, so checkout and apply the command.

Proposal: commit diff as input for changes to make on given repos

Consider adding an option which will parse a commit and compile a list changes to apply on all supplied repos.

For example, a list containing file modifications, simple word substitutions, commit message, branch name, and similar information could be inferred from the commit change(s).

Motivation: This abstraction could be applied in CI/CD pipelines to automatically propagate simple, predictable changes across many repos on a regular basis.

Can `git-xargs` make signed git commits?

Describe the solution you'd like
It is often useful to submit signed commits to repos, it would be good if git-xargs could enable this (likely by a feature flag)

Describe alternatives you've considered
There might be a way to change my system defaults to always do this? It would depend on whether you're using the command line git tool or golang packages for git interaction, and I haven't dug into the code

Additional context
Great tool. Thanks for making and maintaining it!

--version info missing when git-xargs is installed via go get

The CircleCI job for git-xargs currently sets the main go package's VERSION variable to the $CIRCLE_TAG which is either the branch name or the tag name.

This means that when we build and publish binaries through CircleCI and programmatically attach them to a new release, they correctly have their internal VERSION value set to the tag of the release and, therefore, when you run git-xargs --version against them you get back the associated tag, e.g., git-xargs version v0.0.5.

However, when you install git-xargs via go get github.com/gruntwork-io/git-xargs, the package is downloaded from Github and then built in your defined or default $GOBIN directory. In this case, the main package's VERSION value remains unset, so running git-xargs with the --version flag returns an error.

One initial idea would be to update a VERSION file in the repo each time we do a release - so that the HEAD of the default branch contains a VERSION file which always matches the latest release's tag.

Not pushing file to repo

git-xargs version
What does git-xargs --version show?
v0.0.10
Describe the bug
A clear and concise description of what the bug is.
I'm trying to push a blank file via git-xargs on a repository that I own.

To Reproduce
Steps to reproduce the behavior:

  1. Run this command...
    export GITHUB_OAUTH_TOKEN=xxx
git-xargs --repo marshall7m/terraform-aws-github-ci --branch-name master --commit-message "add blank file" --skip-pull-requests touch foo.txt
  1. See error:
[git-xargs] INFO[2021-06-02T09:41:25-07:00] git-xargs running...                         


*****************************************************************
  GIT-XARGS RUN SUMMARY @ 2021-06-02 16:41:26.996364 +0000 UTC
  Runtime in seconds: 1
*****************************************************************


COMMAND SUPPLIED

[touch foo.txt]


 ALL REPOS THAT WERE TARGETED FOR PROCESSING AFTER FILTERING MISSING / MALFORMED REPOS
│─────────────────────────│───────────────────────────────────────────────────────│
│ REPO NAME               │ REPO URL                                              │
│─────────────────────────│───────────────────────────────────────────────────────│
│ terraform-aws-github-ci │ https://github.com/marshall7m/terraform-aws-github-ci │
│─────────────────────────│───────────────────────────────────────────────────────│


 REPOS THAT WERE SUCCESSFULLY CLONED TO THE LOCAL FILESYSTEM
│─────────────────────────│───────────────────────────────────────────────────────│
│ REPO NAME               │ REPO URL                                              │
│─────────────────────────│───────────────────────────────────────────────────────│
│ terraform-aws-github-ci │ https://github.com/marshall7m/terraform-aws-github-ci │
│─────────────────────────│───────────────────────────────────────────────────────│


 REPOS FOR WHICH CHECKING OUT A NEW TOOL-SPECIFIC BRANCH FAILED
│─────────────────────────│───────────────────────────────────────────────────────│
│ REPO NAME               │ REPO URL                                              │
│─────────────────────────│───────────────────────────────────────────────────────│
│ terraform-aws-github-ci │ https://github.com/marshall7m/terraform-aws-github-ci │
│─────────────────────────│───────────────────────────────────────────────────────│


Expected behavior
A clear and concise description of what you expected to happen.

Expected foo.txt to be pushed to target repo's master branch
Additional context
Add any other context about the problem here.

Pull request body validation error

DEBU[0010] Successfully pushed local branch to remote origin  Repo=terraform-aws-architecture-catalog
DEBU[0011] Error opening Pull request                    Base=master Body="_**This PR was created by git-xargs. See https://github.com/gruntwork-io/prototypes/pull/152 for context.**_ We recently renamed all of our repos to follow the Terraform registry format of  (e.g., ). This PR does a search & replace to update all references to these repos to the new names. GitHub can handle redirects, so in theory, everything should work fine with the old names, but there were so many renames, that to reduce confusion, this will update most of our references to the proper values." Error="POST https://api.github.com/repos/gruntwork-io/terraform-aws-architecture-catalog/pulls: 422 Validation Failed [{Resource:PullRequest Field:base Code:invalid Message:}]" Head=refs/heads/rename-repos
DEBU[0011] Error encountered while processing repo       Error="POST https://api.github.com/repos/gruntwork-io/terraform-aws-architecture-catalog/pulls: 422 Validation Failed [{Resource:PullRequest Field:base Code:invalid Message:}]" Repo name=terraform-aws-architecture-catalog

0.0.15 no longer creates PRs.

Describe the bug
The latest version, 0.0.15, no longer creates PRs. I tried same command with 0.0.14 binary and it works fine.

To Reproduce
Steps to reproduce the behavior including the relevant Terraform/Terragrunt/Packer version number and any code snippets and module inputs you used.

	./git-xargs   --branch-name mkow-test4  --repos ./java-apps.txt   --commit-message "My message"   --pull-request-title "My title"   --loglevel DEBUG   `pwd`/scripts/myScript.sh

Expected behavior
The PR should be created.

Nice to have

  • Terminal output
  • Screenshots

Additional context
Add any other context about the problem here.

Teminal output:

$ git-xargs   --branch-name mkow-test2  --repos ./java-apps.txt   --commit-message "My message"   --pull-request-title "My title"   --loglevel DEBUG   ***/updateServiceInfra.sh
[git-xargs] INFO[2022-06-23T14:48:59-04:00] git-xargs running...
[git-xargs] DEBU[2022-06-23T14:48:59-04:00] Looking up filename provided repo             Name=cplus-messaging-application Organization=****
[git-xargs] DEBU[2022-06-23T14:48:59-04:00] Successfully fetched repo                     Name=cplus-messaging-application Organization=***
[git-xargs] DEBU[2022-06-23T14:48:59-04:00] Repo will have all targeted scripts run against it  Repository=cplus-messaging-application
[git-xargs] DEBU[2022-06-23T14:48:59-04:00] Attempting to clone repository using GITHUB_OAUTH_TOKEN  Repo=cplus-messaging-application
[git-xargs] DEBU[2022-06-23T14:49:00-04:00] Enumerating objects: 951, done.
Counting objects: 100% (130/130), done.
Compressing objects: 100% (78/78), done.
Total 951 (delta 44), reused 106 (delta 28), pack-reused 821  Repo=cplus-messaging-application
[git-xargs] DEBU[2022-06-23T14:49:00-04:00] Created branch                                Branch Name=refs/heads/mkow-test2 Repo=cplus-messaging-application
[git-xargs] DEBU[2022-06-23T14:49:00-04:00]                                               Repo=cplus-messaging-application
[git-xargs] DEBU[2022-06-23T14:49:01-04:00] Executing command against local clone of repo...  Command="[***updateServiceInfra.sh]" Directory=***/workspace/git-xargs-cplus-messaging-application1237588432 Repo=cplus-messaging-application
[git-xargs] DEBU[2022-06-23T14:49:31-04:00] Output of command [***/scripts/updateServiceInfra.sh] for repo cplus-messaging-application in directory ***/workspace/git-xargs-cplus-messaging-application1237588432:
[git-xargs] DEBU[2022-06-23T14:49:31-04:00] Local repository worktree no longer clean, will stage and add new files and commit changes  Repo=cplus-messaging-application
[git-xargs] DEBU[2022-06-23T14:49:32-04:00] Successfully pushed local branch to remote origin  Repo=cplus-messaging-application
[git-xargs] INFO[2022-06-23T14:49:32-04:00] Repository successfully processed             Repo name=cplus-messaging-application


*****************************************************************
  GIT-XARGS RUN SUMMARY @ 2022-06-23 18:49:32.233789 +0000 UTC
  Runtime in seconds: 32
*****************************************************************


COMMAND SUPPLIED

[/***/updateServiceInfra.sh]

REPO SELECTION METHOD USED FOR THIS RUN - (see README.md for more information)

repos-file
 REPOS SUPPLIED VIA --repos FILE FLAG
│───────────────────│─────────────────────────────│
│ ORGANIZATION NAME │ URL                         │
│───────────────────│─────────────────────────────│
│ ***      │ cplus-messaging-application │
│───────────────────│──────────────────[git-xargs] DEBU[2022-06-23T14:49:32-04:00] pullRequestWorker received pull request job. Delay: 0 seconds. Retries: 0 for repo: cplus-messaging-application on branch: refs/heads/mkow-test2
[git-xargs] DEBU[2022-06-23T14:49:32-04:00] openPullRequest received job with retries: 0. Config max retries for this run: 3
───────────│

 ALL REPOS THAT WERE TARGETED FOR PROCESSING AFTER FILTERING MISSING / MALFORMED REPOS
│─────────────────────────────│─────────────────────────────────────────────────────────────│
│ REPO NAME                   │ REPO URL                                                    │
│─────────────────────────────│─────────────────────────────────────────────────────────────│
│ cplus-messaging-application │ https://***/cplus-messaging-application │
│─────────────────────────────│─────────────────────────────────────────────────────────────│


 REPOS THAT WERE SUCCESSFULLY CLONED TO THE LOCAL FILESYSTEM
│─────────────────────────────│─────────────────────────────────────────────────────────────│
│ REPO NAME                   │ REPO URL                                                    │
│─────────────────────────────│─────────────────────────────────────────────────────────────│
│ cplus-messaging-application │ https://***/cplus-messaging-application │
│─────────────────────────────│─────────────────────────────────────────────────────────────│


 REPOS THAT SHOWED FILE CHANGES TO THEIR WORKING DIRECTORY FOLLOWING COMMAND EXECUTION
│─────────────────────────────│─────────────────────────────────────────────────────────────│
│ REPO NAME                   │ REPO URL                                                    │
│─────────────────────────────│─────────────────────────────────────────────────────────────│
│ cplus-messaging-application │ https://***/cplus-messaging-application │
│─────────────────────────────│─────────────────────────────────────────────────────────────│


 REPOS WHOSE SPECIFIED BRANCHES DID NOT EXIST ON THE REMOTE, AND SO WERE FIRST CREATED LOCALLY
│─────────────────────────────│─────────────────────────────────────────────────────────────│
│ REPO NAME                   │ REPO URL                                                    │
│─────────────────────────────│─────────────────────────────────────────────────────────────│
│ cplus-messaging-application │ https://***/cplus-messaging-application │
│─────────────────────────────│─────────────────────────────────────────────────────────────│

Note the async log output from the PR creation thread in the report.

Using quotes to construct more complex commands doesn't work

git-xargs version
v0.0.12

To Reproduce
This fails:
git-xargs --loglevel=DEBUG --dry-run --branch-name test --repo gruntwork-io/git-xargs "touch a && touch b"

and so does even this:
git-xargs --loglevel=DEBUG --dry-run --branch-name test --repo gruntwork-io/git-xargs "touch a"

while this works
git-xargs --loglevel=DEBUG --dry-run --branch-name test --repo gruntwork-io/git-xargs touch a

So it seems that quotes are the problem, but they are necessary to construct complex commands.

Interactive mode

Currently, the tool runs in "headless" mode. You can either feed it:

* A Github organization via the `--github-org flag`
* A local file that contains repos, one on in each line, in gruntwork-io/fetch format via the `--repos` flag
* One or many repos explicitly on the command line via `--repo` 

However, whether you run it in --dry-run mode (to only see proposed changes without having them made) or you run it in normal mode such that changes are made, PRs are opened, etc, you have to sit there passively and watch the output stream by.

It would be nice to have the option to run the tool in "interactive mode" where each repo and the rich diff mentioned in #92 would be shown in your terminal and allow you to type [Y\n] to either proceed with or skip making the upgrade / change.

This would also give the tool broader appeal for folks less comfortable with the command line in general, perhaps leveraging something like https://pterm.sh/#/

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.