{"id":18459401,"url":"https://github.com/touchbistro/cannon","last_synced_at":"2025-07-08T05:38:51.917Z","repository":{"id":48049261,"uuid":"201692849","full_name":"TouchBistro/cannon","owner":"TouchBistro","description":"Automate changes across multiple git repos.","archived":false,"fork":false,"pushed_at":"2023-10-05T04:38:42.000Z","size":368,"stargazers_count":19,"open_issues_count":2,"forks_count":2,"subscribers_count":40,"default_branch":"master","last_synced_at":"2025-03-23T07:12:20.341Z","etag":null,"topics":["automation","devops","git","github","go"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TouchBistro.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-08-10T23:16:33.000Z","updated_at":"2024-09-19T15:29:29.000Z","dependencies_parsed_at":"2024-06-19T05:22:55.909Z","dependency_job_id":"3c2238dc-bbd0-46ba-a2ef-01583aa6fd7a","html_url":"https://github.com/TouchBistro/cannon","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TouchBistro%2Fcannon","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TouchBistro%2Fcannon/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TouchBistro%2Fcannon/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TouchBistro%2Fcannon/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TouchBistro","download_url":"https://codeload.github.com/TouchBistro/cannon/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247791997,"owners_count":20996876,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automation","devops","git","github","go"],"created_at":"2024-11-06T08:23:03.310Z","updated_at":"2025-04-08T06:31:45.236Z","avatar_url":"https://github.com/TouchBistro.png","language":"Go","readme":"# Commit Cannon\n\n`cannon` is a small CLI tool that lets you make changes to multiple git repos.\n\n![](docs/resources/cannon.gif)\n\n## Why?\n\nSuppose you need to make the same change across multiple git repos.\nYou could do it all by hand but this will get quite tedious especially with the more repos you have. Automation to the rescue!\n\n`cannon` makes it easy to perform a batch of changes on multiple git repos at once. It even creates GitHub PRs by default.\nAll the heavy lifting is taken care of giving you time to do more important things.\n\nIf you want to know more about why we did this and see a use case for it checkout out our [blog post](https://medium.com/touchbistro-development/commit-cannon-open-source-project-899ee75794c0).\n\n## Setup Instructions\n\n1. Make sure you have [Go](https://golang.org/doc/install) installed and set up.\n2. Install `cannon`:\n\n   ```sh\n   go install github.com/TouchBistro/cannon@latest\n   ```\n\n   **NOTE:** Make sure you have the following in your `~/.bash_profile` or `~/.zshrc` to ensure programs installed with `go install` are available globally:\n\n   ```sh\n   export PATH=\"$(go env GOPATH)/bin:$PATH\"\n   ```\n\n3. Create a GitHub Access Token:\n\n   A Github Access Token is required to be able create GitHub PRs for changes to repos.\n\n   - Create the token with the `repo` box checked in the list of permissions. Follow the instructions [here](https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line) to learn more.\n   - Set the `GITHUB_TOKEN` environment variable to the value of the token.\n     For example if you use bash or zsh, add the following to your `.bash_profile` or `.zshrc`:\n\n     ```sh\n     export GITHUB_TOKEN=\u003cYOUR_TOKEN\u003e\n     ```\n\n## Usage\n\nTo use `cannon` provide a `cannon.yml` file which contains a list of repos and a list of actions to apply.\n\n```sh\nUsage of ./cannon:\n      --clean                   Clean cannon cache directory\n  -m, --commit-message string   The commit message to use (default \"Apply commit-cannon changes\")\n      --no-pr                   Prevents creating a Pull Request in the remote repo\n      --no-push                 Prevents pushing to remote repo\n  -p, --path string             The path to a cannon.yml config file (default \"cannon.yml\")\n  -v, --verbose                 Enable verbose logging\n```\n\n### Actions\n\n`cannon` supports 3 categories of actions which are described below.\n\n#### Text Actions\n\nA text action is an action applied to the text in a file within a repo.\nThe search text for the action is a regex which allows for complex searches within a file.\nThe `path` field in the config must be relative to the root of the repo.\n\nThe following text actions are supported:\n\n1. `replaceLine` - Replace an entire line including any leading whitespace (trims trailing whitespace).\n   ```yml\n   type: replaceLine\n   searchText: \u003cThe line that will be replaced\u003e\n   applyText: \u003cThe line to add\u003e\n   path: \u003cThe path to the file\u003e\n   ```\n2. `deleteLine` - Delete an entire line including any leading whitespace.\n   ```yml\n   type: deleteLine\n   searchText: \u003cThe line to delete\u003e\n   path: \u003cThe path to the file\u003e\n   ```\n3. `replaceText` - Replace some text. The text can span multiple lines.\n   ```yml\n   type: replaceText\n   searchText: \u003cThe text that will be replaced\u003e\n   applyText: \u003cThe text to add\u003e\n   path: \u003cThe path to the file\u003e\n   ```\n4. `appendText` - Append text to matching text.\n   ```yml\n   type: appendText\n   searchText: \u003cThe text that will be appended to\u003e\n   applyText: \u003cThe text to append\u003e\n   path: \u003cThe path to the file\u003e\n   ```\n5. `deleteText` - Delete matching text. The text can span multiple lines.\n   ```yml\n   type: deleteText\n   searchText: \u003cThe text to delete\u003e\n   path: \u003cThe path to the file\u003e\n   ```\n\n#### File Actions\n\nA file action is an action applied to an entire file within a repo.\nThe `dstPath` field in the config must be relative to the root of the repo.\n\nThe following file actions are supported:\n\n1. `createFile` - Create a file if it doesn't already exist.\n   ```yml\n   type: createFile\n   srcPath: \u003cThe file to use\u003e\n   dstPath: \u003cThe path to create the file at\u003e\n   ```\n2. `replaceFile` - Replace a file if it already exists.\n   ```yml\n   type: replaceFile\n   srcPath: \u003cThe file to use\u003e\n   dstPath: \u003cThe path to the file to replace\u003e\n   ```\n3. `createOrReplaceFile` - Create a file if it doesn't exist or replace it if it does exist.\n   ```yml\n   type: createOrReplaceFile\n   srcPath: \u003cThe file to use\u003e\n   dstPath: \u003cThe path to create or replace the file at\u003e\n   ```\n4. `deleteFile` - Delete a file if it already exists.\n   ```yml\n   type: deleteFile\n   dstPath: \u003cThe path to the file to delete\u003e\n   ```\n\n#### Command Action\n\nA command action allows for running a command in a repo.\n\nThe following command actions are supported:\n\n1. `runCommand` - Runs a command in the repo.\n   ```yml\n   type: runCommand\n   run: \u003cThe command to run\u003e\n   ```\n2. `shellCommand` - Runs a command in a shell (`sh`) in a repo.\n   ```yml\n   type: shellCommand\n   run: \u003cThe shell command to run\u003e\n   ```\n\n## Configuration\n\n`cannon.yml` example:\nThe `cannon.yml` file is structured as follows:\n\n```yml\nrepos:\n  - name: TouchBistro/touchbistro-node-boilerplate\n  - name: TouchBistro/touchbistro-node-shared\nactions:\n  - type: replaceLine\n    searchText: DB_USER=SA\n    applyText: DB_USER=core\n    path: .env.example\n  - type: replaceText\n    searchText: console.log\n    applyText: LOGGER.debug\n    path: src/index.ts\n  - type: createFile\n    srcPath: files/text.txt\n    dstPath: text.txt\n  - type: deleteFile\n    dstPath: .env.example\n  - type: replaceFile\n    srcPath: files/.env.test\n    dstPath: .env.compose\n  - type: createOrReplaceFile\n    srcPath: files/.env.test\n    dstPath: .env.test\n  - type: runCommand\n    run: yarn install\n  - type: shellCommand\n    run: if [ ! -d data ]; then mkdir data; touch data/.gitkeep; fi\n```\n\n### Change base branch for PRs\n\nBy default `cannon` will target `master` as the base branch when creating PRs.\nIf you need to use a different base branch you can set it using the `base` field of the repo.\n\nExample:\n\n```yml\nrepos:\n  - name: org/repo-name\n    base: develop\n```\n\nThis would create PRs with `develop` as the base branch.\n\n## Contributing\n\nSee [contributing](CONTRIBUTING.md) for instructions on how to contribute to `cannon`. PRs welcome!\n\n## License\n\nMIT © TouchBistro, see [LICENSE](LICENSE) for details.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftouchbistro%2Fcannon","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftouchbistro%2Fcannon","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftouchbistro%2Fcannon/lists"}