├── LICENSE ├── README.md ├── ci-and-tooling-config ├── global-gitignore.batch.yaml ├── update-circle-ci-config │ └── update-circle-ci-config.batch.yaml └── update-circle-ci-docker-user.batch.yaml ├── docker ├── pin-docker-images.batch.yaml ├── update-dart-base-images.batch.yaml └── update-golang-base-images.batch.yaml ├── golang ├── autofix-go │ ├── README.md │ ├── combine-function-parameters.batch.yml │ ├── remove-expensive-string-comparison.batch.yml │ └── replace-to-replaceAll.batch.yml ├── comby-go-refactor │ ├── README.md │ └── comby-log-printf.batch.yaml ├── comby-goimports │ ├── README.md │ └── comby-go-import-rewrite.batch.yaml └── go-interface-to-any │ └── interface-to-any.spec.yml ├── hcl ├── add-default_tags │ └── add-default-tags.batch.yaml └── set-cidr-vpc │ ├── Dockerfile │ └── set-cidr-vpc.batch.yml ├── java ├── java-openrewrite │ ├── gradle.yaml │ └── maven.yaml └── remove-catch.batch.yaml ├── js-ts ├── bootstrap-upgrade.batch.yaml ├── colors │ └── batch.yml ├── eslint-fix │ ├── README.md │ ├── eslint-fix.batch.yaml │ └── eslint-fix.simple.batch.yaml ├── js-codeshift │ ├── Dockerfile │ ├── README.md │ └── warn-to-log.batch.yml ├── npm-package-update │ ├── README.md │ └── npm-update.yaml ├── update-api-query │ └── replace-viewer-configuration.yaml ├── update-typescript.workspaces.batch.yaml └── vscode-extension-recommendation │ └── vscode-extension-recommendation.batch.yml ├── misc ├── fix-misused-weekyear.batch.yaml ├── update-language.find-and-ruplacer.batch.yaml ├── update-language.ruplacer.batch.yaml └── update-language.sedspec.yaml ├── php └── introduce-phpstan.batch.yml ├── python └── python-refactor │ ├── README.md │ └── python-refactor.yaml ├── semgrep ├── README.md └── semgrep.batch.yaml ├── ticketing-systems ├── github-issues │ ├── Dockerfile │ ├── README.md │ ├── gh-issues.batch.yml │ └── sync-issue.py ├── jira-tickets │ ├── Dockerfile │ ├── README.md │ ├── create-jira.py │ └── jira.campaign.yml ├── track-important-milestone.batch.yaml └── track-many-issues │ ├── README.md │ └── track.batch.yml ├── utils ├── add-backstage-github.batch.yaml ├── add-backstage-minimal.batch.yaml ├── add-file │ ├── README.md │ ├── add-file.batch.yaml │ ├── apache.txt │ └── mount-file.batch.yaml ├── branch-addressing.yaml ├── dynamic-changeset-template.batch.yaml ├── templated-files.batch.yaml ├── workspace-discovery-additional-files.yaml └── workspace-discovery.yaml ├── xml ├── update-maven-dependency-with-transform-changes.yaml ├── update-maven-dependency.yaml └── update-xml-boilerplate.batch.yaml └── yaml ├── README.md ├── modify-yaml-mount-file.batch.yaml ├── modify-yaml.batch.yaml ├── update-k8s-manifest.yaml └── update-yaml.rb /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Batch Changes examples 2 | 3 | Example batch specs to get you started with Batch Changes. Contributions welcome! 4 | 5 | ## Getting started 6 | 7 | Take a look at the [Sourcegraph documentation on Batch Changes](https://docs.sourcegraph.com/batch_changes) to learn what batch changes are and how to run them. 8 | 9 | ## Examples 10 | 11 | - [Rewrite Go import paths using Comby](golang/comby-goimports/README.md) 12 | - [Refactor Go code with Comby](golang/comby-go-refactor/README.md) 13 | - [Open Jira tickets alongside changesets](ticketing-systems/jira-tickets/README.md) 14 | - [Open GitHub tickets alongside changesets (declarative)](ticketing-systems/github-issues/README.md) 15 | - [Update deprecated GraphQL API query](js-ts/update-api-query/replace-viewer-configuration.yaml) 16 | - [Update the Docker Hub username in Circle CI configurations](ci-and-tooling-config/update-circle-ci-docker-user.batch.yaml) 17 | - [Migrate from Python 2 to 3](python/python-refactor/README.md) 18 | - [Update package.json for NPM dependencies](js-ts/npm-package-update/README.md) 19 | - [Rewrite `interface{}` to `any` in Go 1.18 code](golang/go-interface-to-any/interface-to-any.spec.yml) 20 | 21 | For a list of static-checker style linting rules for go, also see [comby go-patterns](https://github.com/comby-tools/go-patterns). 22 | 23 | ## Other examples 24 | 25 | Also see how Batch Changes can help respond to a vulnerability with this [example](https://github.com/sourcegraph/log4j-cve-code-search-resources/tree/c70aeb6236f12c22c7c19e9b3fa54b2049213e29/batch-changes) 26 | -------------------------------------------------------------------------------- /ci-and-tooling-config/global-gitignore.batch.yaml: -------------------------------------------------------------------------------- 1 | name: gitignore-editor-files 2 | description: Append rules to `.gitignore` files to ignore Vim, Emacs and IntelliJ temp files. 3 | 4 | # Find all repositories that contain a .gitignore file. 5 | on: 6 | - repositoriesMatchingQuery: repo:automation-testing$ 7 | 8 | steps: 9 | - run: cat /tmp/global-gitignore >> .gitignore 10 | container: alpine:3 11 | files: 12 | /tmp/global-gitignore: | 13 | # Vim 14 | *.swp 15 | # JetBrains/IntelliJ 16 | .idea 17 | # Emacs 18 | *~ 19 | \#*\# 20 | /.emacs.desktop 21 | /.emacs.desktop.lock 22 | .\#* 23 | .dir-locals.el 24 | 25 | # Describe the changeset (e.g., GitHub pull request) you want for each repository. 26 | changesetTemplate: 27 | title: Ignore editor temp files in .gitignore 28 | body: This extends the .gitignore file to ignore temp files created by Vim/Emacs/IntelliJ 29 | branch: batch-changes/ignore-editor-files-no-admin # Push the commit to this branch. 30 | commit: 31 | message: Ignore editor temp files in .gitignore 32 | published: 33 | - gitlab.sgdev.org/sourcegraph/react-loading-spinner: true 34 | - github.com/sd9/react-quill: false 35 | -------------------------------------------------------------------------------- /ci-and-tooling-config/update-circle-ci-config/update-circle-ci-config.batch.yaml: -------------------------------------------------------------------------------- 1 | name: update-circle-ci-docker-user 2 | description: Changes the Docker Hub username used for Circle CI 3 | 4 | # Search for repositories containing a circle-ci.yml file with the old usename 5 | on: 6 | - repositoriesMatchingQuery: mydockerhub-user file:circle-ci.[yaml|yml] 7 | 8 | # In each repository 9 | steps: 10 | # replace the old with the new username in the found files 11 | - run: | 12 | for file in "${{ join repository.search_result_paths " " }}"; 13 | do 14 | sed -i 's/mydockerhub-user/ci-dockerhub-user/g;' ${file} 15 | done 16 | container: alpine:3 17 | 18 | # Describe the changeset (e.g., GitHub pull request) you want for each repository. 19 | changesetTemplate: 20 | title: Use new Docker Hub username in Circle CI config 21 | body: This change replaces the old Docker Hub user with the new, CI specific user account. 22 | branch: batch-changes/update-ci-user # Push the commit to this branch. 23 | commit: 24 | message: Update Docker Hub user in CI 25 | published: false 26 | -------------------------------------------------------------------------------- /ci-and-tooling-config/update-circle-ci-docker-user.batch.yaml: -------------------------------------------------------------------------------- 1 | name: update-circle-ci-docker-user.batch-change.yaml 2 | description: Changes the Docker Hub username used for Circle CI 3 | 4 | # Search for repositories containing a circle-ci.yml file with the old usename 5 | on: 6 | - repositoriesMatchingQuery: mydockerhub-user file:circle-ci.[yaml|yml] 7 | 8 | # In each repository 9 | steps: 10 | # replace the old with the new username in the found files 11 | - run: | 12 | for file in "${{ join repository.search_result_paths " " }}"; 13 | do 14 | sed -i 's/mydockerhub-user/ci-dockerhub-user/g;' ${file} 15 | done 16 | container: alpine:3 17 | 18 | # Describe the changeset (e.g., GitHub pull request) you want for each repository. 19 | changesetTemplate: 20 | title: Use new Docker Hub username in Circle CI config 21 | body: This change replaces the old Docker Hub user with the new, CI specific user account. 22 | branch: batch-changes/update-ci-user # Push the commit to this branch. 23 | commit: 24 | message: Update Docker Hub user in CI 25 | published: false 26 | -------------------------------------------------------------------------------- /docker/pin-docker-images.batch.yaml: -------------------------------------------------------------------------------- 1 | name: pin-docker-base-images 2 | description: Pin Docker images using the `:latest` tag to a specific image digest. 3 | 4 | on: 5 | # Find all repositories that contain Dockerfiles with a `:latest` tag in a base image. 6 | - repositoriesMatchingQuery: ^FROM (\w+\/)?\w+:latest($|\s) file:Dockerfile patternType:regexp fork:yes 7 | 8 | # In each repository... 9 | steps: 10 | # Use dockerlint to pin the images in the Dockerfiles we found: 11 | - run: | 12 | for file in "${{ join repository.search_result_paths " " }}"; 13 | do 14 | dockerlint -w ${file} 15 | done 16 | container: sourcegraph/dockerlint-run:latest 17 | 18 | # Describe the changeset (e.g., GitHub pull request) you want for each repository. 19 | changesetTemplate: 20 | title: Pin Docker `:latest` image tags to digest 21 | body: | 22 | The `:latest` tag changes, so future pulls of this image may retrieve a different image 23 | with different (and possibly erroneous, unexpected, or dangerous) behavior. 24 | 25 | Pin the image to an [image digest](https://docs.docker.com/engine/reference/commandline/pull/#pull-an-image-by-digest-immutable-identifier) 26 | for deterministic behavior. 27 | 28 | *See also: [Hadolint error DL3007](https://github.com/hadolint/hadolint/wiki/DL3007).* 29 | branch: batch-changes/pin-docker-images 30 | commit: 31 | message: Pin Docker `:latest` image tags to digest 32 | published: 33 | - gitlab.sgdev.org/thorsten/*: true 34 | - bitbucket.sgdev.org/SOUR/automation-testing: true 35 | - github.com/sourcegraph-testing/etcd: true 36 | -------------------------------------------------------------------------------- /docker/update-dart-base-images.batch.yaml: -------------------------------------------------------------------------------- 1 | name: update-dart-base-images-2-10 2 | description: This batch change updates `google/dart:2.*` base images in Dockerfiles to `google/dart:2.10.2`. 3 | 4 | on: 5 | # Find all repositories that contain Dockerfiles with `FROM google/dart:2.*` as base images. 6 | # The regexp used here matches images 7 | # 8 | # google/dart:2.MINOR.PATCH 9 | # google/dart:2.MINOR.PATCH-dev.DEVMINOR.DEVPATCH 10 | # 11 | # google/dart-runtime:2.MINOR.PATCH 12 | # google/dart-runtime:2.MINOR.PATCH-dev.DEVMINOR.DEVPATCH 13 | # 14 | # where the tag is < 2.10. Feel free to adjust it to your requirements. 15 | - repositoriesMatchingQuery: ^FROM google\/dart(-runtime)?:2\.[0-9]\.?\d?(-dev\.\d\.\d)? file:Dockerfile patternType:regexp 16 | 17 | # In each repository 18 | steps: 19 | # we use comby to update the base images with the sha256 suffix 20 | - run: | 21 | find . -name Dockerfile -type f |\ 22 | xargs sed\ 23 | -i\ 24 | --regexp-extended\ 25 | 's/FROM google\/dart(-runtime)?:2\.[[:digit:]]\.?[[:digit:]]?(-dev\.?[[:digit:]]?\.?[[:digit:]]?)?/FROM google\/dart:2\.10/g' 26 | container: alpine:3 27 | 28 | # Describe the changeset (e.g., GitHub pull request) you want for each repository. 29 | changesetTemplate: 30 | title: Update google/dart base images in Dockerfiles to 2.10.2 31 | body: This updates google/dart base images used in Dockerfiles to version 2.10.2 32 | branch: batch-changes/google-dart-2-10-2-base-images # Push the commit to this branch. 33 | commit: 34 | message: Update google/dart base images in Dockerfiles to 2.10.2 35 | published: 36 | - github.com/sourcegraph/lsif-dart-action: true 37 | -------------------------------------------------------------------------------- /docker/update-golang-base-images.batch.yaml: -------------------------------------------------------------------------------- 1 | name: update-golang-base-images 2 | description: This batch change updates the golang builder images in Dockerfiles to Go 1.15. 3 | 4 | on: 5 | # Find all repositories that contain Dockerfiles with `FROM golang:1.MINOR-alpine [...]` in it, 6 | # where the MINOR version can be 10 to 14. 7 | - repositoriesMatchingQuery: FROM golang:1.1:[minor~[0-4]]-alpine file:Dockerfile patternType:structural 8 | # and optionally specify a sha256 hash 9 | - repositoriesMatchingQuery: FROM golang:1.1:[minor~[0-4]]-alpine@sha256::[hash~[a-f0-9]+] file:Dockerfile patternType:structural 10 | 11 | # In each repository 12 | steps: 13 | # we use comby to update the base images with the sha256 suffix 14 | - run: | 15 | comby \ 16 | -in-place \ 17 | 'FROM golang::[version]-alpine@sha256::[hash~[a-f0-9]+]' \ 18 | 'FROM golang:1.15-alpine@sha256:df0119b970c8e5e9f0f5c40f6b55edddf616bab2b911927ebc3b361c469ea29c' \ 19 | Dockerfile 20 | container: comby/comby 21 | # and use comby to replace the ones without it: 22 | - run: | 23 | comby \ 24 | -in-place \ 25 | 'FROM golang::[version]-alpine' \ 26 | 'FROM golang:1.15-alpine' \ 27 | Dockerfile 28 | container: comby/comby 29 | 30 | # Describe the changeset (e.g., GitHub pull request) you want for each repository. 31 | changesetTemplate: 32 | title: Update golang base images in Dockerfiles to 1.15 33 | body: This updates golang base images used in Dockerfiles from golang:1.10 to 1.14 to use golang:1.15. 34 | branch: batch-changes/golang-15-base-images # Push the commit to this branch. 35 | commit: 36 | message: Update golang base images in Dockerfiles to 1.15 37 | published: false 38 | -------------------------------------------------------------------------------- /golang/autofix-go/README.md: -------------------------------------------------------------------------------- 1 | This repository contains example specs used for the "Sourcegraph autofix" for go hackaton project 2 | -------------------------------------------------------------------------------- /golang/autofix-go/combine-function-parameters.batch.yml: -------------------------------------------------------------------------------- 1 | name: combine-functions-parameters 2 | description: | 3 | This batch change uses [Comby](https://comby.dev) to combine function parameters of the same type 4 | 5 | on: 6 | - repositoriesMatchingQuery: lang:go (:[[a]] :[[type]], :[[b]] :[[type]]) patterntype:structural 7 | - repositoriesMatchingQuery: lang:go (:[[a]] :[[type]], :[[b]] :[[type]], :[[c]] :[[type]]) patterntype:structural 8 | - repositoriesMatchingQuery: lang:go (:[[a]] :[[type]], :[[b]] :[[type]], :[[c]] :[[type]], :[[d]] :[[type]]) patterntype:structural 9 | - repositoriesMatchingQuery: lang:go (:[[a]] :[[type]], :[[b]] :[[type]], :[[c]] :[[type]], :[[d]] :[[type]], :[[e]] :[[type]]) patterntype:structural 10 | - repositoriesMatchingQuery: lang:go (:[[a]] :[[type]], :[[b]] :[[type]], :[[c]] :[[type]], :[[d]] :[[type]], :[[e]] :[[type]], :[[f]] :[[type]]) patterntype:structural 11 | 12 | steps: 13 | - run: | 14 | comby -in-place '(:[[a]] :[[type]], :[[b]] :[[type]])' '(:[[a]], :[[b]] :[[type]])' .go -matcher .go -exclude-dir .,vendor; 15 | comby -in-place '(:[[a]] :[[type]], :[[b]] :[[type]]), :[[c]] :[[type]]' '(:[[a]], :[[b]], :[[c]] :[[type]])' .go -matcher .go -exclude-dir .,vendor; 16 | comby -in-place '(:[[a]] :[[type]], :[[b]] :[[type]], :[[c]] :[[type]], :[[d]] :[[type]])' '(:[[a]], :[[b]], :[[c]], :[[d]] :[[type]])' .go -matcher .go -exclude-dir .,vendor; 17 | comby -in-place '(:[[a]] :[[type]], :[[b]] :[[type]], :[[c]] :[[type]], :[[d]] :[[type]], :[[e]] :[[type]])' '(:[[a]], :[[b]], :[[c]], :[[d]], :[[e]] :[[type]])' .go -matcher .go -exclude-dir .,vendor; 18 | comby -in-place '(:[[a]] :[[type]], :[[b]] :[[type]], :[[c]] :[[type]], :[[d]] :[[type]], :[[e]] :[[type]], :[[f]] :[[type]])' '(:[[a]], :[[b]], :[[c]], :[[d]], :[[e]], :[[f]] :[[type]])' .go -matcher .go -exclude-dir .,vendor; 19 | container: comby/comby 20 | 21 | # Describe the changeset (e.g., GitHub pull request) you want for each repository. 22 | changesetTemplate: 23 | title: Combine type declaration in function parameters 24 | body: This batch change combines type declaration in function parameters, when declarations for the same type are contiguous, and for a maximum of 7 parameters. 25 | branch: go-autofix/combine-parameters # Push the commit to this branch. 26 | commit: 27 | message: Combine function parameter type declaration 28 | 29 | -------------------------------------------------------------------------------- /golang/autofix-go/remove-expensive-string-comparison.batch.yml: -------------------------------------------------------------------------------- 1 | name: remove-expensive-string-comparison 2 | description: | 3 | This batch change uses [Comby](https://comby.dev) to remove [expensive string comparisons](https://about.sourcegraph.com/blog/code-search-turned-code-checker/) 4 | 5 | on: 6 | - repositoriesMatchingQuery: if strings.ToLower(:[[a]]) == strings.ToLower(:[[b]]) patternType:structural count:1 7 | 8 | steps: 9 | - run: comby -in-place 'if strings.ToLower(:[[a]]) == strings.ToLower(:[[b]])' 'if strings.EqualFold(:[a],:[b])' .go -matcher .go -exclude-dir .,vendor 10 | container: comby/comby 11 | 12 | # Describe the changeset (e.g., GitHub pull request) you want for each repository. 13 | changesetTemplate: 14 | title: Replace expensive string comparisons 15 | body: This batch change replaces expensive string comparisons by a more [optimized](https://about.sourcegraph.com/blog/code-search-turned-code-checker/) comparison using strings.EqualFold. 16 | branch: go-autofix/expensive-stringcomparison # Push the commit to this branch. 17 | commit: 18 | message: Make string comparison less expensive -------------------------------------------------------------------------------- /golang/autofix-go/replace-to-replaceAll.batch.yml: -------------------------------------------------------------------------------- 1 | name: replace-to-replaceAll 2 | description: | 3 | This batch change uses [Comby](https://comby.dev) to replace the deprecated String.replaceAll(a,b,c,-1) by String.Replace(a,b,c) 4 | 5 | on: 6 | - repositoriesMatchingQuery: strings.Replace(..., ..., -1) lang:go patternType:structural 7 | 8 | steps: 9 | - run: comby -in-place 'strings.Replace(:[a],:[b],:[c], -1)' 'strings.ReplaceAll(:[a],:[b],:[c])' .go -matcher .go -exclude-dir .,vendor 10 | container: comby/comby 11 | 12 | # Describe the changeset (e.g., GitHub pull request) you want for each repository. 13 | changesetTemplate: 14 | title: Replace outdated replace( a, b, c, -1) by replaceAll 15 | body: This batch change uses comby to replace the deprecated replace( a, b, c, -1) by replaceAll 16 | branch: go-autofix/replaceAll # Push the commit to this branch. 17 | commit: 18 | message: Replace replace( , -1) by replaceAll 19 | -------------------------------------------------------------------------------- /golang/comby-go-refactor/README.md: -------------------------------------------------------------------------------- 1 | # Refactoring Go code with Comby 2 | 3 | This batch change rewrites Go statements from 4 | 5 | ```go 6 | fmt.Sprintf("%d", number) 7 | ``` 8 | 9 | to 10 | 11 | ```go 12 | strconv.Itoa(number) 13 | ``` 14 | 15 | since they are equivalent. 16 | 17 | And then runs `gofmt` over the repository. 18 | 19 | --- 20 | 21 | ```yaml 22 | name: comby-go-fmt 23 | description: Run `comby` and `go fmt` 24 | 25 | # Find all repositories that contain a README.md file. 26 | on: 27 | - repositoriesMatchingQuery: lang:go fmt.Sprintf("%d", :[v]) patterntype:structural 28 | 29 | steps: 30 | - run: comby -in-place 'fmt.Sprintf("%d", :[v])' 'strconv.Itoa(:[v])' ${{ join repository.search_result_paths " " }} 31 | container: comby/comby 32 | - run: goimports -w ${{ join previous_step.modified_files " " }} 33 | container: unibeautify/goimports 34 | 35 | # Describe the changeset (e.g., GitHub pull request) you want for each repository. 36 | changesetTemplate: 37 | title: Replacing fmt.Sprintf with strconv.Itoa 38 | body: This campiagn replaces `fmt.Sprintf` with `strconv.Itoa` 39 | branch: batch-changes/comby-go-fmt # Push the commit to this branch. 40 | commit: 41 | message: Replacing fmt.Sprintf with strconv.Iota 42 | published: true 43 | ``` 44 | 45 | Save as `batch-batch.yaml` and execute 46 | 47 | ``` 48 | src batch preview -f batch-batch.yaml -namespace 49 | ``` 50 | -------------------------------------------------------------------------------- /golang/comby-go-refactor/comby-log-printf.batch.yaml: -------------------------------------------------------------------------------- 1 | name: comby-log-printf 2 | description: | 3 | This batch change uses [Comby](https://comby.dev) to rewrite `log.Printf` calls with `log15.Warn` calls. 4 | 5 | on: 6 | - repositoriesMatchingQuery: lang:go log.Printf(":[format]", :[args]) patternType:structural repo:sourcegraph$ 7 | 8 | steps: 9 | # Run comby only over the exact search result paths: 10 | - run: comby -in-place -matcher .go -config /tmp/comby-conf.toml -f ${{ join repository.search_result_paths "," }} 11 | container: comby/comby 12 | files: 13 | # Create files inside the container by specifying path and content here: 14 | /tmp/comby-conf.toml: | 15 | [log_to_log15] 16 | match='log.Printf(":[format]", :[args])' 17 | rewrite='log15.Warn(":[format]", :[args])' 18 | rule='where 19 | rewrite :[format] { "%:[[_]] " -> "" }, 20 | rewrite :[format] { " %:[[_]]" -> "" }, 21 | rewrite :[args] { ":[arg~[a-zA-Z0-9.()]+]" -> "\":[arg]\", :[arg]" }' 22 | 23 | # Now run goimports, but only over those files that comby modified: 24 | - run: goimports -w ${{ join previous_step.modified_files " " }} 25 | container: unibeautify/goimports 26 | 27 | changesetTemplate: 28 | title: Replace log.Printf with log15.Warn 29 | body: | 30 | This batch change replaces `log.Printf` calls with with `log15.Warn` to standardize on a logger. 31 | 32 | It converts `log.Printf` calls like this: 33 | 34 | ``` 35 | log.Printf("Add %v as a temporary child of root %v", t.Span.ID, root.Span.ID) 36 | ``` 37 | 38 | into `log15.Warn` calls like this: 39 | 40 | ``` 41 | log15.Warn("Add as a temporary child of root", "t.Span.ID,", t.Span.ID, "root.Span.ID", root.Span.ID) 42 | ``` 43 | branch: batch-changes/sprintf-to-itoa 44 | commit: 45 | message: Replacing fmt.Sprintf with strconv.Iota 46 | author: 47 | email: mrnugget@gmail.com 48 | name: Thorsten Ball 49 | published: false 50 | -------------------------------------------------------------------------------- /golang/comby-goimports/README.md: -------------------------------------------------------------------------------- 1 | # Rewriting Go imports with Comby 2 | 3 | This batch change rewrites Go import paths for the `log15` package from `gopkg.in/inconshreveable/log15.v2` to `github.com/inconshreveable/log15` using [Comby](https://comby.dev/): 4 | 5 | It can handle single-package import statements like these 6 | 7 | ```go 8 | import "gopkg.in/inconshreveable/log15.v2" 9 | ``` 10 | 11 | and multi-package import statements like these: 12 | 13 | ```go 14 | import ( 15 | "io" 16 | 17 | "github.com/pkg/errors" 18 | "gopkg.in/inconshreveable/log15.v2" 19 | ) 20 | ``` 21 | 22 | --- 23 | 24 | ```yaml 25 | name: rewrite-log15-import 26 | description: This batch change rewrites Go import paths for the `log15` package from `gopkg.in/inconshreveable/log15.v2` to `github.com/inconshreveable/log15` using [Comby](https://comby.dev/) 27 | 28 | # Find all repositories that contain the import we want to change. 29 | on: 30 | - repositoriesMatchingQuery: lang:go gopkg.in/inconshreveable/log15.v2 31 | 32 | # In each repository 33 | steps: 34 | # we first replace the import when it's part of a multi-package import statement 35 | - run: comby -in-place 'import (:[before]"gopkg.in/inconshreveable/log15.v2":[after])' 'import (:[before]"github.com/inconshreveable/log15":[after])' .go -matcher .go -exclude-dir .,vendor 36 | container: comby/comby 37 | # ... and when it's a single import line. 38 | - run: comby -in-place 'import "gopkg.in/inconshreveable/log15.v2"' 'import "github.com/inconshreveable/log15"' .go -matcher .go -exclude-dir .,vendor 39 | container: comby/comby 40 | 41 | # Describe the changeset (e.g., GitHub pull request) you want for each repository. 42 | changesetTemplate: 43 | title: Fix import path for log15 package 44 | body: Rewrites Go import paths for the `log15` package from `gopkg.in/inconshreveable/log15.v2` to `github.com/inconshreveable/log15` using [Comby](https://comby.dev/) 45 | branch: batch-changes/comby-go-fmt # Push the commit to this branch. 46 | commit: 47 | message: Fix import path for log15 package 48 | published: false 49 | ``` 50 | 51 | Save as `batch-batch.yaml` and execute 52 | 53 | ``` 54 | src batch preview -f batch-batch.yaml -namespace 55 | ``` 56 | -------------------------------------------------------------------------------- /golang/comby-goimports/comby-go-import-rewrite.batch.yaml: -------------------------------------------------------------------------------- 1 | name: rewrite-log15-import 2 | description: "This batch change rewrites Go import paths for the `log15` package from 3 | 4 | `gopkg.in/inconshreveable/log15.v2` 5 | 6 | to 7 | 8 | `github.com/inconshreveable/log15` 9 | 10 | using [Comby](https://comby.dev/)" 11 | 12 | on: 13 | - repositoriesMatchingQuery: lang:go gopkg.in/inconshreveable/log15.v2 -repo:sourcegraph/sourcegraph$ 14 | 15 | steps: 16 | - run: comby -in-place 'import (:[before]"gopkg.in/inconshreveable/log15.v2":[after])' 'import (:[before]"github.com/inconshreveable/log15":[after])' .go -matcher .go -exclude-dir .,vendor 17 | container: comby/comby 18 | - run: comby -in-place 'import "gopkg.in/inconshreveable/log15.v2"' 'import "github.com/inconshreveable/log15"' .go -matcher .go -exclude-dir .,vendor 19 | container: comby/comby 20 | 21 | # Describe the changeset (e.g., GitHub pull request) you want for each repository. 22 | changesetTemplate: 23 | title: Fix import path for log15 package 24 | body: Rewrites Go import paths for the `log15` package from `gopkg.in/inconshreveable/log15.v2` to `github.com/inconshreveable/log15` using [Comby](https://comby.dev/) 25 | branch: batch-change/rewrite-log15-import 26 | commit: 27 | message: Fix import path for log15 package 28 | published: true 29 | -------------------------------------------------------------------------------- /golang/go-interface-to-any/interface-to-any.spec.yml: -------------------------------------------------------------------------------- 1 | name: interface-to-any 2 | description: | 3 | This batch spec rewrites `interface{}` to `any`, the new type alias introduced with Go.18 4 | on: 5 | - repositoriesMatchingQuery: lang:go interface{} 6 | 7 | steps: 8 | - run: | 9 | results="${{ join repository.search_result_paths "\n" }}" 10 | for result in $results; 11 | do 12 | echo "Rewriting ${result}" 13 | gofmt -w -r 'interface{} -> any' "${result}" 14 | done; 15 | container: golang 16 | 17 | changesetTemplate: 18 | title: "Go 1.18: rewrite `interface{}` to `any`" 19 | body: Rewrites `interface{}` to `any` using `gofmt` 20 | branch: batches/interface-to-any 21 | commit: 22 | message: Rewrites `interface{}` to `any` using `gofmt` 23 | -------------------------------------------------------------------------------- /hcl/add-default_tags/add-default-tags.batch.yaml: -------------------------------------------------------------------------------- 1 | # This batch change uses comby to add default tags to Terraform locals.tf file 2 | # The comby replace patterns are stored in a TOML file for convenience https://comby.dev/docs/configuration#toml-format 3 | 4 | name: add-repo-tags 5 | description: | 6 | Use comby to add the repository name as a ServiceName tag 7 | 8 | on: 9 | - repositoriesMatchingQuery: file:locals.tf$ lang:HCL tag not ServiceName 10 | 11 | steps: 12 | - run: | 13 | comby -in-place -config /tmp/patterns.toml; 14 | container: comby/comby 15 | files: # comby patterns can be listed out in a file 16 | /tmp/patterns.toml: | 17 | [pattern] 18 | match='''locals { 19 | name = :[name] 20 | default_tags = {:[block] 21 | } 22 | }''' 23 | 24 | rewrite='''locals { 25 | name = :[name] 26 | default_tags = {:[block] 27 | Repository = "${{repository.name}}" 28 | } 29 | }''' 30 | - run: terraform fmt # use your usual formatter 31 | container: hashicorp/terraform:latest 32 | 33 | 34 | # Describe the changeset (e.g., GitHub pull request) you want for each repository. 35 | changesetTemplate: 36 | title: Add ServiceName tag 37 | body: Use comby to add the repository name as a ServiceName tag 38 | branch: batches/add-servicename-tag 39 | commit: 40 | message: Add service name tag 41 | -------------------------------------------------------------------------------- /hcl/set-cidr-vpc/Dockerfile: -------------------------------------------------------------------------------- 1 | # If building on M1, build using --platform linux/amd64 2 | FROM golang:1.18.3-alpine3.16 3 | RUN apk --no-cache add make git bash 4 | RUN git clone https://github.com/minamijoyo/hcledit; make install -C hcledit 5 | 6 | FROM alpine:latest 7 | RUN apk --no-cache add ca-certificates 8 | WORKDIR /work 9 | COPY --from=0 /go/bin/hcledit /bin 10 | ENTRYPOINT ["bin/sh"] 11 | -------------------------------------------------------------------------------- /hcl/set-cidr-vpc/set-cidr-vpc.batch.yml: -------------------------------------------------------------------------------- 1 | # This batch change is a toy example of using https://github.com/minamijoyo/hcledit to edit Terraform files 2 | # It can be a good alternative of comby for some use cases as it allows to easily select elements to change 3 | # It comes with some limitations and cannot be used to set attributes to objects or lists (https://github.com/minamijoyo/hcledit/issues) 4 | 5 | name: set-cidr_block 6 | description: Set CIDR blocks in aws_vcp resources to some value 7 | 8 | on: 9 | - repositoriesMatchingQuery: lang:HCl aws_vpc count:100 10 | 11 | steps: 12 | - run: echo "Hello world" 13 | container: alpine:3 14 | - run: pwd 15 | container: malomarrec/hcledit:amd64 16 | - run: | 17 | results="${{ join repository.search_result_paths "\n" }}" 18 | for result in $results; do 19 | vpcs=$(hcledit block list -f $result | grep '\.aws_vpc\.') 20 | for vpc in $vpcs; do 21 | hcledit attribute set "${vpc}.cidr_block" '"10.0.1.0/24"' -f $result -u 22 | done 23 | done 24 | container: malomarrec/hcledit:amd64 25 | 26 | changesetTemplate: 27 | title: Set aws_vpc CIDR blocks 28 | body: Set aws_vpc CIDR blocks to some value 29 | branch: batch/set-cidr 30 | commit: 31 | message: Set aws_vpc CIDR blocks to some value 32 | -------------------------------------------------------------------------------- /java/java-openrewrite/gradle.yaml: -------------------------------------------------------------------------------- 1 | name: openrewrite-gradle 2 | description: Add Hello World to READMEs 3 | 4 | on: 5 | # Change this search query to run rewrite on other repositories. For example, 6 | # `file:^gradlew` matches all repositories with a top-level `gradlew` file. 7 | - repositoriesMatchingQuery: repo:apache/poi 8 | 9 | steps: 10 | # Change `org.gradle.jvmargs` option to customize JVM flagw. Useful to increase memory. 11 | - run: ./gradlew --init-script /openrewrite.gradle -Porg.gradle.jvmargs=-Xmx16000m rewriteRun 12 | container: gradle:jdk11 13 | files: 14 | /openrewrite.gradle: | 15 | // Gradle init script that automatically enables the openrewrite plugin 16 | // even if it's not declared in the build. Adapted from the following docs: 17 | // https://docs.openrewrite.org/running-recipes/running-rewrite-on-a-gradle-project-without-modifying-the-build 18 | initscript { 19 | repositories { 20 | mavenCentral() 21 | maven { url "https://plugins.gradle.org/m2" } 22 | } 23 | 24 | dependencies { 25 | classpath("org.openrewrite:plugin:latest.release") 26 | } 27 | } 28 | 29 | addListener(new BuildInfoPluginListener()) 30 | 31 | allprojects { 32 | repositories { 33 | mavenCentral() 34 | } 35 | project.afterEvaluate { 36 | if (!project.plugins.hasPlugin(org.openrewrite.gradle.RewritePlugin)) { 37 | project.plugins.apply(org.openrewrite.gradle.RewritePlugin) 38 | } 39 | } 40 | dependencies { 41 | // (optional) Add custom dependencies, which is needed to run non-builtin recipes. 42 | // rewrite("org.openrewrite:rewrite-java") 43 | // rewrite(platform("org.openrewrite.recipe:rewrite-recipe-bom:1.15.0")) 44 | // rewrite("org.openrewrite.recipe:rewrite-migrate-java") 45 | } 46 | rewrite { 47 | // Change the active recipe below to run something else than OrderImports 48 | activeRecipe("org.openrewrite.java.OrderImports") 49 | } 50 | } 51 | 52 | class BuildInfoPluginListener extends BuildAdapter { 53 | 54 | def void projectsLoaded(Gradle gradle) { 55 | Project root = gradle.getRootProject() 56 | if (!"buildSrc".equals(root.name)) { 57 | root.allprojects { 58 | apply { 59 | apply plugin: org.openrewrite.gradle.RewritePlugin 60 | } 61 | } 62 | } 63 | } 64 | } 65 | 66 | # Describe the changeset (e.g., GitHub pull request) you want for each repository. 67 | changesetTemplate: 68 | title: Reorder imports with Openrewrite 69 | body: This PR shows how to use Batch Changes with Openrewrite and Gradle 70 | commit: 71 | message: Reorder imports 72 | # Optional: Push the commit to a branch named after this batch change by default. 73 | branch: ${{ batch_change.name }} 74 | -------------------------------------------------------------------------------- /java/java-openrewrite/maven.yaml: -------------------------------------------------------------------------------- 1 | name: openrewrite-maven 2 | description: Order imports 3 | 4 | on: 5 | # Change this search query to run rewrite on other repositories. For example, 6 | # `file:^pom.xml` matches all repositories with a top-level `pom.xml` file. 7 | - repositoriesMatchingQuery: repo:java-design-patterns 8 | 9 | steps: 10 | # Change `activeRecipes` value to run another recipe. 11 | - run: mvn org.openrewrite.maven:rewrite-maven-plugin:4.36.0:run -DactiveRecipes=org.openrewrite.java.OrderImports -Dcheckstyle.skip 12 | container: maven:eclipse-temurin 13 | env: 14 | MAVEN_OPTS: -Xmx16000m # Custom Java options. Useful to increase memory. 15 | 16 | # Describe the changeset (e.g., GitHub pull request) you want for each repository. 17 | changesetTemplate: 18 | title: Order Java imports 19 | body: This is demo of how to run the Openrewrite `OrderImports` recipe against a Java codebase 20 | commit: 21 | message: Order imports 22 | # Optional: Push the commit to a branch named after this batch change by default. 23 | branch: ${{ batch_change.name }} -------------------------------------------------------------------------------- /java/remove-catch.batch.yaml: -------------------------------------------------------------------------------- 1 | name: java-remove-catch 2 | description: Find try-catch-finally statements where the catch statement has no body (the catch clause could be omitted) 3 | 4 | on: 5 | - repositoriesMatchingQuery: try {:[a]} catch (:[e]) { } finally {:[b]} lang:java patterntype:structural 6 | 7 | steps: 8 | - run: comby -in-place 'try {:[a]} catch (:[e]) { } finally {:[b]}' 'try {:[a]} finally {:[b]}' ${{ join repository.search_result_paths " " }} 9 | container: comby/comby 10 | 11 | changesetTemplate: 12 | title: Remove empty catch statements 13 | body: Find try-catch-finally statements where the catch statement has no body (the catch clause could be omitted) 14 | branch: batch-changes/remove-catch 15 | commit: 16 | message: remove-catch-statement 17 | published: true 18 | -------------------------------------------------------------------------------- /js-ts/bootstrap-upgrade.batch.yaml: -------------------------------------------------------------------------------- 1 | name: bootstrap-upgrade 2 | description: All our applications should look the same, so we want to make them all use the same version of bootstrap. This batch change opens up a joint-effort to make all those upgrades happen in a short time span. 3 | 4 | on: 5 | - repositoriesMatchingQuery: 'f:package.json "bootstrap": ".?4 patterntype:regexp -r:13k -r:ghe -r:gitlab' 6 | 7 | steps: 8 | - run: | 9 | if [[ $(find . -name yarn.lock | grep -v node_modules) ]]; then 10 | find . -name yarn.lock | grep -v node_modules | xargs -L 1 dirname | xargs -L 1 realpath | xargs -I{} yarn --cwd {} add bootstrap@5.0.0-alpha1 11 | else 12 | find . -name package.json | grep -v node_modules | xargs -L 1 dirname | xargs -L 1 realpath | xargs -I{} cd {} && npm i bootstrap@5.0.0-alpha1 13 | fi 14 | container: node:14.8 15 | 16 | changesetTemplate: 17 | title: Upgrade to bootstrap 5 18 | body: This upgrades the bootstrap version to v5. Please use this PR to make any adjustments, if necessary. It is tracked in a Souregraph batch change. 19 | branch: batch-change/bootstrap-5 20 | commit: 21 | message: Upgrade bootstrap to v5 22 | published: false 23 | -------------------------------------------------------------------------------- /js-ts/colors/batch.yml: -------------------------------------------------------------------------------- 1 | name: pin-colors-3 2 | description: Force colors to use 1.4.0 to avoid vulnerability 3 | 4 | # All package.json to capture transitive dependencies 5 | on: 6 | - repositoriesMatchingQuery: file:package-lock.json colors 7 | 8 | steps: 9 | - run: | 10 | for result in "${{ join repository.search_result_paths " " }}"; do 11 | python /tmp/script "${result}"; 12 | done; 13 | container: python:3-slim 14 | files: 15 | /tmp/script: | 16 | import json 17 | import sys 18 | try: 19 | package = None 20 | files = sys.argv[1] 21 | 22 | # when a repository contains multiple package.json, its file paths get passed as a string separated by 23 | # spaces. We split by a single space to parse every single occurrence. 24 | for file in files.split(' '): 25 | # Look for colors in package-lock to catch transitive dependencies, add resolutions in package.json 26 | file = file.replace('package-lock.json', 'package.json') 27 | 28 | with open(file) as f: 29 | package = json.loads(f.read()) 30 | if 'resolutions' in package: 31 | package['resolutions']['colors']="1.4.0" 32 | else: 33 | package['resolutions'] = {"colors":"1.4.0"} 34 | 35 | with open(file, "w") as f: 36 | f.write(json.dumps(package, indent=2)) 37 | except Exception as e: 38 | print("No-op:error {}".format(e)) 39 | 40 | changesetTemplate: 41 | title: Force colors to use 1.4.0 42 | body: Force colors to use 1.4.0 to avoid infinite loop 43 | branch: colors 44 | published: false 45 | commit: 46 | message: Force colors to use 1.4.0 47 | 48 | -------------------------------------------------------------------------------- /js-ts/eslint-fix/README.md: -------------------------------------------------------------------------------- 1 | # Run `eslint --fix` in repositories with an eslint configuration 2 | 3 | This batch change finds repositories that have either an `.eslint`, an 4 | `.eslintrc.js` or an `eslintrc.json` file at their root. 5 | 6 | It then uses 7 | [`steps.outputs`](https://docs.sourcegraph.com/batch_changes/references/batch_spec_yaml_reference#steps-outputs) 8 | to dynamically construct an output in YAML format. 9 | 10 | Then, in the other two steps, it uses 11 | [`steps.if`](https://docs.sourcegraph.com/batch_changes/references/batch_spec_yaml_reference#steps-if) 12 | combined with [batch spec 13 | templating](https://docs.sourcegraph.com/batch_changes/references/batch_spec_templating) 14 | to conditionally install and run `eslint --fix` either with NPM or with Yarn. 15 | 16 | Using these features here is not necessary, but the batch spec serves as a 17 | practical example of how one could use them and extend their use. See 18 | `eslint-fix.simple.batch.yaml` for a functionally equivalent batch spec that only 19 | uses a single step. 20 | -------------------------------------------------------------------------------- /js-ts/eslint-fix/eslint-fix.batch.yaml: -------------------------------------------------------------------------------- 1 | name: eslint-fix 2 | description: Run `eslint --fix` in repositories with `eslintrc[.js]` files. 3 | 4 | on: 5 | - repositoriesMatchingQuery: file:^.eslintrc[\.js|\.json]? 6 | 7 | steps: 8 | # Dynamically print a YAML object on standard out with information about 9 | # which package manager is used. 10 | # We can use this to execute different steps. 11 | - run: | 12 | echo "usesYarn: $(test -f yarn.lock && echo true || echo false)" && 13 | echo "usesNPM: $(test -f package-lock.json && echo true || echo false)" 14 | container: alpine:3 15 | outputs: 16 | packageManagers: 17 | value: ${{ step.stdout }} 18 | format: yaml 19 | # Use yarn to run eslint --fix if we detected yarn before. 20 | # exit 0 in any case, because we want the fixes, even though there might 21 | # still be warnings/errors. 22 | - run: yarn && yarn run eslint --fix --ext .js,.jsx,.ts,.tsx . || exit 0 23 | if: ${{ outputs.packageManagers.usesYarn }} 24 | container: node:15.0 25 | # Use npm if we detected npm. 26 | - run: | 27 | npm config set package-lock false \ 28 | && npm install \ 29 | && npm run eslint --fix --ext .js,.jsx,.ts,.tsx . || exit 0 30 | if: ${{ outputs.packageManagers.usesNPM }} 31 | container: node:15.0 32 | 33 | changesetTemplate: 34 | title: Run eslint --fix 35 | body: The changes here were produced by running `eslint --fix` 36 | commit: 37 | message: Run `eslint --fix` in the directories 38 | branch: batch-changes/eslint-fix 39 | published: false 40 | -------------------------------------------------------------------------------- /js-ts/eslint-fix/eslint-fix.simple.batch.yaml: -------------------------------------------------------------------------------- 1 | name: eslint-fix 2 | description: Run `eslint --fix` in repositories with `eslintrc[.js]` files. 3 | 4 | on: 5 | - repositoriesMatchingQuery: file:^.eslintrc[\.js|\.json]? 6 | 7 | steps: 8 | # Check whether `yarn.lock` exists and if so, use yarn. Otherwise npm. 9 | - run: | 10 | if [ -f yarn.lock ]; then 11 | yarn && yarn run eslint --fix --ext .js,.jsx,.ts,.tsx . || exit 0 12 | else 13 | npm config set package-lock false \ 14 | && npm install \ 15 | && npm run eslint --fix --ext .js,.jsx,.ts,.tsx . || exit 0 16 | fi 17 | container: node:15.0 18 | 19 | changesetTemplate: 20 | title: Run eslint --fix 21 | body: The changes here were produced by running `eslint --fix` 22 | commit: 23 | message: Run `eslint --fix` in the directories 24 | branch: batch-changes/eslint-fix 25 | published: false 26 | -------------------------------------------------------------------------------- /js-ts/js-codeshift/Dockerfile: -------------------------------------------------------------------------------- 1 | # Container image that runs your code 2 | FROM node:14 3 | 4 | RUN npm install -g jscodeshift 5 | 6 | # As an alternative to defining steps.files in the batch spec, Transform files could be copied into the container. 7 | # COPY warn-to-log.ts /warn-to-log.ts 8 | 9 | # Code file to execute when the docker container starts up (`entrypoint.sh`) 10 | ENTRYPOINT ["bin/sh"] 11 | -------------------------------------------------------------------------------- /js-ts/js-codeshift/README.md: -------------------------------------------------------------------------------- 1 | # Running jscodeshift in Batch Changes 2 | 3 | This batch change is an example of running [jscodeshift](https://github.com/facebook/jscodeshift) in Batch Changes. This toy example simply replaces `console.log` statements by `console.warn` statements. 4 | 5 | ## How to 6 | 7 | The [Transform module](https://github.com/facebook/jscodeshift#transform-module) in `warn-to-log.ts` defines what changes will be executed through the AST-to-AST transform tool. 8 | -------------------------------------------------------------------------------- /js-ts/js-codeshift/warn-to-log.batch.yml: -------------------------------------------------------------------------------- 1 | name: codeshift-demo 2 | description: Replace console.warn by console.log 3 | 4 | # Repositories containing this package 5 | on: 6 | - repositoriesMatchingQuery: console.warn 7 | 8 | steps: 9 | - run: npx jscodeshift -t /warn-to-log.ts . --extensions js,ts --parser=ts 10 | container: malomarrec/codeshift 11 | files: 12 | /warn-to-log.ts: | 13 | export default function transformer(file, api) { 14 | const j = api.jscodeshift; 15 | const root = j(file.source); 16 | const consoleLogCalls = root.find(j.CallExpression, { 17 | callee: { 18 | object: { 19 | name: 'console' 20 | }, 21 | property: { 22 | name: 'warn' 23 | } 24 | } 25 | }); 26 | consoleLogCalls.forEach(p => { 27 | p.node.callee.property.name = 'log'; 28 | }); 29 | return root.toSource(); 30 | }; 31 | 32 | changesetTemplate: 33 | title: Replace console.warn by console.log in .js files 34 | body: Because why not? 35 | branch: batch-changes/warn-to-log # Push the commit to this branch. 36 | commit: 37 | message: js-warn-to-log 38 | published: false 39 | -------------------------------------------------------------------------------- /js-ts/npm-package-update/README.md: -------------------------------------------------------------------------------- 1 | # Updating npm dependencies 2 | 3 | This batch change runs `npm-check-updates` and, if outdated changes are found in the `package.json` file, updates the dependencies to the latest version. 4 | 5 | --- 6 | 7 | ``` 8 | name: npm-update-package.json 9 | description: Use NPM to update dependencies in package.json. 10 | 11 | # NPM Update. 12 | 13 | on: 14 | - repositoriesMatchingQuery: patternType:regexp file:package.json 15 | 16 | # In each repository 17 | steps: 18 | - run: | 19 | npm install -g npm-check-updates 20 | ncu -u 21 | container: node:16-alpine 22 | # Describe the changeset (e.g., GitHub pull request) you want for each repository. 23 | changesetTemplate: 24 | title: Update outdated npm modules 25 | body: Running npm-check-updates 26 | branch: batch-changes/npm-update # Push the commit to this branch. 27 | commit: 28 | message: Updating outdated packages in package.json. 29 | published: false 30 | ``` 31 | -------------------------------------------------------------------------------- /js-ts/npm-package-update/npm-update.yaml: -------------------------------------------------------------------------------- 1 | name: npm-update-package.json 2 | description: Use NPM to update dependencies in package.json. 3 | 4 | # NPM Update. 5 | 6 | on: 7 | - repositoriesMatchingQuery: patternType:regexp file:package.json repo:sourcegraph-testing/docker-image-pin$ 8 | 9 | # In each repository 10 | steps: 11 | - run: | 12 | npm install -g npm-check-updates 13 | ncu -u 14 | container: node:16-alpine 15 | 16 | # Describe the changeset (e.g., GitHub pull request) you want for each repository. 17 | changesetTemplate: 18 | title: Update outdated npm modules 19 | body: Running npm-check-updates 20 | branch: batch-changes/npm-update # Push the commit to this branch. 21 | commit: 22 | message: Updating outdated packages in package.json. 23 | published: false 24 | -------------------------------------------------------------------------------- /js-ts/update-api-query/replace-viewer-configuration.yaml: -------------------------------------------------------------------------------- 1 | name: replace-viewer-configuration.batch.yaml 2 | 3 | description: Updates GraphQL queries using deprecated viewerConfiguration to viewerSettings 4 | 5 | # Search for repositories containing a GraphQL API query using the deprecated viewerConfiguration query 6 | on: 7 | - repositoriesMatchingQuery: repo:github.com/sourcegraph/sourcegraph viewerConfiguration lang:typescript 8 | # In each repository 9 | steps: 10 | # replace the deprecated query with viewerSettings 11 | - run: | 12 | for file in "${{ join repository.search_result_paths " " }}"; 13 | do 14 | sed -i 's/viewerConfiguration/viewerSettings/g;' ${file} 15 | done 16 | container: alpine:3 17 | # Describe the changeset (e.g., GitHub pull request) you want for each repository. 18 | changesetTemplate: 19 | title: Use new `viewerSettings` instead of `viewerConfiguration` 20 | body: This change replaces the deprecated usage of `viewerConfiguration` with `viewerSettings` 21 | branch: batch-change/viewer-settings 22 | commit: 23 | message: Use new `viewerSettings` instead of `viewerConfiguration` 24 | published: false 25 | 26 | -------------------------------------------------------------------------------- /js-ts/update-typescript.workspaces.batch.yaml: -------------------------------------------------------------------------------- 1 | name: update-typescript-monorepo 2 | description: This batch change updates the TypeScript dependency to the latest version 3 | 4 | on: 5 | - repository: github.com/sourcegraph/automation-testing 6 | 7 | workspaces: 8 | - rootAtLocationOf: package.json 9 | in: github.com/sourcegraph/automation-testing 10 | 11 | steps: 12 | - run: npm update typescript 13 | container: node:14 14 | 15 | changesetTemplate: 16 | title: Update TypeScript 17 | body: This updates TypeScript to the latest version 18 | branch: batch-changes/update-typescript-${{ replace steps.path "/" "-" }} 19 | commit: 20 | message: Update TypeScript 21 | published: false 22 | -------------------------------------------------------------------------------- /js-ts/vscode-extension-recommendation/vscode-extension-recommendation.batch.yml: -------------------------------------------------------------------------------- 1 | name: vscode-extension-recommendation-demo 2 | description: Add a VS Code extension to the recommended extensions list 3 | 4 | # Repositories containing this package 5 | on: 6 | - repositoriesMatchingQuery: path:.vscode\/extensions.json$ 7 | 8 | steps: 9 | - run: | 10 | npm root -g 11 | npm install -g jsonc-parser 12 | NODE_PATH=$(npm root -g) node /add-to-recommendations.js ${{repository.search_result_paths}} 13 | container: node:16-alpine 14 | files: 15 | /add-to-recommendations.js: | 16 | const fs = require("fs"); 17 | const path = require("path"); 18 | const { modify, applyEdits, parse } = require("jsonc-parser"); 19 | 20 | const EXTENSION_NAME = "sourcegraph.sourcegraph"; 21 | 22 | const files = process.argv.slice(2); 23 | if (files.length <= 0) { 24 | console.log("Usage:"); 25 | console.log( 26 | "node add-to-recommendations.js app1/.vscode/extension.json app2/.vscode/extension.json" 27 | ); 28 | process.exit(1); 29 | } 30 | 31 | for (let file of files) { 32 | const filepath = path.join(process.cwd(), file); 33 | 34 | const content = fs.readFileSync(filepath, "utf8").toString(); 35 | const parsedContent = parse(content); 36 | 37 | const hasExtension = 38 | Array.isArray(parsedContent.recommendations) && 39 | parsedContent.recommendations.includes(EXTENSION_NAME); 40 | 41 | if (hasExtension) { 42 | console.log(`Extension already recommended in ${file}`); 43 | process.exit(0); 44 | } 45 | 46 | const edit = modify( 47 | content, 48 | ["recommendations", 0], 49 | "sourcegraph.sourcegraph", 50 | { 51 | isArrayInsertion: true, 52 | formattingOptions: { 53 | eol: "\n", 54 | insertSpaces: true, 55 | tabSize: 2, 56 | }, 57 | } 58 | ); 59 | 60 | fs.writeFileSync(filepath, applyEdits(content, edit)); 61 | console.log(`Extension added to recommendations in ${file}`); 62 | } 63 | 64 | changesetTemplate: 65 | title: Add recommended VS Code extension 66 | body: This extension provides a lot of value and we recommend it to all developers. 67 | branch: batch-changes/add-vscode-recommended-extension 68 | commit: 69 | message: Add recommended VS Code extension 70 | -------------------------------------------------------------------------------- /misc/fix-misused-weekyear.batch.yaml: -------------------------------------------------------------------------------- 1 | name: fix-misused-weekyear 2 | description: Update misue of YYYY weekyear for calendar year yyyy. 3 | on: 4 | # Find all repositories that contain references to weekyears 'dd-MMM-YYYY'. 5 | - repositoriesMatchingQuery: repo:sourcegraph-testing dd-MMM-YYYY fork:yes patternType:regexp case:true 6 | # In each repository: 7 | steps: 8 | # we use comby to update the base images with the sha256 suffix 9 | # and use comby to replace the ones without it: 10 | - run: find . -name '*.java' -type f | xargs sed -i 's/dd-MMM-YYYY/dd-MMM-yyyy/g' 11 | container: alpine:3 12 | # Describe the changeset (e.g., GitHub pull request) you want for each repository. 13 | changesetTemplate: 14 | title: Update misue of YYYY weekyear for calendar year yyyy. 15 | body: > 16 | Week year is intended to be used for week dates, eg 2015-W01-1, it is often mistakenly used for calendar dates, in which case the year may be incorrect during the last week of the year 17 | branch: batch-change/fix-misused-weekyear 18 | commit: 19 | message: Update misue of YYYY weekyear for calendar year yyyy. 20 | published: true 21 | -------------------------------------------------------------------------------- /misc/update-language.find-and-ruplacer.batch.yaml: -------------------------------------------------------------------------------- 1 | name: use-allowlist-denylist-wording-ruplacer 2 | description: This batch change updates our Markdown docs to use the terms "allowlist" and "denylist" instead of "whitelist" and "blacklist". 3 | 4 | # Search for repositories in which the term "whitelist" or "blacklist" appears 5 | # in Markdown files. 6 | on: 7 | - repositoriesMatchingQuery: whitelist OR blacklist lang:markdown -file:vendor repo:sourcegraph 8 | 9 | # In each repository 10 | steps: 11 | # find all *.md or *.markdown files, that are not in a vendor or node_modules folder, and replace the terms in them 12 | - run: | 13 | apk add curl \ 14 | && curl -o ruplacer-v0.4.1-linux-x86_64.tar.gz -L 'https://github.com/TankerHQ/ruplacer/releases/download/v0.4.1/ruplacer-v0.4.1-linux-x86_64.tar.gz' \ 15 | && tar xvzf ruplacer-v0.4.1-linux-x86_64.tar.gz \ 16 | && mv ruplacer-v0.4.1-linux-x86_64/ruplacer /usr/local/bin/ruplacer \ 17 | && chmod +x /usr/local/bin/ruplacer \ 18 | && find . -type f \( -name '*.md' -or -name '*.markdown' \) -not -path "*/vendor/*" -not -path "*/node_modules/*" >> /tmp/find_result.txt \ 19 | && cat /tmp/find_result.txt | while read file; 20 | do 21 | ruplacer --subvert whitelist allowlist --go ${file} || echo "nothing to replace"; 22 | ruplacer --subvert blacklist denylist --go ${file} || echo "nothing to replace"; 23 | done 24 | container: alpine:3 25 | 26 | # Describe the changeset (e.g., GitHub pull request) you want for each repository. 27 | changesetTemplate: 28 | title: Replace whitelist/blacklist with allowlist/denylist 29 | body: This replaces the terms whitelist/blacklist in Markdown files with allowlist/denylist 30 | branch: batch-changes/allowlist-denylist # Push the commit to this branch. 31 | commit: 32 | message: Replace whitelist/blacklist with allowlist/denylist 33 | published: false 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /misc/update-language.ruplacer.batch.yaml: -------------------------------------------------------------------------------- 1 | # Step 1: build the `ruplacer` Docker image 2 | # $ cat Dockerfile 3 | # FROM rust 4 | # RUN cargo install ruplacer 5 | # 6 | # $ docker build -t ruplacer . 7 | # 8 | # 9 | # (Why use ruplacer? Because it supports `--subvert` which allows us to 10 | # replace `camelCase`, `snake_case`, `ThisCase`, `nocase`.) 11 | # 12 | # Step 2: use the src-cli prototype with templating support 13 | # 14 | # $ cd src-cli && git fetch && git checkout mrnugget/templates-and-files 15 | # $ go build ./cmd/src -o ~/bin/src 16 | # 17 | # Step 3: update the `repositoriesMatchingQuery` to include or exclude file types. 18 | # 19 | # Step 4: run this batch change 20 | # 21 | # $ src batch preview -f update-language.batch.yaml 22 | name: update-language 23 | description: This batch change changes occurrences of whitelist & blacklist to allowlist & denylist. 24 | 25 | on: 26 | - repositoriesMatchingQuery: whitelist OR blacklist -file:scss$ -file:html$ repo:github.com/sourcegraph 27 | 28 | steps: 29 | - run: | 30 | cat /tmp/search-results | while read file; 31 | do 32 | ruplacer --subvert whitelist allowlist --go ${file} || echo "nothing to replace"; 33 | ruplacer --subvert blacklist denylist --go ${file} || echo "nothing to replace"; 34 | done 35 | container: ruplacer 36 | files: 37 | /tmp/search-results: ${{ join repository.search_result_paths "\n" }} 38 | 39 | # Describe the changeset (e.g., GitHub pull request) you want for each repository. 40 | changesetTemplate: 41 | title: Replace usage of whitelist & blacklist with allowlist & denylist 42 | body: This replaces usages 43 | branch: batch-changes/allowlist-denylist 44 | commit: 45 | message: Use allowlist/denylist in wording 46 | published: false 47 | -------------------------------------------------------------------------------- /misc/update-language.sedspec.yaml: -------------------------------------------------------------------------------- 1 | name: use-allowlist-denylist-wording 2 | description: This batch change updates our Markdown docs to use the terms "allowlist" and "denylist" instead of "whitelist" and "blacklist". 3 | 4 | # Search for repositories in which the term "whitelist" or "blacklist" appears 5 | # in Markdown files. 6 | on: 7 | - repositoriesMatchingQuery: whitelist OR blacklist lang:markdown -file:vendor repo:sourcegraph 8 | 9 | # In each repository 10 | steps: 11 | # find all *.md or *.markdown files, that are not in a vendor or node_modules folder, and replace the terms in them 12 | - run: | 13 | find . -type f \( -name '*.md' -or -name '*.markdown' \) -not -path "*/vendor/*" -not -path "*/node_modules/*" |\ 14 | xargs sed -i 's/whitelist/allowlist/g; s/blacklist/denylist/g' 15 | container: alpine:3 16 | 17 | # Describe the changeset (e.g., GitHub pull request) you want for each repository. 18 | changesetTemplate: 19 | title: Replace whitelist/blacklist with allowlist/denylist 20 | body: This replaces the terms whitelist/blacklist in Markdown files with allowlist/denylist 21 | branch: batch-changes/allowlist-denylist # Push the commit to this branch. 22 | commit: 23 | message: Replace whitelist/blacklist with allowlist/denylist 24 | published: false 25 | -------------------------------------------------------------------------------- /php/introduce-phpstan.batch.yml: -------------------------------------------------------------------------------- 1 | name: Introduce-PHPStan 2 | description: Improve QA tooling by introducing PHPStan 3 | 4 | on: 5 | - repositoriesMatchingQuery: 'repo:has.path(.*\.php$) -repo:has.content(phpstan/phpstan)' 6 | 7 | # In each matched repository: 8 | # - Install PHPStan as a dev dependency 9 | # - Add PHPStan to CI workflow 10 | # - Create PHPStan configuration file 11 | # - Generate baseline file with existing issues (some issues can't be dumped, so CI job may fail even with baseline) 12 | # 13 | # Please keep in mind that it assumes few things (like `src` and `tests` directories in the repo), 14 | # some repositories may require dedicated image to run PHPStan on (additional libs, PHP extensions etc.), 15 | # so in the end it may require additional tweaks for specific repos to work correctly. 16 | # 17 | # See: https://twitter.com/_Codito_/status/1701558793136484401 18 | steps: 19 | - run: | 20 | apt-get update && apt-get install -y zip unzip libzip-dev \ 21 | && docker-php-ext-install zip \ 22 | && curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \ 23 | && composer require --dev --no-plugins phpstan/phpstan \ 24 | && echo -e 'parameters:\n paths:\n - src\n - tests\n level: max' > phpstan.dist.neon \ 25 | && vendor/bin/phpstan --ansi analyse --generate-baseline=phpstan-baseline.php --memory-limit=2G \ 26 | && echo -e '\nincludes:\n - phpstan-baseline.php' >> phpstan.dist.neon \ 27 | && php -r "\$json = json_decode(file_get_contents(__DIR__.'/composer.json'), true); \$json['scripts']['phpstan:check'] = ['Composer\Config::disableProcessTimeout', 'phpstan analyse']; \$json['scripts']['phpstan:baseline'] = '@phpstan:check --generate-baseline=phpstan-baseline.php'; \$json['scripts']['quality-assurance'][] = '@phpstan:check'; \$json['scripts']['qa'] = '@quality-assurance'; \$scripts = \$json['scripts']; ksort(\$scripts); \$json['scripts'] = \$scripts; file_put_contents(__DIR__.'/composer.json', json_encode(\$json, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES));" \ 28 | && echo -e 'phpstan:\n image: php:8.2-cli-alpine\n script:\n - curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer\n - composer update --prefer-dist --no-progress\n - COMPOSER_ALLOW_SUPERUSER=1 composer phpstan:check' >> .gitlab-ci.yml \ 29 | container: php:8.2-cli 30 | 31 | changesetTemplate: 32 | title: 'Introduce PHPStan' 33 | body: Introduce PHPStan to the project and dump existing problems to baseline file. 34 | commit: 35 | message: Introduce PHPStan 36 | branch: batch-changes/introduce-phpstan 37 | -------------------------------------------------------------------------------- /python/python-refactor/README.md: -------------------------------------------------------------------------------- 1 | # Refactoring Python 2 code to Python 3 with 2to3 2 | This batch change is an example of how to use `2to3` to refactor Python 2 code into Python 3. The Python docs have [more information on 2to3](https://docs.python.org/3/library/2to3.html). This will: 3 | 4 | - Find repositories using Python 2-style print statments, with Python-language files in them. 5 | - Install `2to3` in the container. 6 | - Run `2to3` on the respositories that Sourcegraph finds. 7 | 8 | ## How to 9 | - If running this issue on your own code, you may want to adjust the `repositoriesMatchingQuery` to just look for repositories containing Python code, rather than using the Python 2-style print statement as an indicator of Python 2 code. You may also want to adjust the repository exclusions (`-repo:python-language-server -repo:ctags`) to meet your needs, and may wish to exclude forks by removing `fork:yes`. 10 | -------------------------------------------------------------------------------- /python/python-refactor/python-refactor.yaml: -------------------------------------------------------------------------------- 1 | name: python-refactor 2 | description: Python 2 to 3. 3 | 4 | # Python 2 to 3. 5 | 6 | on: 7 | - repositoriesMatchingQuery: lang:python print ":[string]" -repo:python-language-server -repo:ctags fork:yes patternType:structural 8 | 9 | # In each repository 10 | steps: 11 | - run: | 12 | pip install 2to3 13 | 2to3 -w . 14 | container: python:3-slim 15 | 16 | # Describe the changeset (e.g., GitHub pull request) you want for each repository. 17 | changesetTemplate: 18 | title: Python conversion 19 | body: Moving to Python 3 20 | branch: batch-changes/python-convert # Push the commit to this branch. 21 | commit: 22 | message: Moving Python 2 to Python 3. 23 | published: false 24 | -------------------------------------------------------------------------------- /semgrep/README.md: -------------------------------------------------------------------------------- 1 | Run [semgrep autofix](https://semgrep.dev/docs/experiments/overview/#autofix) (experimental) on multiple (toy) repositories using Batch Changes. Track all resulting changesets, all from a single dashboard. 2 | 3 | Screenshot 2021-10-05 at 11 06 56 4 | -------------------------------------------------------------------------------- /semgrep/semgrep.batch.yaml: -------------------------------------------------------------------------------- 1 | name: run-semgrep 2 | description: Run semgrep autofix on vulnerable test projects 3 | 4 | on: 5 | # Running on a named list of repositories. Use repositoriesMatchingQuery to use a search 6 | - repository: github.com/juice-shop/juice-shop 7 | - repository: github.com/we45/Vulnerable-Flask-App 8 | - repository: github.com/dineshshetty/Android-InsecureBankv2 9 | 10 | steps: # repositories are cloned and available at /work 11 | - run: semgrep --config p/security-audit --autofix /work 12 | container: returntocorp/semgrep 13 | 14 | changesetTemplate: 15 | title: Run semgrep autofix 16 | body: Runs semgprep autofix 17 | branch: semgrep-autofix 18 | commit: 19 | message: run semgrep autofix 20 | 21 | # Change published to true once you're ready to create changesets on the code host. 22 | published: false 23 | -------------------------------------------------------------------------------- /ticketing-systems/github-issues/Dockerfile: -------------------------------------------------------------------------------- 1 | # Container image that runs your code 2 | FROM python:3.6-rc-alpine 3 | 4 | RUN pip install requests 5 | 6 | # Copies your code file from your action repository to the filesystem path `/` of the container 7 | COPY sync-issue.py /sync-issue.py 8 | 9 | # Code file to execute when the docker container starts up (`entrypoint.sh`) 10 | ENTRYPOINT ["python","sync-issue.py"] 11 | -------------------------------------------------------------------------------- /ticketing-systems/github-issues/README.md: -------------------------------------------------------------------------------- 1 | # Creating and updating GitHub issues along with batch changes 2 | This batch change is an example of how to create tickets alongside changesets. 3 | It will: 4 | 5 | - Find repositories with `fmt.Sprintf` 6 | - Open changesets to replace them with `strconv.Itoa` 7 | - For each open changeset, create a GH issue mentioning the files that have been modified 8 | 9 | When reapplying the spec, it will 10 | - first check for existing issues matching the changes and update them if they exist 11 | - otherwise create new issues 12 | 13 | It demonstrates how to use [steps.outputs](https://docs.sourcegraph.com/batch_changes/references/batch_spec_yaml_reference#steps-outputs) and [batch spec templating](https://docs.sourcegraph.com/batch_changes/references/batch_spec_templating). 14 | 15 | 16 | **Note**: by convention, all the issues tracked by this script must be named `batch-change/`. In this example `batch-change/refactor-go-gh-issue` 17 | 18 | ## How to 19 | - Modify the `gh_username` flag with your own in `gh-issues.batch.yml` 20 | - Create a [GitHub Personal Access Token](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) and set it as the `GH_TOKEN` environment variable. 21 | 22 | ```bash 23 | export GH_TOKEN=mysecrettoken 24 | src batch apply -f gh.issues.batch.yml 25 | ``` 26 | 27 | ## Getting to know Batch Changes 28 | 29 | This spec uses batch spec templating to produce text values inserted in the spec at runtime. They are delimited by `${{` and `}}`. 30 | For example, one of the batch changes step passes the name of the batch change, to create a corresponding issue. Using the 31 | `${{batch_change.name}}` statement allows for it to be dynamically read from the spec name, instead of hard coded. 32 | 33 | ``` 34 | name: refactor-go-gh-issue 35 | 36 | steps: 37 | ... 38 | - run: > 39 | python ../sync-issue.py 40 | ... 41 | # no need to hardcode the batch change name twice! 42 | --batch_change_name ${{batch_change.name}} 43 | ... 44 | ``` 45 | 46 | ## Limitations 47 | * For each changeset, the script will load all the issues in the repository affected by the changeset. That is inefficient, and a way better solution would be to maintain an index of all batch changes associated issues. 48 | * This does not work in a monorepo as it assumes that there is only one issue matching a given batch change in any given repository. 49 | -------------------------------------------------------------------------------- /ticketing-systems/github-issues/gh-issues.batch.yml: -------------------------------------------------------------------------------- 1 | name: refactor-go-gh-issue 2 | description: | 3 | This batch change creates Jira tickets for each repository where fmt.Sprintf is replaced by strconv.Itoa. 4 | It also keeps the tickets updated when the batch change is re-applied. 5 | on: 6 | - repository: github.com/sourcegraph-testing/tiny-go-test-repository 7 | 8 | steps: 9 | - run: comby -in-place 'fmt.Sprintf("%d", :[v])' 'strconv.Itoa(:[v])' ${{ join repository.search_result_paths " " }} 10 | container: comby/comby 11 | # This run step uses batch change templating statements to dynamically generate text 12 | # The ${{ previous_step.modified_files }} generates the list of files modified by the comby step above 13 | - run: > 14 | python ../sync-issue.py 15 | --repository ${{repository.name}} 16 | --batch_change_name ${{batch_change.name}} 17 | --description 'Modify ${{ previous_step.modified_files }}' 18 | --gh_username malomarrec 19 | --gh_token $GH_TOKEN 20 | --labels batch-change batch change1 21 | --reopen 22 | container: malomarrec/src-gh-issue:latest 23 | env: 24 | - GH_TOKEN 25 | outputs: 26 | issueLink: 27 | value: ${{step.stdout}} 28 | 29 | changesetTemplate: 30 | title: Replace fmt.Sprintf with equivalent strconv.Itoa 31 | body: | 32 | Linked issue: ${{outputs.issueLink}} 33 | branch: batch-change/sprintf-to-itoa 34 | commit: 35 | message: Replacing fmt.Sprintf with strconv.Iota 36 | published: false 37 | -------------------------------------------------------------------------------- /ticketing-systems/github-issues/sync-issue.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from requests.auth import HTTPBasicAuth 3 | import json 4 | import argparse 5 | 6 | parser = argparse.ArgumentParser(description='Parse GH issue instructions') 7 | parser.add_argument("--repository", help="the GitHub repository where the issue will live", required=True) 8 | parser.add_argument("--batch_change_name", help="the name of the batch_change the issue is created from", required=True) 9 | parser.add_argument("--description", help="the issue description text", required=True) 10 | parser.add_argument("--reopen", dest='reopen', action='store_true', help="reopen closed issues matching the change. Defaults to False.") 11 | parser.add_argument( 12 | "--labels", 13 | nargs="*", 14 | type=str, 15 | default=[], 16 | help="(optional) a list of labels, space is the separator, eg. --labels label1 label2 label3" 17 | ) 18 | parser.add_argument("--gh_username", help="GitHub username", required=True ) 19 | parser.add_argument("--gh_token", help="GitHub PAT or machine access token, with push scope", required=True) 20 | parser.set_defaults(reopen=False) 21 | args = parser.parse_args() 22 | 23 | repository = args.repository 24 | batch_change_name = args.batch_change_name 25 | description = args.description 26 | reopen = args.reopen 27 | labels = args.labels 28 | GH_USERNAME = args.gh_username 29 | GH_TOKEN = args.gh_token 30 | 31 | URL = "https://api.github.com/repos/" 32 | 33 | # Cut prefix if exist 34 | if "github.com/" in repository: 35 | repository=repository[11:] 36 | 37 | def check_for_issue(repository, batch_change_name): 38 | """Check if an issue corresponding to the batch change exists in a repository. 39 | By convention issues associated with a batch change need to be named 'batch-change/batch_change_name'. 40 | Returns the id of the issue, or 0 if there is no matching issue. 41 | Expects repository to be "owner/repo_name". 42 | """ 43 | 44 | session = requests.Session() 45 | session.auth = (GH_USERNAME, GH_TOKEN) 46 | 47 | repo_url = URL + repository + "/issues?per_page=100" 48 | if reopen: 49 | repo_url += "&state=all" 50 | 51 | res = session.get(repo_url) 52 | issues=res.json() 53 | 54 | if res.status_code == 401 or res.status_code == 404: 55 | raise Exception("Not authenticated. Did you set a GH_TOKEN environment variable with your PAT") 56 | 57 | while 'next' in res.links.keys(): 58 | res=session.get(res.links['next']['url']) 59 | issues.extend(res.json()) 60 | 61 | for issue in issues: 62 | if issue["title"] == "batch-change/"+batch_change_name: 63 | return issue["number"] 64 | return 0 65 | 66 | def create_issue(repository, batch_change_name, description, labels): 67 | """Create an issue for the batch change. 68 | By convention issues associated with a batch change need to be named 'batch-change/batch_change_name'. 69 | """ 70 | repo_url = URL + repository + "/issues" 71 | auth = HTTPBasicAuth(GH_USERNAME, GH_TOKEN) 72 | 73 | headers = { 74 | "Accept": "application/json", 75 | "Content-Type": "application/json" 76 | } 77 | 78 | payload = { 79 | "title": "batch-change/" + batch_change_name, 80 | "body": description, 81 | } 82 | 83 | if len(labels) > 0: 84 | payload["labels"] = labels 85 | 86 | payload = json.dumps(payload) 87 | 88 | response = requests.request( 89 | "POST", 90 | repo_url, 91 | data=payload, 92 | headers=headers, 93 | auth=auth 94 | ) 95 | issue_number = json.loads(response.content.decode('utf-8'))["number"] 96 | print("https://github.com/"+repository+"/issues/"+str(issue_number)) 97 | 98 | def update_issue(repository, issue_id, description, label = []): 99 | """ Update an issue with a new description, and optionally label 100 | """ 101 | repo_url = URL + repository + "/issues/" + str(issue_id) 102 | auth = HTTPBasicAuth(GH_USERNAME, GH_TOKEN) 103 | 104 | headers = { 105 | "Accept": "application/json", 106 | "Content-Type": "application/json" 107 | } 108 | 109 | payload = { 110 | "body": description, 111 | "state": "open" 112 | } 113 | 114 | if len(labels) > 0: 115 | payload["labels"] = labels 116 | 117 | payload = json.dumps(payload) 118 | 119 | response = requests.request( 120 | "PATCH", 121 | repo_url, 122 | data=payload, 123 | headers=headers, 124 | auth=auth 125 | ) 126 | 127 | issue_number = json.loads(response.content.decode('utf-8'))["number"] 128 | print("https://github.com/"+repository+"/issues/"+str(issue_number)) 129 | 130 | if __name__ == "__main__": 131 | issue_id = check_for_issue(repository, batch_change_name) 132 | if issue_id == 0: 133 | create_issue(repository, batch_change_name, description, labels) 134 | else: 135 | update_issue(repository, issue_id, description, labels) 136 | -------------------------------------------------------------------------------- /ticketing-systems/jira-tickets/Dockerfile: -------------------------------------------------------------------------------- 1 | # Container image that runs your code 2 | FROM python:3.6-rc-alpine 3 | 4 | 5 | RUN pip install requests 6 | 7 | 8 | # Copies your code file from your action repository to the filesystem path `/` of the container 9 | COPY create-jira.py /create-jira.py 10 | 11 | # Code file to execute when the docker container starts up (`entrypoint.sh`) 12 | ENTRYPOINT ["python","create-jira.py"] 13 | -------------------------------------------------------------------------------- /ticketing-systems/jira-tickets/README.md: -------------------------------------------------------------------------------- 1 | # Creating Jira tickets from batch changes 2 | 3 | This batch change is an example of how to create tickets alongside changes in batch changes. 4 | It will: 5 | 6 | - Find repositories with `fmt.Sprintf` 7 | - Open changesets to replace them with `strconv.Itoa` 8 | - For each open changeset, create a Jira ticket mentioning the files that have been modified 9 | 10 | It demonstrates how to use [steps.outputs](https://docs.sourcegraph.com/batch_changes/references/batch_spec_yaml_reference#steps-outputs) and [batch spec templating](https://docs.sourcegraph.com/batch_changes/references/batch_spec_templating). 11 | 12 | ## How to use 13 | - Modify the `jira_project`, `jira_username`, `jira_sitename` flags with your own in `jira.batch.yml` 14 | - Create a [JIRA API token](https://developer.atlassian.com/cloud/jira/platform/basic-auth-for-rest-apis/) and set it as the `JIRA_TOKEN` environment variable. 15 | 16 | ```bash 17 | JIRA_TOKEN=mysecrettoken 18 | src batch apply -f jira.batch.yaml 19 | ``` 20 | 21 | ## Limitations 22 | * Batch changes has a declarative syntax for code changes: if the state of the codebase has not changed between two runs, there will be no additional changesets created. 23 | * It's up to the user to make sure that the steps the batch change runs are declarative. 24 | * In this simple example, tickets are not "declarative": every time that the batch change runs, and changesets are created or updated, a new ticket will be created (instead of tickets being updated). 25 | -------------------------------------------------------------------------------- /ticketing-systems/jira-tickets/create-jira.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from requests.auth import HTTPBasicAuth 3 | import json 4 | import argparse 5 | 6 | parser = argparse.ArgumentParser(description='Parse jira ticket attributes') 7 | parser.add_argument("--summary", help="summary of the issue to be created", default="") 8 | parser.add_argument("--description", help="description of the issue to be created", default="") 9 | parser.add_argument("--batch change_name", help="description of the issue to be created", default="") 10 | parser.add_argument("--jira_sitename", help="Name of your site. Can be found in the site URL https://.atlassian.net/", required=True) 11 | parser.add_argument("--jira_username", help="Jira email address", required=True) 12 | parser.add_argument("--jira_token", help="Jira API token. ", required=True) 13 | parser.add_argument("--jira_project", help="The project key where issues will be created. Eg. 'MP' ", required=True) 14 | args = parser.parse_args() 15 | 16 | url = "https://" + args.jira_sitename + ".atlassian.net/rest/api/3/issue/" 17 | 18 | auth = HTTPBasicAuth(args.jira_username, args.jira_token) 19 | 20 | headers = { 21 | "Accept": "application/json", 22 | "Content-Type": "application/json" 23 | } 24 | 25 | payload = { 26 | "update": {}, 27 | "fields": { 28 | "summary": args.summary, 29 | "issuetype": { 30 | "id": "10000" 31 | }, 32 | "project": { 33 | "id": "10000" 34 | }, 35 | "customfield_10011": "go_refactor", 36 | "description": { 37 | "type": "doc", 38 | "version": 1, 39 | "content": [ 40 | { 41 | "type": "paragraph", 42 | "content": [ 43 | { 44 | "text": args.description, 45 | "type": "text" 46 | } 47 | ] 48 | } 49 | ] 50 | }, 51 | "labels": [ 52 | "sourcegraph-batch changes", 53 | ], 54 | } 55 | } 56 | 57 | 58 | if len(args.batch change_name) > 0: 59 | payload['fields']['labels'].append(args.batch change_name) 60 | 61 | payload = json.dumps(payload) 62 | 63 | 64 | 65 | 66 | response = requests.request( 67 | "POST", 68 | url, 69 | data=payload, 70 | headers=headers, 71 | auth=auth 72 | ) 73 | 74 | try: 75 | issue = json.loads(response.text)["key"] 76 | link = "https://"+args.jira_sitename+".atlassian.net/secure/RapidBoard.jspa?rapidView=1&modal=detail&projectKey="+args.jira_project+"&selectedIssue="+issue 77 | print(link) 78 | except: 79 | print(json.dumps(json.loads(response.text), sort_keys=True, indent=4, separators=(",", ": "))) 80 | -------------------------------------------------------------------------------- /ticketing-systems/jira-tickets/jira.campaign.yml: -------------------------------------------------------------------------------- 1 | name: refactor-go-jira 2 | description: | 3 | This batch change creates Jira tickets for each repository where fmt.Sprintf is replaced by strconv.Itoa. 4 | on: 5 | - repository: github.com/sourcegraph-testing/tiny-go-test-repository 6 | 7 | steps: 8 | - run: comby -in-place 'fmt.Sprintf("%d", :[v])' 'strconv.Itoa(:[v])' .go -matcher .go -exclude-dir .,vendor; echo "issue" 9 | container: comby/comby 10 | - run: > 11 | python ../create-jira.py 12 | --summary 'Update ${{repository.name}}' 13 | --description 'Modify ${{ previous_step.modified_files }}' 14 | --batch change_name "reactor-go-jira" 15 | --jira_sitename mmgcn 16 | --jira_username mm@getcloudnative.fr 17 | --jira_token $JIRA_TOKEN 18 | --jira_project MP 19 | container: malomarrec/src-py-jira:latest 20 | env: 21 | - JIRA_TOKEN 22 | outputs: 23 | issueLink: 24 | value: ${{step.stdout}} 25 | 26 | changesetTemplate: 27 | title: Replace fmt.Sprintf with equivalent strconv.Itoa 28 | body: | 29 | Linked issue: ${{outputs.issueLink}} 30 | branch: batch-changes/sprintf-to-itoa 31 | commit: 32 | message: Replacing fmt.Sprintf with strconv.Iota 33 | published: false 34 | -------------------------------------------------------------------------------- /ticketing-systems/track-important-milestone.batch.yaml: -------------------------------------------------------------------------------- 1 | name: track-important-milestone 2 | description: Track all changesets related to our important batch changes milestone 3 | 4 | importChangesets: 5 | - repository: github.com/sourcegraph/sourcegraph 6 | externalIDs: [15397, 15590, 15597, 15583, 15806, 15798] 7 | - repository: github.com/sourcegraph/src-cli 8 | externalIDs: [378, 373, 374, 369, 368, 361, 380] 9 | -------------------------------------------------------------------------------- /ticketing-systems/track-many-issues/README.md: -------------------------------------------------------------------------------- 1 | # Track many existing issues with Batch Changes 2 | 3 | Batch Changes can be used to track existing changesets, by listing their id in the batch change. 4 | 5 | 6 | -------------------------------------------------------------------------------- /ticketing-systems/track-many-issues/track.batch.yml: -------------------------------------------------------------------------------- 1 | name: track-many-issues 2 | description: Track all changesets in sourcegraph/sourcegraph, since changeset 10000. 3 | 4 | importChangesets: 5 | - repository: github.com/sourcegraph/sourcegraph 6 | externalIDs: [10000, 10001, 10002, 10003, 10004, 10005, 10006, 10007, 10008, 10009, 10010, 10011, 10012, 10013, 10014, 10015, 10016, 10017, 10018, 10019, 10020, 10021, 10022, 10023, 10024, 10025, 10026, 10027, 10028, 10029, 10030, 10031, 10032, 10033, 10034, 10035, 10036, 10037, 10038, 10039, 10040, 10041, 10042, 10043, 10044, 10045, 10046, 10047, 10048, 10049, 10050, 10051, 10052, 10053, 10054, 10055, 10056, 10057, 10058, 10059, 10060, 10061, 10062, 10063, 10064, 10065, 10066, 10067, 10068, 10069, 10070, 10071, 10072, 10073, 10074, 10075, 10076, 10077, 10078, 10079, 10080, 10081, 10082, 10083, 10084, 10085, 10086, 10087, 10088, 10089, 10090, 10091, 10092, 10093, 10094, 10095, 10096, 10097, 10098, 10099, 10100, 10101, 10102, 10103, 10104, 10105, 10106, 10107, 10108, 10109, 10110, 10111, 10112, 10113, 10114, 10115, 10116, 10117, 10118, 10119, 10120, 10121, 10122, 10123, 10124, 10125, 10126, 10127, 10128, 10129, 10130, 10131, 10132, 10133, 10134, 10135, 10136, 10137, 10138, 10139, 10140, 10141, 10142, 10143, 10144, 10145, 10146, 10147, 10148, 10149, 10150, 10151, 10152, 10153, 10154, 10155, 10156, 10157, 10158, 10159, 10160, 10161, 10162, 10163, 10164, 10165, 10166, 10167, 10168, 10169, 10170, 10171, 10172, 10173, 10174, 10175, 10176, 10177, 10178, 10179, 10180, 10181, 10182, 10183, 10184, 10185, 10186, 10187, 10188, 10189, 10190, 10191, 10192, 10193, 10194, 10195, 10196, 10197, 10198, 10199, 10200, 10201, 10202, 10203, 10204, 10205, 10206, 10207, 10208, 10209, 10210, 10211, 10212, 10213, 10214, 10215, 10216, 10217, 10218, 10219, 10220, 10221, 10222, 10223, 10224, 10225, 10226, 10227, 10228, 10229, 10230, 10231, 10232, 10233, 10234, 10235, 10236, 10237, 10238, 10239, 10240, 10241, 10242, 10243, 10244, 10245, 10246, 10247, 10248, 10249, 10250, 10251, 10252, 10253, 10254, 10255, 10256, 10257, 10258, 10259, 10260, 10261, 10262, 10263, 10264, 10265, 10266, 10267, 10268, 10269, 10270, 10271, 10272, 10273, 10274, 10275, 10276, 10277, 10278, 10279, 10280, 10281, 10282, 10283, 10284, 10285, 10286, 10287, 10288, 10289, 10290, 10291, 10292, 10293, 10294, 10295, 10296, 10297, 10298, 10299, 10300, 10301, 10302, 10303, 10304, 10305, 10306, 10307, 10308, 10309, 10310, 10311, 10312, 10313, 10314, 10315, 10316, 10317, 10318, 10319, 10320, 10321, 10322, 10323, 10324, 10325, 10326, 10327, 10328, 10329, 10330, 10331, 10332, 10333, 10334, 10335, 10336, 10337, 10338, 10339, 10340, 10341, 10342, 10343, 10344, 10345, 10346, 10347, 10348, 10349, 10350, 10351, 10352, 10353, 10354, 10355, 10356, 10357, 10358, 10359, 10360, 10361, 10362, 10363, 10364, 10365, 10366, 10367, 10368, 10369, 10370, 10371, 10372, 10373, 10374, 10375, 10376, 10377, 10378, 10379, 10380, 10381, 10382, 10383, 10384, 10385, 10386, 10387, 10388, 10389, 10390, 10391, 10392, 10393, 10394, 10395, 10396, 10397, 10398, 10399, 10400, 10401, 10402, 10403, 10404, 10405, 10406, 10407, 10408, 10409, 10410, 10411, 10412, 10413, 10414, 10415, 10416, 10417, 10418, 10419, 10420, 10421, 10422, 10423, 10424, 10425, 10426, 10427, 10428, 10429, 10430, 10431, 10432, 10433, 10434, 10435, 10436, 10437, 10438, 10439, 10440, 10441, 10442, 10443, 10444, 10445, 10446, 10447, 10448, 10449, 10450, 10451, 10452, 10453, 10454, 10455, 10456, 10457, 10458, 10459, 10460, 10461, 10462, 10463, 10464, 10465, 10466, 10467, 10468, 10469, 10470, 10471, 10472, 10473, 10474, 10475, 10476, 10477, 10478, 10479, 10480, 10481, 10482, 10483, 10484, 10485, 10486, 10487, 10488, 10489, 10490, 10491, 10492, 10493, 10494, 10495, 10496, 10497, 10498, 10499, 10500, 10501, 10502, 10503, 10504, 10505, 10506, 10507, 10508, 10509, 10510, 10511, 10512, 10513, 10514, 10515, 10516, 10517, 10518, 10519, 10520, 10521, 10522, 10523, 10524, 10525, 10526, 10527, 10528, 10529, 10530, 10531, 10532, 10533, 10534, 10535, 10536, 10537, 10538, 10539, 10540, 10541, 10542, 10543, 10544, 10545, 10546, 10547, 10548, 10549, 10550, 10551, 10552, 10553, 10554, 10555, 10556, 10557, 10558, 10559, 10560, 10561, 10562, 10563, 10564, 10565, 10566, 10567, 10568, 10569, 10570, 10571, 10572, 10573, 10574, 10575, 10576, 10577, 10578, 10579, 10580, 10581, 10582, 10583, 10584, 10585, 10586, 10587, 10588, 10589, 10590, 10591, 10592, 10593, 10594, 10595, 10596, 10597, 10598, 10599, 10600, 10601, 10602, 10603, 10604, 10605, 10606, 10607, 10608, 10609, 10610, 10611, 10612, 10613, 10614, 10615, 10616, 10617, 10618, 10619, 10620, 10621, 10622, 10623, 10624, 10625, 10626, 10627, 10628, 10629, 10630, 10631, 10632, 10633, 10634, 10635, 10636, 10637, 10638, 10639, 10640, 10641, 10642, 10643, 10644, 10645, 10646, 10647, 10648, 10649, 10650, 10651, 10652, 10653, 10654, 10655, 10656, 10657, 10658, 10659, 10660, 10661, 10662, 10663, 10664, 10665, 10666, 10667, 10668, 10669, 10670, 10671, 10672, 10673, 10674, 10675, 10676, 10677, 10678, 10679, 10680, 10681, 10682, 10683, 10684, 10685, 10686, 10687, 10688, 10689, 10690, 10691, 10692, 10693, 10694, 10695, 10696, 10697, 10698, 10699, 10700, 10701, 10702, 10703, 10704, 10705, 10706, 10707, 10708, 10709, 10710, 10711, 10712, 10713, 10714, 10715, 10716, 10717, 10718, 10719, 10720, 10721, 10722, 10723, 10724, 10725, 10726, 10727, 10728, 10729, 10730, 10731, 10732, 10733, 10734, 10735, 10736, 10737, 10738, 10739, 10740, 10741, 10742, 10743, 10744, 10745, 10746, 10747, 10748, 10749, 10750, 10751, 10752, 10753, 10754, 10755, 10756, 10757, 10758, 10759, 10760, 10761, 10762, 10763, 10764, 10765, 10766, 10767, 10768, 10769, 10770, 10771, 10772, 10773, 10774, 10775, 10776, 10777, 10778, 10779, 10780, 10781, 10782, 10783, 10784, 10785, 10786, 10787, 10788, 10789, 10790, 10791, 10792, 10793, 10794, 10795, 10796, 10797, 10798, 10799, 10800, 10801, 10802, 10803, 10804, 10805, 10806, 10807, 10808, 10809, 10810, 10811, 10812, 10813, 10814, 10815, 10816, 10817, 10818, 10819, 10820, 10821, 10822, 10823, 10824, 10825, 10826, 10827, 10828, 10829, 10830, 10831, 10832, 10833, 10834, 10835, 10836, 10837, 10838, 10839, 10840, 10841, 10842, 10843, 10844, 10845, 10846, 10847, 10848, 10849, 10850, 10851, 10852, 10853, 10854, 10855, 10856, 10857, 10858, 10859, 10860, 10861, 10862, 10863, 10864, 10865, 10866, 10867, 10868, 10869, 10870, 10871, 10872, 10873, 10874, 10875, 10876, 10877, 10878, 10879, 10880, 10881, 10882, 10883, 10884, 10885, 10886, 10887, 10888, 10889, 10890, 10891, 10892, 10893, 10894, 10895, 10896, 10897, 10898, 10899, 10900, 10901, 10902, 10903, 10904, 10905, 10906, 10907, 10908, 10909, 10910, 10911, 10912, 10913, 10914, 10915, 10916, 10917, 10918, 10919, 10920, 10921, 10922, 10923, 10924, 10925, 10926, 10927, 10928, 10929, 10930, 10931, 10932, 10933, 10934, 10935, 10936, 10937, 10938, 10939, 10940, 10941, 10942, 10943, 10944, 10945, 10946, 10947, 10948, 10949, 10950, 10951, 10952, 10953, 10954, 10955, 10956, 10957, 10958, 10959, 10960, 10961, 10962, 10963, 10964, 10965, 10966, 10967, 10968, 10969, 10970, 10971, 10972, 10973, 10974, 10975, 10976, 10977, 10978, 10979, 10980, 10981, 10982, 10983, 10984, 10985, 10986, 10987, 10988, 10989, 10990, 10991, 10992, 10993, 10994, 10995, 10996, 10997, 10998, 10999, 11000, 11001, 11002, 11003, 11004, 11005, 11006, 11007, 11008, 11009, 11010, 11011, 11012, 11013, 11014, 11015, 11016, 11017, 11018, 11019, 11020, 11021, 11022, 11023, 11024, 11025, 11026, 11027, 11028, 11029, 11030, 11031, 11032, 11033, 11034, 11035, 11036, 11037, 11038, 11039, 11040, 11041, 11042, 11043, 11044, 11045, 11046, 11047, 11048, 11049, 11050, 11051, 11052, 11053, 11054, 11055, 11056, 11057, 11058, 11059, 11060, 11061, 11062, 11063, 11064, 11065, 11066, 11067, 11068, 11069, 11070, 11071, 11072, 11073, 11074, 11075, 11076, 11077, 11078, 11079, 11080, 11081, 11082, 11083, 11084, 11085, 11086, 11087, 11088, 11089, 11090, 11091, 11092, 11093, 11094, 11095, 11096, 11097, 11098, 11099, 11100, 11101, 11102, 11103, 11104, 11105, 11106, 11107, 11108, 11109, 11110, 11111, 11112, 11113, 11114, 11115, 11116, 11117, 11118, 11119, 11120, 11121, 11122, 11123, 11124, 11125, 11126, 11127, 11128, 11129, 11130, 11131, 11132, 11133, 11134, 11135, 11136, 11137, 11138, 11139, 11140, 11141, 11142, 11143, 11144, 11145, 11146, 11147, 11148, 11149, 11150, 11151, 11152, 11153, 11154, 11155, 11156, 11157, 11158, 11159, 11160, 11161, 11162, 11163, 11164, 11165, 11166, 11167, 11168, 11169, 11170, 11171, 11172, 11173, 11174, 11175, 11176, 11177, 11178, 11179, 11180, 11181, 11182, 11183, 11184, 11185, 11186, 11187, 11188, 11189, 11190, 11191, 11192, 11193, 11194, 11195, 11196, 11197, 11198, 11199, 11200, 11201, 11202, 11203, 11204, 11205, 11206, 11207, 11208, 11209, 11210, 11211, 11212, 11213, 11214, 11215, 11216, 11217, 11218, 11219, 11220, 11221, 11222, 11223, 11224, 11225, 11226, 11227, 11228, 11229, 11230, 11231, 11232, 11233, 11234, 11235, 11236, 11237, 11238, 11239, 11240, 11241, 11242, 11243, 11244, 11245, 11246, 11247, 11248, 11249, 11250, 11251, 11252, 11253, 11254, 11255, 11256, 11257, 11258, 11259, 11260, 11261, 11262, 11263, 11264, 11265, 11266, 11267, 11268, 11269, 11270, 11271, 11272, 11273, 11274, 11275, 11276, 11277, 11278, 11279, 11280, 11281, 11282, 11283, 11284, 11285, 11286, 11287, 11288, 11289, 11290, 11291, 11292, 11293, 11294, 11295, 11296, 11297, 11298, 11299, 11300, 11301, 11302, 11303, 11304, 11305, 11306, 11307, 11308, 11309, 11310, 11311, 11312, 11313, 11314, 11315, 11316, 11317, 11318, 11319, 11320, 11321, 11322, 11323, 11324, 11325, 11326, 11327, 11328, 11329, 11330, 11331, 11332, 11333, 11334, 11335, 11336, 11337, 11338, 11339, 11340, 11341, 11342, 11343, 11344, 11345, 11346, 11347, 11348, 11349, 11350, 11351, 11352, 11353, 11354, 11355, 11356, 11357, 11358, 11359, 11360, 11361, 11362, 11363, 11364, 11365, 11366, 11367, 11368, 11369, 11370, 11371, 11372, 11373, 11374, 11375, 11376, 11377, 11378, 11379, 11380, 11381, 11382, 11383, 11384, 11385, 11386, 11387, 11388, 11389, 11390, 11391, 11392, 11393, 11394, 11395, 11396, 11397, 11398, 11399, 11400, 11401, 11402, 11403, 11404, 11405, 11406, 11407, 11408, 11409, 11410, 11411, 11412, 11413, 11414, 11415, 11416, 11417, 11418, 11419, 11420, 11421, 11422, 11423, 11424, 11425, 11426, 11427, 11428, 11429, 11430, 11431, 11432, 11433, 11434, 11435, 11436, 11437, 11438, 11439, 11440, 11441, 11442, 11443, 11444, 11445, 11446, 11447, 11448, 11449, 11450, 11451, 11452, 11453, 11454, 11455, 11456, 11457, 11458, 11459, 11460, 11461, 11462, 11463, 11464, 11465, 11466, 11467, 11468, 11469, 11470, 11471, 11472, 11473, 11474, 11475, 11476, 11477, 11478, 11479, 11480, 11481, 11482, 11483, 11484, 11485, 11486, 11487, 11488, 11489, 11490, 11491, 11492, 11493, 11494, 11495, 11496, 11497, 11498, 11499, 11500, 11501, 11502, 11503, 11504, 11505, 11506, 11507, 11508, 11509, 11510, 11511, 11512, 11513, 11514, 11515, 11516, 11517, 11518, 11519, 11520, 11521, 11522, 11523, 11524, 11525, 11526, 11527, 11528, 11529, 11530, 11531, 11532, 11533, 11534, 11535, 11536, 11537, 11538, 11539, 11540, 11541, 11542, 11543, 11544, 11545, 11546, 11547, 11548, 11549, 11550, 11551, 11552, 11553, 11554, 11555, 11556, 11557, 11558, 11559, 11560, 11561, 11562, 11563, 11564, 11565, 11566, 11567, 11568, 11569, 11570, 11571, 11572, 11573, 11574, 11575, 11576, 11577, 11578, 11579, 11580, 11581, 11582, 11583, 11584, 11585, 11586, 11587, 11588, 11589, 11590, 11591, 11592, 11593, 11594, 11595, 11596, 11597, 11598, 11599, 11600, 11601, 11602, 11603, 11604, 11605, 11606, 11607, 11608, 11609, 11610, 11611, 11612, 11613, 11614, 11615, 11616, 11617, 11618, 11619, 11620, 11621, 11622, 11623, 11624, 11625, 11626, 11627, 11628, 11629, 11630, 11631, 11632, 11633, 11634, 11635, 11636, 11637, 11638, 11639, 11640, 11641, 11642, 11643, 11644, 11645, 11646, 11647, 11648, 11649, 11650, 11651, 11652, 11653, 11654, 11655, 11656, 11657, 11658, 11659, 11660, 11661, 11662, 11663, 11664, 11665, 11666, 11667, 11668, 11669, 11670, 11671, 11672, 11673, 11674, 11675, 11676, 11677, 11678, 11679, 11680, 11681, 11682, 11683, 11684, 11685, 11686, 11687, 11688, 11689, 11690, 11691, 11692, 11693, 11694, 11695, 11696, 11697, 11698, 11699, 11700, 11701, 11702, 11703, 11704, 11705, 11706, 11707, 11708, 11709, 11710, 11711, 11712, 11713, 11714, 11715, 11716, 11717, 11718, 11719, 11720, 11721, 11722, 11723, 11724, 11725, 11726, 11727, 11728, 11729, 11730, 11731, 11732, 11733, 11734, 11735, 11736, 11737, 11738, 11739, 11740, 11741, 11742, 11743, 11744, 11745, 11746, 11747, 11748, 11749, 11750, 11751, 11752, 11753, 11754, 11755, 11756, 11757, 11758, 11759, 11760, 11761, 11762, 11763, 11764, 11765, 11766, 11767, 11768, 11769, 11770, 11771, 11772, 11773, 11774, 11775, 11776, 11777, 11778, 11779, 11780, 11781, 11782, 11783, 11784, 11785, 11786, 11787, 11788, 11789, 11790, 11791, 11792, 11793, 11794, 11795, 11796, 11797, 11798, 11799, 11800, 11801, 11802, 11803, 11804, 11805, 11806, 11807, 11808, 11809, 11810, 11811, 11812, 11813, 11814, 11815, 11816, 11817, 11818, 11819, 11820, 11821, 11822, 11823, 11824, 11825, 11826, 11827, 11828, 11829, 11830, 11831, 11832, 11833, 11834, 11835, 11836, 11837, 11838, 11839, 11840, 11841, 11842, 11843, 11844, 11845, 11846, 11847, 11848, 11849, 11850, 11851, 11852, 11853, 11854, 11855, 11856, 11857, 11858, 11859, 11860, 11861, 11862, 11863, 11864, 11865, 11866, 11867, 11868, 11869, 11870, 11871, 11872, 11873, 11874, 11875, 11876, 11877, 11878, 11879, 11880, 11881, 11882, 11883, 11884, 11885, 11886, 11887, 11888, 11889, 11890, 11891, 11892, 11893, 11894, 11895, 11896, 11897, 11898, 11899, 11900, 11901, 11902, 11903, 11904, 11905, 11906, 11907, 11908, 11909, 11910, 11911, 11912, 11913, 11914, 11915, 11916, 11917, 11918, 11919, 11920, 11921, 11922, 11923, 11924, 11925, 11926, 11927, 11928, 11929, 11930, 11931, 11932, 11933, 11934, 11935, 11936, 11937, 11938, 11939, 11940, 11941, 11942, 11943, 11944, 11945, 11946, 11947, 11948, 11949, 11950, 11951, 11952, 11953, 11954, 11955, 11956, 11957, 11958, 11959, 11960, 11961, 11962, 11963, 11964, 11965, 11966, 11967, 11968, 11969, 11970, 11971, 11972, 11973, 11974, 11975, 11976, 11977, 11978, 11979, 11980, 11981, 11982, 11983, 11984, 11985, 11986, 11987, 11988, 11989, 11990, 11991, 11992, 11993, 11994, 11995, 11996, 11997, 11998, 11999, 12000, 12001, 12002, 12003, 12004, 12005, 12006, 12007, 12008, 12009, 12010, 12011, 12012, 12013, 12014, 12015, 12016, 12017, 12018, 12019, 12020, 12021, 12022, 12023, 12024, 12025, 12026, 12027, 12028, 12029, 12030, 12031, 12032, 12033, 12034, 12035, 12036, 12037, 12038, 12039, 12040, 12041, 12042, 12043, 12044, 12045, 12046, 12047, 12048, 12049, 12050, 12051, 12052, 12053, 12054, 12055, 12056, 12057, 12058, 12059, 12060, 12061, 12062, 12063, 12064, 12065, 12066, 12067, 12068, 12069, 12070, 12071, 12072, 12073, 12074, 12075, 12076, 12077, 12078, 12079, 12080, 12081, 12082, 12083, 12084, 12085, 12086, 12087, 12088, 12089, 12090, 12091, 12092, 12093, 12094, 12095, 12096, 12097, 12098, 12099, 12100, 12101, 12102, 12103, 12104, 12105, 12106, 12107, 12108, 12109, 12110, 12111, 12112, 12113, 12114, 12115, 12116, 12117, 12118, 12119, 12120, 12121, 12122, 12123, 12124, 12125, 12126, 12127, 12128, 12129, 12130, 12131, 12132, 12133, 12134, 12135, 12136, 12137, 12138, 12139, 12140, 12141, 12142, 12143, 12144, 12145, 12146, 12147, 12148, 12149, 12150, 12151, 12152, 12153, 12154, 12155, 12156, 12157, 12158, 12159, 12160, 12161, 12162, 12163, 12164, 12165, 12166, 12167, 12168, 12169, 12170, 12171, 12172, 12173, 12174, 12175, 12176, 12177, 12178, 12179, 12180, 12181, 12182, 12183, 12184, 12185, 12186, 12187, 12188, 12189, 12190, 12191, 12192, 12193, 12194, 12195, 12196, 12197, 12198, 12199, 12200, 12201, 12202, 12203, 12204, 12205, 12206, 12207, 12208, 12209, 12210, 12211, 12212, 12213, 12214, 12215, 12216, 12217, 12218, 12219, 12220, 12221, 12222, 12223, 12224, 12225, 12226, 12227, 12228, 12229, 12230, 12231, 12232, 12233, 12234, 12235, 12236, 12237, 12238, 12239, 12240, 12241, 12242, 12243, 12244, 12245, 12246, 12247, 12248, 12249, 12250, 12251, 12252, 12253, 12254, 12255, 12256, 12257, 12258, 12259, 12260, 12261, 12262, 12263, 12264, 12265, 12266, 12267, 12268, 12269, 12270, 12271, 12272, 12273, 12274, 12275, 12276, 12277, 12278, 12279, 12280, 12281, 12282, 12283, 12284, 12285, 12286, 12287, 12288, 12289, 12290, 12291, 12292, 12293, 12294, 12295, 12296, 12297, 12298, 12299, 12300, 12301, 12302, 12303, 12304, 12305, 12306, 12307, 12308, 12309, 12310, 12311, 12312, 12313, 12314, 12315, 12316, 12317, 12318, 12319, 12320, 12321, 12322, 12323, 12324, 12325, 12326, 12327, 12328, 12329, 12330, 12331, 12332, 12333, 12334, 12335, 12336, 12337, 12338, 12339, 12340, 12341, 12342, 12343, 12344, 12345, 12346, 12347, 12348, 12349, 12350, 12351, 12352, 12353, 12354, 12355, 12356, 12357, 12358, 12359, 12360, 12361, 12362, 12363, 12364, 12365, 12366, 12367, 12368, 12369, 12370, 12371, 12372, 12373, 12374, 12375, 12376, 12377, 12378, 12379, 12380, 12381, 12382, 12383, 12384, 12385, 12386, 12387, 12388, 12389, 12390, 12391, 12392, 12393, 12394, 12395, 12396, 12397, 12398, 12399, 12400, 12401, 12402, 12403, 12404, 12405, 12406, 12407, 12408, 12409, 12410, 12411, 12412, 12413, 12414, 12415, 12416, 12417, 12418, 12419, 12420, 12421, 12422, 12423, 12424, 12425, 12426, 12427, 12428, 12429, 12430, 12431, 12432, 12433, 12434, 12435, 12436, 12437, 12438, 12439, 12440, 12441, 12442, 12443, 12444, 12445, 12446, 12447, 12448, 12449, 12450, 12451, 12452, 12453, 12454, 12455, 12456, 12457, 12458, 12459, 12460, 12461, 12462, 12463, 12464, 12465, 12466, 12467, 12468, 12469, 12470, 12471, 12472, 12473, 12474, 12475, 12476, 12477, 12478, 12479, 12480, 12481, 12482, 12483, 12484, 12485, 12486, 12487, 12488, 12489, 12490, 12491, 12492, 12493, 12494, 12495, 12496, 12497, 12498, 12499, 12500, 12501, 12502, 12503, 12504, 12505, 12506, 12507, 12508, 12509, 12510, 12511, 12512, 12513, 12514, 12515, 12516, 12517, 12518, 12519, 12520, 12521, 12522, 12523, 12524, 12525, 12526, 12527, 12528, 12529, 12530, 12531, 12532, 12533, 12534, 12535, 12536, 12537, 12538, 12539, 12540, 12541, 12542, 12543, 12544, 12545, 12546, 12547, 12548, 12549, 12550, 12551, 12552, 12553, 12554, 12555, 12556, 12557, 12558, 12559, 12560, 12561, 12562, 12563, 12564, 12565, 12566, 12567, 12568, 12569, 12570, 12571, 12572, 12573, 12574, 12575, 12576, 12577, 12578, 12579, 12580, 12581, 12582, 12583, 12584, 12585, 12586, 12587, 12588, 12589, 12590, 12591, 12592, 12593, 12594, 12595, 12596, 12597, 12598, 12599, 12600, 12601, 12602, 12603, 12604, 12605, 12606, 12607, 12608, 12609, 12610, 12611, 12612, 12613, 12614, 12615, 12616, 12617, 12618, 12619, 12620, 12621, 12622, 12623, 12624, 12625, 12626, 12627, 12628, 12629, 12630, 12631, 12632, 12633, 12634, 12635, 12636, 12637, 12638, 12639, 12640, 12641, 12642, 12643, 12644, 12645, 12646, 12647, 12648, 12649, 12650, 12651, 12652, 12653, 12654, 12655, 12656, 12657, 12658, 12659, 12660, 12661, 12662, 12663, 12664, 12665, 12666, 12667, 12668, 12669, 12670, 12671, 12672, 12673, 12674, 12675, 12676, 12677, 12678, 12679, 12680, 12681, 12682, 12683, 12684, 12685, 12686, 12687, 12688, 12689, 12690, 12691, 12692, 12693, 12694, 12695, 12696, 12697, 12698, 12699, 12700, 12701, 12702, 12703, 12704, 12705, 12706, 12707, 12708, 12709, 12710, 12711, 12712, 12713, 12714, 12715, 12716, 12717, 12718, 12719, 12720, 12721, 12722, 12723, 12724, 12725, 12726, 12727, 12728, 12729, 12730, 12731, 12732, 12733, 12734, 12735, 12736, 12737, 12738, 12739, 12740, 12741, 12742, 12743, 12744, 12745, 12746, 12747, 12748, 12749, 12750, 12751, 12752, 12753, 12754, 12755, 12756, 12757, 12758, 12759, 12760, 12761, 12762, 12763, 12764, 12765, 12766, 12767, 12768, 12769, 12770, 12771, 12772, 12773, 12774, 12775, 12776, 12777, 12778, 12779, 12780, 12781, 12782, 12783, 12784, 12785, 12786, 12787, 12788, 12789, 12790, 12791, 12792, 12793, 12794, 12795, 12796, 12797, 12798, 12799, 12800, 12801, 12802, 12803, 12804, 12805, 12806, 12807, 12808, 12809, 12810, 12811, 12812, 12813, 12814, 12815, 12816, 12817, 12818, 12819, 12820, 12821, 12822, 12823, 12824, 12825, 12826, 12827, 12828, 12829, 12830, 12831, 12832, 12833, 12834, 12835, 12836, 12837, 12838, 12839, 12840, 12841, 12842, 12843, 12844, 12845, 12846, 12847, 12848, 12849, 12850, 12851, 12852, 12853, 12854, 12855, 12856, 12857, 12858, 12859, 12860, 12861, 12862, 12863, 12864, 12865, 12866, 12867, 12868, 12869, 12870, 12871, 12872, 12873, 12874, 12875, 12876, 12877, 12878, 12879, 12880, 12881, 12882, 12883, 12884, 12885, 12886, 12887, 12888, 12889, 12890, 12891, 12892, 12893, 12894, 12895, 12896, 12897, 12898, 12899, 12900, 12901, 12902, 12903, 12904, 12905, 12906, 12907, 12908, 12909, 12910, 12911, 12912, 12913, 12914, 12915, 12916, 12917, 12918, 12919, 12920, 12921, 12922, 12923, 12924, 12925, 12926, 12927, 12928, 12929, 12930, 12931, 12932, 12933, 12934, 12935, 12936, 12937, 12938, 12939, 12940, 12941, 12942, 12943, 12944, 12945, 12946, 12947, 12948, 12949, 12950, 12951, 12952, 12953, 12954, 12955, 12956, 12957, 12958, 12959, 12960, 12961, 12962, 12963, 12964, 12965, 12966, 12967, 12968, 12969, 12970, 12971, 12972, 12973, 12974, 12975, 12976, 12977, 12978, 12979, 12980, 12981, 12982, 12983, 12984, 12985, 12986, 12987, 12988, 12989, 12990, 12991, 12992, 12993, 12994, 12995, 12996, 12997, 12998, 12999, 13000, 13001, 13002, 13003, 13004, 13005, 13006, 13007, 13008, 13009, 13010, 13011, 13012, 13013, 13014, 13015, 13016, 13017, 13018, 13019, 13020, 13021, 13022, 13023, 13024, 13025, 13026, 13027, 13028, 13029, 13030, 13031, 13032, 13033, 13034, 13035, 13036, 13037, 13038, 13039, 13040, 13041, 13042, 13043, 13044, 13045, 13046, 13047, 13048, 13049, 13050, 13051, 13052, 13053, 13054, 13055, 13056, 13057, 13058, 13059, 13060, 13061, 13062, 13063, 13064, 13065, 13066, 13067, 13068, 13069, 13070, 13071, 13072, 13073, 13074, 13075, 13076, 13077, 13078, 13079, 13080, 13081, 13082, 13083, 13084, 13085, 13086, 13087, 13088, 13089, 13090, 13091, 13092, 13093, 13094, 13095, 13096, 13097, 13098, 13099, 13100, 13101, 13102, 13103, 13104, 13105, 13106, 13107, 13108, 13109, 13110, 13111, 13112, 13113, 13114, 13115, 13116, 13117, 13118, 13119, 13120, 13121, 13122, 13123, 13124, 13125, 13126, 13127, 13128, 13129, 13130, 13131, 13132, 13133, 13134, 13135, 13136, 13137, 13138, 13139, 13140, 13141, 13142, 13143, 13144, 13145, 13146, 13147, 13148, 13149, 13150, 13151, 13152, 13153, 13154, 13155, 13156, 13157, 13158, 13159, 13160, 13161, 13162, 13163, 13164, 13165, 13166, 13167, 13168, 13169, 13170, 13171, 13172, 13173, 13174, 13175, 13176, 13177, 13178, 13179, 13180, 13181, 13182, 13183, 13184, 13185, 13186, 13187, 13188, 13189, 13190, 13191, 13192, 13193, 13194, 13195, 13196, 13197, 13198, 13199, 13200, 13201, 13202, 13203, 13204, 13205, 13206, 13207, 13208, 13209, 13210, 13211, 13212, 13213, 13214, 13215, 13216, 13217, 13218, 13219, 13220, 13221, 13222, 13223, 13224, 13225, 13226, 13227, 13228, 13229, 13230, 13231, 13232, 13233, 13234, 13235, 13236, 13237, 13238, 13239, 13240, 13241, 13242, 13243, 13244, 13245, 13246, 13247, 13248, 13249, 13250, 13251, 13252, 13253, 13254, 13255, 13256, 13257, 13258, 13259, 13260, 13261, 13262, 13263, 13264, 13265, 13266, 13267, 13268, 13269, 13270, 13271, 13272, 13273, 13274, 13275, 13276, 13277, 13278, 13279, 13280, 13281, 13282, 13283, 13284, 13285, 13286, 13287, 13288, 13289, 13290, 13291, 13292, 13293, 13294, 13295, 13296, 13297, 13298, 13299, 13300, 13301, 13302, 13303, 13304, 13305, 13306, 13307, 13308, 13309, 13310, 13311, 13312, 13313, 13314, 13315, 13316, 13317, 13318, 13319, 13320, 13321, 13322, 13323, 13324, 13325, 13326, 13327, 13328, 13329, 13330, 13331, 13332, 13333, 13334, 13335, 13336, 13337, 13338, 13339, 13340, 13341, 13342, 13343, 13344, 13345, 13346, 13347, 13348, 13349, 13350, 13351, 13352, 13353, 13354, 13355, 13356, 13357, 13358, 13359, 13360, 13361, 13362, 13363, 13364, 13365, 13366, 13367, 13368, 13369, 13370, 13371, 13372, 13373, 13374, 13375, 13376, 13377, 13378, 13379, 13380, 13381, 13382, 13383, 13384, 13385, 13386, 13387, 13388, 13389, 13390, 13391, 13392, 13393, 13394, 13395, 13396, 13397, 13398, 13399, 13400, 13401, 13402, 13403, 13404, 13405, 13406, 13407, 13408, 13409, 13410, 13411, 13412, 13413, 13414, 13415, 13416, 13417, 13418, 13419, 13420, 13421, 13422, 13423, 13424, 13425, 13426, 13427, 13428, 13429, 13430, 13431, 13432, 13433, 13434, 13435, 13436, 13437, 13438, 13439, 13440, 13441, 13442, 13443, 13444, 13445, 13446, 13447, 13448, 13449, 13450, 13451, 13452, 13453, 13454, 13455, 13456, 13457, 13458, 13459, 13460, 13461, 13462, 13463, 13464, 13465, 13466, 13467, 13468, 13469, 13470, 13471, 13472, 13473, 13474, 13475, 13476, 13477, 13478, 13479, 13480, 13481, 13482, 13483, 13484, 13485, 13486, 13487, 13488, 13489, 13490, 13491, 13492, 13493, 13494, 13495, 13496, 13497, 13498, 13499, 13500, 13501, 13502, 13503, 13504, 13505, 13506, 13507, 13508, 13509, 13510, 13511, 13512, 13513, 13514, 13515, 13516, 13517, 13518, 13519, 13520, 13521, 13522, 13523, 13524, 13525, 13526, 13527, 13528, 13529, 13530, 13531, 13532, 13533, 13534, 13535, 13536, 13537, 13538, 13539, 13540, 13541, 13542, 13543, 13544, 13545, 13546, 13547, 13548, 13549, 13550, 13551, 13552, 13553, 13554, 13555, 13556, 13557, 13558, 13559, 13560, 13561, 13562, 13563, 13564, 13565, 13566, 13567, 13568, 13569, 13570, 13571, 13572, 13573, 13574, 13575, 13576, 13577, 13578, 13579, 13580, 13581, 13582, 13583, 13584, 13585, 13586, 13587, 13588, 13589, 13590, 13591, 13592, 13593, 13594, 13595, 13596, 13597, 13598, 13599, 13600, 13601, 13602, 13603, 13604, 13605, 13606, 13607, 13608, 13609, 13610, 13611, 13612, 13613, 13614, 13615, 13616, 13617, 13618, 13619, 13620, 13621, 13622, 13623, 13624, 13625, 13626, 13627, 13628, 13629, 13630, 13631, 13632, 13633, 13634, 13635, 13636, 13637, 13638, 13639, 13640, 13641, 13642, 13643, 13644, 13645, 13646, 13647, 13648, 13649, 13650, 13651, 13652, 13653, 13654, 13655, 13656, 13657, 13658, 13659, 13660, 13661, 13662, 13663, 13664, 13665, 13666, 13667, 13668, 13669, 13670, 13671, 13672, 13673, 13674, 13675, 13676, 13677, 13678, 13679, 13680, 13681, 13682, 13683, 13684, 13685, 13686, 13687, 13688, 13689, 13690, 13691, 13692, 13693, 13694, 13695, 13696, 13697, 13698, 13699, 13700, 13701, 13702, 13703, 13704, 13705, 13706, 13707, 13708, 13709, 13710, 13711, 13712, 13713, 13714, 13715, 13716, 13717, 13718, 13719, 13720, 13721, 13722, 13723, 13724, 13725, 13726, 13727, 13728, 13729, 13730, 13731, 13732, 13733, 13734, 13735, 13736, 13737, 13738, 13739, 13740, 13741, 13742, 13743, 13744, 13745, 13746, 13747, 13748, 13749, 13750, 13751, 13752, 13753, 13754, 13755, 13756, 13757, 13758, 13759, 13760, 13761, 13762, 13763, 13764, 13765, 13766, 13767, 13768, 13769, 13770, 13771, 13772, 13773, 13774, 13775, 13776, 13777, 13778, 13779, 13780, 13781, 13782, 13783, 13784, 13785, 13786, 13787, 13788, 13789, 13790, 13791, 13792, 13793, 13794, 13795, 13796, 13797, 13798, 13799, 13800, 13801, 13802, 13803, 13804, 13805, 13806, 13807, 13808, 13809, 13810, 13811, 13812, 13813, 13814, 13815, 13816, 13817, 13818, 13819, 13820, 13821, 13822, 13823, 13824, 13825, 13826, 13827, 13828, 13829, 13830, 13831, 13832, 13833, 13834, 13835, 13836, 13837, 13838, 13839, 13840, 13841, 13842, 13843, 13844, 13845, 13846, 13847, 13848, 13849, 13850, 13851, 13852, 13853, 13854, 13855, 13856, 13857, 13858, 13859, 13860, 13861, 13862, 13863, 13864, 13865, 13866, 13867, 13868, 13869, 13870, 13871, 13872, 13873, 13874, 13875, 13876, 13877, 13878, 13879, 13880, 13881, 13882, 13883, 13884, 13885, 13886, 13887, 13888, 13889, 13890, 13891, 13892, 13893, 13894, 13895, 13896, 13897, 13898, 13899, 13900, 13901, 13902, 13903, 13904, 13905, 13906, 13907, 13908, 13909, 13910, 13911, 13912, 13913, 13914, 13915, 13916, 13917, 13918, 13919, 13920, 13921, 13922, 13923, 13924, 13925, 13926, 13927, 13928, 13929, 13930, 13931, 13932, 13933, 13934, 13935, 13936, 13937, 13938, 13939, 13940, 13941, 13942, 13943, 13944, 13945, 13946, 13947, 13948, 13949, 13950, 13951, 13952, 13953, 13954, 13955, 13956, 13957, 13958, 13959, 13960, 13961, 13962, 13963, 13964, 13965, 13966, 13967, 13968, 13969, 13970, 13971, 13972, 13973, 13974, 13975, 13976, 13977, 13978, 13979, 13980, 13981, 13982, 13983, 13984, 13985, 13986, 13987, 13988, 13989, 13990, 13991, 13992, 13993, 13994, 13995, 13996, 13997, 13998, 13999, 14000, 14001, 14002, 14003, 14004, 14005, 14006, 14007, 14008, 14009, 14010, 14011, 14012, 14013, 14014, 14015, 14016, 14017, 14018, 14019, 14020, 14021, 14022, 14023, 14024, 14025, 14026, 14027, 14028, 14029, 14030, 14031, 14032, 14033, 14034, 14035, 14036, 14037, 14038, 14039, 14040, 14041, 14042, 14043, 14044, 14045, 14046, 14047, 14048, 14049, 14050, 14051, 14052, 14053, 14054, 14055, 14056, 14057, 14058, 14059, 14060, 14061, 14062, 14063, 14064, 14065, 14066, 14067, 14068, 14069, 14070, 14071, 14072, 14073, 14074, 14075, 14076, 14077, 14078, 14079, 14080, 14081, 14082, 14083, 14084, 14085, 14086, 14087, 14088, 14089, 14090, 14091, 14092, 14093, 14094, 14095, 14096, 14097, 14098, 14099, 14100, 14101, 14102, 14103, 14104, 14105, 14106, 14107, 14108, 14109, 14110, 14111, 14112, 14113, 14114, 14115, 14116, 14117, 14118, 14119, 14120, 14121, 14122, 14123, 14124, 14125, 14126, 14127, 14128, 14129, 14130, 14131, 14132, 14133, 14134, 14135, 14136, 14137, 14138, 14139, 14140, 14141, 14142, 14143, 14144, 14145, 14146, 14147, 14148, 14149, 14150, 14151, 14152, 14153, 14154, 14155, 14156, 14157, 14158, 14159, 14160, 14161, 14162, 14163, 14164, 14165, 14166, 14167, 14168, 14169, 14170, 14171, 14172, 14173, 14174, 14175, 14176, 14177, 14178, 14179, 14180, 14181, 14182, 14183, 14184, 14185, 14186, 14187, 14188, 14189, 14190, 14191, 14192, 14193, 14194, 14195, 14196, 14197, 14198, 14199, 14200, 14201, 14202, 14203, 14204, 14205, 14206, 14207, 14208, 14209, 14210, 14211, 14212, 14213, 14214, 14215, 14216, 14217, 14218, 14219, 14220, 14221, 14222, 14223, 14224, 14225, 14226, 14227, 14228, 14229, 14230, 14231, 14232, 14233, 14234, 14235, 14236, 14237, 14238, 14239, 14240, 14241, 14242, 14243, 14244, 14245, 14246, 14247, 14248, 14249, 14250, 14251, 14252, 14253, 14254, 14255, 14256, 14257, 14258, 14259, 14260, 14261, 14262, 14263, 14264, 14265, 14266, 14267, 14268, 14269, 14270, 14271, 14272, 14273, 14274, 14275, 14276, 14277, 14278, 14279, 14280, 14281, 14282, 14283, 14284, 14285, 14286, 14287, 14288, 14289, 14290, 14291, 14292, 14293, 14294, 14295, 14296, 14297, 14298, 14299, 14300, 14301, 14302, 14303, 14304, 14305, 14306, 14307, 14308, 14309, 14310, 14311, 14312, 14313, 14314, 14315, 14316, 14317, 14318, 14319, 14320, 14321, 14322, 14323, 14324, 14325, 14326, 14327, 14328, 14329, 14330, 14331, 14332, 14333, 14334, 14335, 14336, 14337, 14338, 14339, 14340, 14341, 14342, 14343, 14344, 14345, 14346, 14347, 14348, 14349, 14350, 14351, 14352, 14353, 14354, 14355, 14356, 14357, 14358, 14359, 14360, 14361, 14362, 14363, 14364, 14365, 14366, 14367, 14368, 14369, 14370, 14371, 14372, 14373, 14374, 14375, 14376, 14377, 14378, 14379, 14380, 14381, 14382, 14383, 14384, 14385, 14386, 14387, 14388, 14389, 14390, 14391, 14392, 14393, 14394, 14395, 14396, 14397, 14398, 14399, 14400, 14401, 14402, 14403, 14404, 14405, 14406, 14407, 14408, 14409, 14410, 14411, 14412, 14413, 14414, 14415, 14416, 14417, 14418, 14419, 14420, 14421, 14422, 14423, 14424, 14425, 14426, 14427, 14428, 14429, 14430, 14431, 14432, 14433, 14434, 14435, 14436, 14437, 14438, 14439, 14440, 14441, 14442, 14443, 14444, 14445, 14446, 14447, 14448, 14449, 14450, 14451, 14452, 14453, 14454, 14455, 14456, 14457, 14458, 14459, 14460, 14461, 14462, 14463, 14464, 14465, 14466, 14467, 14468, 14469, 14470, 14471, 14472, 14473, 14474, 14475, 14476, 14477, 14478, 14479, 14480, 14481, 14482, 14483, 14484, 14485, 14486, 14487, 14488, 14489, 14490, 14491, 14492, 14493, 14494, 14495, 14496, 14497, 14498, 14499, 14500, 14501, 14502, 14503, 14504, 14505, 14506, 14507, 14508, 14509, 14510, 14511, 14512, 14513, 14514, 14515, 14516, 14517, 14518, 14519, 14520, 14521, 14522, 14523, 14524, 14525, 14526, 14527, 14528, 14529, 14530, 14531, 14532, 14533, 14534, 14535, 14536, 14537, 14538, 14539, 14540, 14541, 14542, 14543, 14544, 14545, 14546, 14547, 14548, 14549, 14550, 14551, 14552, 14553, 14554, 14555, 14556, 14557, 14558, 14559, 14560, 14561, 14562, 14563, 14564, 14565, 14566, 14567, 14568, 14569, 14570, 14571, 14572, 14573, 14574, 14575, 14576, 14577, 14578, 14579, 14580, 14581, 14582, 14583, 14584, 14585, 14586, 14587, 14588, 14589, 14590, 14591, 14592, 14593, 14594, 14595, 14596, 14597, 14598, 14599, 14600, 14601, 14602, 14603, 14604, 14605, 14606, 14607, 14608, 14609, 14610, 14611, 14612, 14613, 14614, 14615, 14616, 14617, 14618, 14619, 14620, 14621, 14622, 14623, 14624, 14625, 14626, 14627, 14628, 14629, 14630, 14631, 14632, 14633, 14634, 14635, 14636, 14637, 14638, 14639, 14640, 14641, 14642, 14643, 14644, 14645, 14646, 14647, 14648, 14649, 14650, 14651, 14652, 14653, 14654, 14655, 14656, 14657, 14658, 14659, 14660, 14661, 14662, 14663, 14664, 14665, 14666, 14667, 14668, 14669, 14670, 14671, 14672, 14673, 14674, 14675, 14676, 14677, 14678, 14679, 14680, 14681, 14682, 14683, 14684, 14685, 14686, 14687, 14688, 14689, 14690, 14691, 14692, 14693, 14694, 14695, 14696, 14697, 14698, 14699, 14700, 14701, 14702, 14703, 14704, 14705, 14706, 14707, 14708, 14709, 14710, 14711, 14712, 14713, 14714, 14715, 14716, 14717, 14718, 14719, 14720, 14721, 14722, 14723, 14724, 14725, 14726, 14727, 14728, 14729, 14730, 14731, 14732, 14733, 14734, 14735, 14736, 14737, 14738, 14739, 14740, 14741, 14742, 14743, 14744, 14745, 14746, 14747, 14748, 14749, 14750, 14751, 14752, 14753, 14754, 14755, 14756, 14757, 14758, 14759, 14760, 14761, 14762, 14763, 14764, 14765, 14766, 14767, 14768, 14769, 14770, 14771, 14772, 14773, 14774, 14775, 14776, 14777, 14778, 14779, 14780, 14781, 14782, 14783, 14784, 14785, 14786, 14787, 14788, 14789, 14790, 14791, 14792, 14793, 14794, 14795, 14796, 14797, 14798, 14799, 14800, 14801, 14802, 14803, 14804, 14805, 14806, 14807, 14808, 14809, 14810, 14811, 14812, 14813, 14814, 14815, 14816, 14817, 14818, 14819, 14820, 14821, 14822, 14823, 14824, 14825, 14826, 14827, 14828, 14829, 14830, 14831, 14832, 14833, 14834, 14835, 14836, 14837, 14838, 14839, 14840, 14841, 14842, 14843, 14844, 14845, 14846, 14847, 14848, 14849, 14850, 14851, 14852, 14853, 14854, 14855, 14856, 14857, 14858, 14859, 14860, 14861, 14862, 14863, 14864, 14865, 14866, 14867, 14868, 14869, 14870, 14871, 14872, 14873, 14874, 14875, 14876, 14877, 14878, 14879, 14880, 14881, 14882, 14883, 14884, 14885, 14886, 14887, 14888, 14889, 14890, 14891, 14892, 14893, 14894, 14895, 14896, 14897, 14898, 14899, 14900, 14901, 14902, 14903, 14904, 14905, 14906, 14907, 14908, 14909, 14910, 14911, 14912, 14913, 14914, 14915, 14916, 14917, 14918, 14919, 14920, 14921, 14922, 14923, 14924, 14925, 14926, 14927, 14928, 14929, 14930, 14931, 14932, 14933, 14934, 14935, 14936, 14937, 14938, 14939, 14940, 14941, 14942, 14943, 14944, 14945, 14946, 14947, 14948, 14949, 14950, 14951, 14952, 14953, 14954, 14955, 14956, 14957, 14958, 14959, 14960, 14961, 14962, 14963, 14964, 14965, 14966, 14967, 14968, 14969, 14970, 14971, 14972, 14973, 14974, 14975, 14976, 14977, 14978, 14979, 14980, 14981, 14982, 14983, 14984, 14985, 14986, 14987, 14988, 14989, 14990, 14991, 14992, 14993, 14994, 14995, 14996, 14997, 14998, 14999, 15000, 15001, 15002, 15003, 15004, 15005, 15006, 15007, 15008, 15009, 15010, 15011, 15012, 15013, 15014, 15015, 15016, 15017, 15018, 15019, 15020, 15021, 15022, 15023, 15024, 15025, 15026, 15027, 15028, 15029, 15030, 15031, 15032, 15033, 15034, 15035, 15036, 15037, 15038, 15039, 15040, 15041, 15042, 15043, 15044, 15045, 15046, 15047, 15048, 15049, 15050, 15051, 15052, 15053, 15054, 15055, 15056, 15057, 15058, 15059, 15060, 15061, 15062, 15063, 15064, 15065, 15066, 15067, 15068, 15069, 15070, 15071, 15072, 15073, 15074, 15075, 15076, 15077, 15078, 15079, 15080, 15081, 15082, 15083, 15084, 15085, 15086, 15087, 15088, 15089, 15090, 15091, 15092, 15093, 15094, 15095, 15096, 15097, 15098, 15099, 15100, 15101, 15102, 15103, 15104, 15105, 15106, 15107, 15108, 15109, 15110, 15111, 15112, 15113, 15114, 15115, 15116, 15117, 15118, 15119, 15120, 15121, 15122, 15123, 15124, 15125, 15126, 15127, 15128, 15129, 15130, 15131, 15132, 15133, 15134, 15135, 15136, 15137, 15138, 15139, 15140, 15141, 15142, 15143, 15144, 15145, 15146, 15147, 15148, 15149, 15150, 15151, 15152, 15153, 15154, 15155, 15156, 15157, 15158, 15159, 15160, 15161, 15162, 15163, 15164, 15165, 15166, 15167, 15168, 15169, 15170, 15171, 15172, 15173, 15174, 15175, 15176, 15177, 15178, 15179, 15180, 15181, 15182, 15183, 15184, 15185, 15186, 15187, 15188, 15189, 15190, 15191, 15192, 15193, 15194, 15195, 15196, 15197, 15198, 15199, 15200, 15201, 15202, 15203, 15204, 15205, 15206, 15207, 15208, 15209, 15210, 15211, 15212, 15213, 15214, 15215, 15216, 15217, 15218, 15219, 15220, 15221, 15222, 15223, 15224, 15225, 15226, 15227, 15228, 15229, 15230, 15231, 15232, 15233, 15234, 15235, 15236, 15237, 15238, 15239, 15240, 15241, 15242, 15243, 15244, 15245, 15246, 15247, 15248, 15249, 15250, 15251, 15252, 15253, 15254, 15255, 15256, 15257, 15258, 15259, 15260, 15261, 15262, 15263, 15264, 15265, 15266, 15267, 15268, 15269, 15270, 15271, 15272, 15273, 15274, 15275, 15276, 15277, 15278, 15279, 15280, 15281, 15282, 15283, 15284, 15285, 15286, 15287, 15288, 15289, 15290, 15291, 15292, 15293, 15294, 15295, 15296, 15297, 15298, 15299, 15300, 15301, 15302, 15303, 15304, 15305, 15306, 15307, 15308, 15309, 15310, 15311, 15312, 15313, 15314, 15315, 15316, 15317, 15318, 15319, 15320, 15321, 15322, 15323, 15324, 15325, 15326, 15327, 15328, 15329, 15330, 15331, 15332, 15333, 15334, 15335, 15336, 15337, 15338, 15339, 15340, 15341, 15342, 15343, 15344, 15345, 15346, 15347, 15348, 15349, 15350, 15351, 15352, 15353, 15354, 15355, 15356, 15357, 15358, 15359, 15360, 15361, 15362, 15363, 15364, 15365, 15366, 15367, 15368, 15369, 15370, 15371, 15372, 15373, 15374, 15375, 15376, 15377, 15378, 15379, 15380, 15381, 15382, 15383, 15384, 15385, 15386, 15387, 15388, 15389, 15390, 15391, 15392, 15393, 15394, 15395, 15396, 15397, 15398, 15399, 15400, 15401, 15402, 15403, 15404, 15405, 15406, 15407, 15408, 15409, 15410, 15411, 15412, 15413, 15414, 15415, 15416, 15417, 15418, 15419, 15420, 15421, 15422, 15423, 15424, 15425, 15426, 15427, 15428, 15429, 15430, 15431, 15432, 15433, 15434, 15435, 15436, 15437, 15438, 15439, 15440, 15441, 15442, 15443, 15444, 15445, 15446, 15447, 15448, 15449, 15450, 15451, 15452, 15453, 15454, 15455, 15456, 15457, 15458, 15459, 15460, 15461, 15462, 15463, 15464, 15465, 15466, 15467, 15468, 15469, 15470, 15471, 15472, 15473, 15474, 15475, 15476, 15477, 15478, 15479, 15480, 15481, 15482, 15483, 15484, 15485, 15486, 15487, 15488, 15489, 15490, 15491, 15492, 15493, 15494, 15495, 15496, 15497, 15498, 15499, 15500, 15501, 15502, 15503, 15504, 15505, 15506, 15507, 15508, 15509, 15510, 15511, 15512, 15513, 15514, 15515, 15516, 15517, 15518, 15519, 15520, 15521, 15522, 15523, 15524, 15525, 15526, 15527, 15528, 15529, 15530, 15531, 15532, 15533, 15534, 15535, 15536, 15537, 15538, 15539, 15540, 15541, 15542, 15543, 15544, 15545, 15546, 15547, 15548, 15549, 15550, 15551, 15552, 15553, 15554, 15555, 15556, 15557, 15558, 15559, 15560, 15561, 15562, 15563, 15564, 15565, 15566, 15567, 15568, 15569, 15570, 15571, 15572, 15573, 15574, 15575, 15576, 15577, 15578, 15579, 15580, 15581, 15582, 15583, 15584, 15585, 15586, 15587, 15588, 15589, 15590, 15591, 15592, 15593, 15594, 15595, 15596, 15597, 15598, 15599, 15600, 15601, 15602, 15603, 15604, 15605, 15606, 15607, 15608, 15609, 15610, 15611, 15612, 15613, 15614, 15615, 15616, 15617, 15618, 15619, 15620, 15621, 15622, 15623, 15624, 15625, 15626, 15627, 15628, 15629, 15630, 15631, 15632, 15633, 15634, 15635, 15636, 15637, 15638, 15639, 15640, 15641, 15642, 15643, 15644, 15645, 15646, 15647, 15648, 15649, 15650, 15651, 15652, 15653, 15654, 15655, 15656, 15657, 15658, 15659, 15660, 15661, 15662, 15663, 15664, 15665, 15666, 15667, 15668, 15669, 15670, 15671, 15672, 15673, 15674, 15675, 15676, 15677, 15678, 15679, 15680, 15681, 15682, 15683, 15684, 15685, 15686, 15687, 15688, 15689, 15690, 15691, 15692, 15693, 15694, 15695, 15696, 15697, 15698, 15699, 15700, 15701, 15702, 15703, 15704, 15705, 15706, 15707, 15708, 15709, 15710, 15711, 15712, 15713, 15714, 15715, 15716, 15717, 15718, 15719, 15720, 15721, 15722, 15723, 15724, 15725, 15726, 15727, 15728, 15729, 15730, 15731, 15732, 15733, 15734, 15735, 15736, 15737, 15738, 15739, 15740, 15741, 15742, 15743, 15744, 15745, 15746, 15747, 15748, 15749, 15750, 15751, 15752, 15753, 15754, 15755, 15756, 15757, 15758, 15759, 15760, 15761, 15762, 15763, 15764, 15765, 15766, 15767, 15768, 15769, 15770, 15771, 15772, 15773, 15774, 15775, 15776, 15777, 15778, 15779, 15780, 15781, 15782, 15783, 15784, 15785, 15786, 15787, 15788, 15789, 15790, 15791, 15792, 15793, 15794, 15795, 15796, 15797, 15798, 15799, 15800, 15801, 15802, 15803, 15804, 15805, 15806, 15807, 15808, 15809, 15810, 15811, 15812, 15813, 15814, 15815, 15816, 15817, 15818, 15819, 15820, 15821, 15822, 15823, 15824, 15825, 15826, 15827, 15828, 15829, 15830, 15831, 15832, 15833, 15834, 15835, 15836, 15837, 15838, 15839, 15840, 15841, 15842, 15843, 15844, 15845, 15846, 15847, 15848, 15849, 15850, 15851, 15852, 15853, 15854, 15855, 15856, 15857, 15858, 15859, 15860, 15861, 15862, 15863, 15864, 15865, 15866, 15867, 15868, 15869, 15870, 15871, 15872, 15873, 15874, 15875, 15876, 15877, 15878, 15879, 15880, 15881, 15882, 15883, 15884, 15885, 15886, 15887, 15888, 15889, 15890, 15891, 15892, 15893, 15894, 15895, 15896, 15897, 15898, 15899, 15900, 15901, 15902, 15903, 15904, 15905, 15906, 15907, 15908, 15909, 15910, 15911, 15912, 15913, 15914, 15915, 15916, 15917, 15918, 15919, 15920, 15921, 15922, 15923, 15924, 15925, 15926, 15927, 15928, 15929, 15930, 15931, 15932, 15933, 15934, 15935, 15936, 15937, 15938, 15939, 15940, 15941, 15942, 15943, 15944, 15945, 15946, 15947, 15948, 15949, 15950, 15951, 15952, 15953, 15954, 15955, 15956, 15957, 15958, 15959, 15960, 15961, 15962, 15963, 15964, 15965, 15966, 15967, 15968, 15969, 15970, 15971, 15972, 15973, 15974, 15975, 15976, 15977, 15978, 15979, 15980, 15981, 15982, 15983, 15984, 15985, 15986, 15987, 15988, 15989, 15990, 15991, 15992, 15993, 15994, 15995, 15996, 15997, 15998, 15999, 16000, 16001, 16002, 16003, 16004, 16005, 16006, 16007, 16008, 16009, 16010, 16011, 16012, 16013, 16014, 16015, 16016, 16017, 16018, 16019, 16020, 16021, 16022, 16023, 16024, 16025, 16026, 16027, 16028, 16029, 16030, 16031, 16032, 16033, 16034, 16035, 16036, 16037, 16038, 16039, 16040, 16041, 16042, 16043, 16044, 16045, 16046, 16047, 16048, 16049, 16050, 16051, 16052, 16053, 16054, 16055, 16056, 16057, 16058, 16059, 16060, 16061, 16062, 16063, 16064, 16065, 16066, 16067, 16068, 16069, 16070, 16071, 16072, 16073, 16074, 16075, 16076, 16077, 16078, 16079, 16080, 16081, 16082, 16083, 16084, 16085, 16086, 16087, 16088, 16089, 16090, 16091, 16092, 16093, 16094, 16095, 16096, 16097, 16098, 16099, 16100, 16101, 16102, 16103, 16104, 16105, 16106, 16107, 16108, 16109, 16110, 16111, 16112, 16113, 16114, 16115, 16116, 16117, 16118, 16119, 16120, 16121, 16122, 16123, 16124, 16125, 16126, 16127, 16128, 16129, 16130, 16131, 16132, 16133, 16134, 16135, 16136, 16137, 16138, 16139, 16140, 16141, 16142, 16143, 16144, 16145, 16146, 16147, 16148, 16149, 16150, 16151, 16152, 16153, 16154, 16155, 16156, 16157, 16158, 16159, 16160, 16161, 16162, 16163, 16164, 16165, 16166, 16167, 16168, 16169, 16170, 16171, 16172, 16173, 16174, 16175, 16176, 16177, 16178, 16179, 16180, 16181, 16182, 16183, 16184, 16185, 16186, 16187, 16188, 16189, 16190, 16191, 16192, 16193, 16194, 16195, 16196, 16197, 16198, 16199, 16200, 16201, 16202, 16203, 16204, 16205, 16206, 16207, 16208, 16209, 16210, 16211, 16212, 16213, 16214, 16215, 16216, 16217, 16218, 16219, 16220, 16221, 16222, 16223, 16224, 16225, 16226, 16227, 16228, 16229, 16230, 16231, 16232, 16233, 16234, 16235, 16236, 16237, 16238, 16239, 16240, 16241, 16242, 16243, 16244, 16245, 16246, 16247, 16248, 16249, 16250, 16251, 16252, 16253, 16254, 16255, 16256, 16257, 16258, 16259, 16260, 16261, 16262, 16263, 16264, 16265, 16266, 16267, 16268, 16269, 16270, 16271, 16272, 16273, 16274, 16275, 16276, 16277, 16278, 16279, 16280, 16281, 16282, 16283, 16284, 16285, 16286, 16287, 16288, 16289, 16290, 16291, 16292, 16293, 16294, 16295, 16296, 16297, 16298, 16299, 16300, 16301, 16302, 16303, 16304, 16305, 16306, 16307, 16308, 16309, 16310, 16311, 16312, 16313, 16314, 16315, 16316, 16317, 16318, 16319, 16320, 16321, 16322, 16323, 16324, 16325, 16326, 16327, 16328, 16329, 16330, 16331, 16332, 16333, 16334, 16335, 16336, 16337, 16338, 16339, 16340, 16341, 16342, 16343, 16344, 16345, 16346, 16347, 16348, 16349, 16350, 16351, 16352, 16353, 16354, 16355, 16356, 16357, 16358, 16359, 16360, 16361, 16362, 16363, 16364, 16365, 16366, 16367, 16368, 16369, 16370, 16371, 16372, 16373, 16374, 16375, 16376, 16377, 16378, 16379, 16380, 16381, 16382, 16383, 16384, 16385, 16386, 16387, 16388, 16389, 16390, 16391, 16392, 16393, 16394, 16395, 16396, 16397, 16398, 16399, 16400, 16401, 16402, 16403, 16404, 16405, 16406, 16407, 16408, 16409, 16410, 16411, 16412, 16413, 16414, 16415, 16416, 16417, 16418, 16419, 16420, 16421, 16422, 16423, 16424, 16425, 16426, 16427, 16428, 16429, 16430, 16431, 16432, 16433, 16434, 16435, 16436, 16437, 16438, 16439, 16440, 16441, 16442, 16443, 16444, 16445, 16446, 16447, 16448, 16449, 16450, 16451, 16452, 16453, 16454, 16455, 16456, 16457, 16458, 16459, 16460, 16461, 16462, 16463, 16464, 16465, 16466, 16467, 16468, 16469, 16470, 16471, 16472, 16473, 16474, 16475, 16476, 16477, 16478, 16479, 16480, 16481, 16482, 16483, 16484, 16485, 16486, 16487, 16488, 16489, 16490, 16491, 16492, 16493, 16494, 16495, 16496, 16497, 16498, 16499, 16500, 16501, 16502, 16503, 16504, 16505, 16506, 16507, 16508, 16509, 16510, 16511, 16512, 16513, 16514, 16515, 16516, 16517, 16518, 16519, 16520, 16521, 16522, 16523, 16524, 16525, 16526, 16527, 16528, 16529, 16530, 16531, 16532, 16533, 16534, 16535, 16536, 16537, 16538, 16539, 16540, 16541, 16542, 16543, 16544, 16545, 16546, 16547, 16548, 16549, 16550, 16551, 16552, 16553, 16554, 16555, 16556, 16557, 16558, 16559, 16560, 16561, 16562, 16563, 16564, 16565, 16566, 16567, 16568, 16569, 16570, 16571, 16572, 16573, 16574, 16575, 16576, 16577, 16578, 16579, 16580, 16581, 16582, 16583, 16584, 16585, 16586, 16587, 16588, 16589, 16590, 16591, 16592, 16593, 16594, 16595, 16596, 16597, 16598, 16599, 16600, 16601, 16602, 16603, 16604, 16605, 16606, 16607, 16608, 16609, 16610, 16611, 16612, 16613, 16614, 16615, 16616, 16617, 16618, 16619, 16620, 16621, 16622, 16623, 16624, 16625, 16626, 16627, 16628, 16629, 16630, 16631, 16632, 16633, 16634, 16635, 16636, 16637, 16638, 16639, 16640, 16641, 16642, 16643, 16644, 16645, 16646, 16647, 16648, 16649, 16650, 16651, 16652, 16653, 16654, 16655, 16656, 16657, 16658, 16659, 16660, 16661, 16662, 16663, 16664, 16665, 16666, 16667, 16668, 16669, 16670, 16671, 16672, 16673, 16674, 16675, 16676, 16677, 16678, 16679, 16680, 16681, 16682, 16683, 16684, 16685, 16686, 16687, 16688, 16689, 16690, 16691, 16692, 16693, 16694, 16695, 16696, 16697, 16698, 16699, 16700, 16701, 16702, 16703, 16704, 16705, 16706, 16707, 16708, 16709, 16710, 16711, 16712, 16713, 16714, 16715, 16716, 16717, 16718, 16719, 16720, 16721, 16722, 16723, 16724, 16725, 16726, 16727, 16728, 16729, 16730, 16731, 16732, 16733, 16734, 16735, 16736, 16737, 16738, 16739, 16740, 16741, 16742, 16743, 16744, 16745, 16746, 16747, 16748, 16749, 16750, 16751, 16752, 16753, 16754, 16755, 16756, 16757, 16758, 16759, 16760, 16761, 16762, 16763, 16764, 16765, 16766, 16767, 16768, 16769, 16770, 16771, 16772, 16773, 16774, 16775, 16776, 16777, 16778, 16779, 16780, 16781, 16782, 16783, 16784, 16785, 16786, 16787, 16788, 16789, 16790, 16791, 16792, 16793, 16794, 16795, 16796, 16797, 16798, 16799, 16800, 16801, 16802, 16803, 16804, 16805, 16806, 16807, 16808, 16809, 16810, 16811, 16812, 16813, 16814, 16815, 16816, 16817, 16818, 16819, 16820, 16821, 16822, 16823, 16824, 16825, 16826, 16827, 16828, 16829, 16830, 16831, 16832, 16833, 16834, 16835, 16836, 16837, 16838, 16839, 16840, 16841, 16842, 16843, 16844, 16845, 16846, 16847, 16848, 16849, 16850, 16851, 16852, 16853, 16854, 16855, 16856, 16857, 16858, 16859, 16860, 16861, 16862, 16863, 16864, 16865, 16866, 16867, 16868, 16869, 16870, 16871, 16872, 16873, 16874, 16875, 16876, 16877, 16878, 16879, 16880, 16881, 16882, 16883, 16884, 16885, 16886, 16887, 16888, 16889, 16890, 16891, 16892, 16893, 16894, 16895, 16896, 16897, 16898, 16899, 16900, 16901, 16902, 16903, 16904, 16905, 16906, 16907, 16908, 16909, 16910, 16911, 16912, 16913, 16914, 16915, 16916, 16917, 16918, 16919, 16920, 16921, 16922, 16923, 16924, 16925, 16926, 16927, 16928, 16929, 16930, 16931, 16932, 16933, 16934, 16935, 16936, 16937, 16938, 16939, 16940, 16941, 16942, 16943, 16944, 16945, 16946, 16947, 16948, 16949, 16950, 16951, 16952, 16953, 16954, 16955, 16956, 16957, 16958, 16959, 16960, 16961, 16962, 16963, 16964, 16965, 16966, 16967, 16968, 16969, 16970, 16971, 16972, 16973, 16974, 16975, 16976, 16977, 16978, 16979, 16980, 16981, 16982, 16983, 16984, 16985, 16986, 16987, 16988, 16989, 16990, 16991, 16992, 16993, 16994, 16995, 16996, 16997, 16998, 16999, 17000, 17001, 17002, 17003, 17004, 17005, 17006, 17007, 17008, 17009, 17010, 17011, 17012, 17013, 17014, 17015, 17016, 17017, 17018, 17019, 17020, 17021, 17022, 17023, 17024, 17025, 17026, 17027, 17028, 17029, 17030, 17031, 17032, 17033, 17034, 17035, 17036, 17037, 17038, 17039, 17040, 17041, 17042, 17043, 17044, 17045, 17046, 17047, 17048, 17049, 17050, 17051, 17052, 17053, 17054, 17055, 17056, 17057, 17058, 17059, 17060, 17061, 17062, 17063, 17064, 17065, 17066, 17067, 17068, 17069, 17070, 17071, 17072, 17073, 17074, 17075, 17076, 17077, 17078, 17079, 17080, 17081, 17082, 17083, 17084, 17085, 17086, 17087, 17088, 17089, 17090, 17091, 17092, 17093, 17094, 17095, 17096, 17097, 17098, 17099, 17100, 17101, 17102, 17103, 17104, 17105, 17106, 17107, 17108, 17109, 17110, 17111, 17112, 17113, 17114, 17115, 17116, 17117, 17118, 17119, 17120, 17121, 17122, 17123, 17124, 17125, 17126, 17127, 17128, 17129, 17130, 17131, 17132, 17133, 17134, 17135, 17136, 17137, 17138, 17139, 17140, 17141, 17142, 17143, 17144, 17145, 17146, 17147, 17148, 17149, 17150, 17151, 17152, 17153, 17154, 17155, 17156, 17157, 17158, 17159, 17160, 17161, 17162, 17163, 17164, 17165, 17166, 17167, 17168, 17169, 17170, 17171, 17172, 17173, 17174, 17175, 17176, 17177, 17178, 17179, 17180, 17181, 17182, 17183, 17184, 17185, 17186, 17187, 17188, 17189, 17190, 17191, 17192, 17193, 17194, 17195, 17196, 17197, 17198, 17199, 17200, 17201, 17202, 17203, 17204, 17205, 17206, 17207, 17208, 17209, 17210, 17211, 17212, 17213, 17214, 17215, 17216, 17217, 17218, 17219, 17220, 17221, 17222, 17223, 17224, 17225, 17226, 17227, 17228, 17229, 17230, 17231, 17232, 17233, 17234, 17235, 17236, 17237, 17238, 17239, 17240, 17241, 17242, 17243, 17244, 17245, 17246, 17247, 17248, 17249, 17250, 17251, 17252, 17253, 17254, 17255, 17256, 17257, 17258, 17259, 17260, 17261, 17262, 17263, 17264, 17265, 17266, 17267, 17268, 17269, 17270, 17271, 17272, 17273, 17274, 17275, 17276, 17277, 17278, 17279, 17280, 17281, 17282, 17283, 17284, 17285, 17286, 17287, 17288, 17289, 17290, 17291, 17292, 17293, 17294, 17295, 17296, 17297, 17298, 17299, 17300, 17301, 17302, 17303, 17304, 17305, 17306, 17307, 17308, 17309, 17310, 17311, 17312, 17313, 17314, 17315, 17316, 17317, 17318, 17319, 17320, 17321, 17322, 17323, 17324, 17325, 17326, 17327, 17328, 17329, 17330, 17331, 17332, 17333, 17334, 17335, 17336, 17337, 17338, 17339, 17340, 17341, 17342, 17343, 17344, 17345, 17346, 17347, 17348, 17349, 17350, 17351, 17352, 17353, 17354, 17355, 17356, 17357, 17358, 17359, 17360, 17361, 17362, 17363, 17364, 17365, 17366, 17367, 17368, 17369, 17370, 17371, 17372, 17373, 17374, 17375, 17376, 17377, 17378, 17379, 17380, 17381, 17382, 17383, 17384, 17385, 17386, 17387, 17388, 17389, 17390, 17391, 17392, 17393, 17394, 17395, 17396, 17397, 17398, 17399, 17400, 17401, 17402, 17403, 17404, 17405, 17406, 17407, 17408, 17409, 17410, 17411, 17412, 17413, 17414, 17415, 17416, 17417, 17418, 17419, 17420, 17421, 17422, 17423, 17424, 17425, 17426, 17427, 17428, 17429, 17430, 17431, 17432, 17433, 17434, 17435, 17436, 17437, 17438, 17439, 17440, 17441, 17442, 17443, 17444, 17445, 17446, 17447, 17448, 17449, 17450, 17451, 17452, 17453, 17454, 17455, 17456, 17457, 17458, 17459, 17460, 17461, 17462, 17463, 17464, 17465, 17466, 17467, 17468, 17469, 17470, 17471, 17472, 17473, 17474, 17475, 17476, 17477, 17478, 17479, 17480, 17481, 17482, 17483, 17484, 17485, 17486, 17487, 17488, 17489, 17490, 17491, 17492, 17493, 17494, 17495, 17496, 17497, 17498, 17499, 17500, 17501, 17502, 17503, 17504, 17505, 17506, 17507, 17508, 17509, 17510, 17511, 17512, 17513, 17514, 17515, 17516, 17517, 17518, 17519, 17520, 17521, 17522, 17523, 17524, 17525, 17526, 17527, 17528, 17529, 17530, 17531, 17532, 17533, 17534, 17535, 17536, 17537, 17538, 17539, 17540, 17541, 17542, 17543, 17544, 17545, 17546, 17547, 17548, 17549, 17550, 17551, 17552, 17553, 17554, 17555, 17556, 17557, 17558, 17559, 17560, 17561, 17562, 17563, 17564, 17565, 17566, 17567, 17568, 17569, 17570, 17571, 17572, 17573, 17574, 17575, 17576, 17577, 17578, 17579, 17580, 17581, 17582, 17583, 17584, 17585, 17586, 17587, 17588, 17589, 17590, 17591, 17592, 17593, 17594, 17595, 17596, 17597, 17598, 17599, 17600, 17601, 17602, 17603, 17604, 17605, 17606, 17607, 17608, 17609, 17610, 17611, 17612, 17613, 17614, 17615, 17616, 17617, 17618, 17619, 17620, 17621, 17622, 17623, 17624, 17625, 17626, 17627, 17628, 17629, 17630, 17631, 17632, 17633, 17634, 17635, 17636, 17637, 17638, 17639, 17640, 17641, 17642, 17643, 17644, 17645, 17646, 17647, 17648, 17649, 17650, 17651, 17652, 17653, 17654, 17655, 17656, 17657, 17658, 17659, 17660, 17661, 17662, 17663, 17664, 17665, 17666, 17667, 17668, 17669, 17670, 17671, 17672, 17673, 17674, 17675, 17676, 17677, 17678, 17679, 17680, 17681, 17682, 17683, 17684, 17685, 17686, 17687, 17688, 17689, 17690, 17691, 17692, 17693, 17694, 17695, 17696, 17697, 17698, 17699, 17700, 17701, 17702, 17703, 17704, 17705, 17706, 17707, 17708, 17709, 17710, 17711, 17712, 17713, 17714, 17715, 17716, 17717, 17718, 17719, 17720, 17721, 17722, 17723, 17724, 17725, 17726, 17727, 17728, 17729, 17730, 17731, 17732, 17733, 17734, 17735, 17736, 17737, 17738, 17739, 17740, 17741, 17742, 17743, 17744, 17745, 17746, 17747, 17748, 17749, 17750, 17751, 17752, 17753, 17754, 17755, 17756, 17757, 17758, 17759, 17760, 17761, 17762, 17763, 17764, 17765, 17766, 17767, 17768, 17769, 17770, 17771, 17772, 17773, 17774, 17775, 17776, 17777, 17778, 17779, 17780, 17781, 17782, 17783, 17784, 17785, 17786, 17787, 17788, 17789, 17790, 17791, 17792, 17793, 17794, 17795, 17796, 17797, 17798, 17799, 17800, 17801, 17802, 17803, 17804, 17805, 17806, 17807, 17808, 17809, 17810, 17811, 17812, 17813, 17814, 17815, 17816, 17817, 17818, 17819, 17820, 17821, 17822, 17823, 17824, 17825, 17826, 17827, 17828, 17829, 17830, 17831, 17832, 17833, 17834, 17835, 17836, 17837, 17838, 17839, 17840, 17841, 17842, 17843, 17844, 17845, 17846, 17847, 17848, 17849, 17850, 17851, 17852, 17853, 17854, 17855, 17856, 17857, 17858, 17859, 17860, 17861, 17862, 17863, 17864, 17865, 17866, 17867, 17868, 17869, 17870, 17871, 17872, 17873, 17874, 17875, 17876, 17877, 17878, 17879, 17880, 17881, 17882, 17883, 17884, 17885, 17886, 17887, 17888, 17889, 17890, 17891, 17892, 17893, 17894, 17895, 17896, 17897, 17898, 17899, 17900, 17901, 17902, 17903, 17904, 17905, 17906, 17907, 17908, 17909, 17910, 17911, 17912, 17913, 17914, 17915, 17916, 17917, 17918, 17919, 17920, 17921, 17922, 17923, 17924, 17925, 17926, 17927, 17928, 17929, 17930, 17931, 17932, 17933, 17934, 17935, 17936, 17937, 17938, 17939, 17940, 17941, 17942, 17943, 17944, 17945, 17946, 17947, 17948, 17949, 17950, 17951, 17952, 17953, 17954, 17955, 17956, 17957, 17958, 17959, 17960, 17961, 17962, 17963, 17964, 17965, 17966, 17967, 17968, 17969, 17970, 17971, 17972, 17973, 17974, 17975, 17976, 17977, 17978, 17979, 17980, 17981, 17982, 17983, 17984, 17985, 17986, 17987, 17988, 17989, 17990, 17991, 17992, 17993, 17994, 17995, 17996, 17997, 17998, 17999, 18000, 18001, 18002, 18003, 18004, 18005, 18006, 18007, 18008, 18009, 18010, 18011, 18012, 18013, 18014, 18015, 18016, 18017, 18018, 18019, 18020, 18021, 18022, 18023, 18024, 18025, 18026, 18027, 18028, 18029, 18030, 18031, 18032, 18033, 18034, 18035, 18036, 18037, 18038, 18039, 18040, 18041, 18042, 18043, 18044, 18045, 18046, 18047, 18048, 18049, 18050, 18051, 18052, 18053, 18054, 18055, 18056, 18057, 18058, 18059, 18060, 18061, 18062, 18063, 18064, 18065, 18066, 18067, 18068, 18069, 18070, 18071, 18072, 18073, 18074, 18075, 18076, 18077, 18078, 18079, 18080, 18081, 18082, 18083, 18084, 18085, 18086, 18087, 18088, 18089, 18090, 18091, 18092, 18093, 18094, 18095, 18096, 18097, 18098, 18099, 18100, 18101, 18102, 18103, 18104, 18105, 18106, 18107, 18108, 18109, 18110, 18111, 18112, 18113, 18114, 18115, 18116, 18117, 18118, 18119, 18120, 18121, 18122, 18123, 18124, 18125, 18126, 18127, 18128, 18129, 18130, 18131, 18132, 18133, 18134, 18135, 18136, 18137, 18138, 18139, 18140, 18141, 18142, 18143, 18144, 18145, 18146, 18147, 18148, 18149, 18150, 18151, 18152, 18153, 18154, 18155, 18156, 18157, 18158, 18159, 18160, 18161, 18162, 18163, 18164, 18165, 18166, 18167, 18168, 18169, 18170, 18171, 18172, 18173, 18174, 18175, 18176, 18177, 18178, 18179, 18180, 18181, 18182, 18183, 18184, 18185, 18186, 18187, 18188, 18189, 18190, 18191, 18192, 18193, 18194, 18195, 18196, 18197, 18198, 18199, 18200, 18201, 18202, 18203, 18204, 18205, 18206, 18207, 18208, 18209, 18210, 18211, 18212, 18213, 18214, 18215, 18216, 18217, 18218, 18219, 18220, 18221, 18222, 18223, 18224, 18225, 18226, 18227, 18228, 18229, 18230, 18231, 18232, 18233, 18234, 18235, 18236, 18237, 18238, 18239, 18240, 18241, 18242, 18243, 18244, 18245, 18246, 18247, 18248, 18249, 18250, 18251, 18252, 18253, 18254, 18255, 18256, 18257, 18258, 18259, 18260, 18261, 18262, 18263, 18264, 18265, 18266, 18267, 18268, 18269, 18270, 18271, 18272, 18273, 18274, 18275, 18276, 18277, 18278, 18279, 18280, 18281, 18282, 18283, 18284, 18285, 18286, 18287, 18288, 18289, 18290, 18291, 18292, 18293, 18294, 18295, 18296, 18297, 18298, 18299, 18300, 18301, 18302, 18303, 18304, 18305, 18306, 18307, 18308, 18309, 18310, 18311, 18312, 18313, 18314, 18315, 18316, 18317, 18318, 18319, 18320, 18321, 18322, 18323, 18324, 18325, 18326, 18327, 18328, 18329, 18330, 18331, 18332, 18333, 18334, 18335, 18336, 18337, 18338, 18339, 18340, 18341, 18342, 18343, 18344, 18345, 18346, 18347, 18348, 18349, 18350, 18351, 18352, 18353, 18354, 18355, 18356, 18357, 18358, 18359, 18360, 18361, 18362, 18363, 18364, 18365, 18366, 18367, 18368, 18369, 18370, 18371, 18372, 18373, 18374, 18375, 18376, 18377, 18378, 18379, 18380, 18381, 18382, 18383, 18384, 18385, 18386, 18387, 18388, 18389, 18390, 18391, 18392, 18393, 18394, 18395, 18396, 18397, 18398, 18399, 18400, 18401, 18402, 18403, 18404, 18405, 18406, 18407, 18408, 18409, 18410, 18411, 18412, 18413, 18414, 18415, 18416, 18417, 18418, 18419, 18420, 18421, 18422, 18423, 18424, 18425, 18426, 18427, 18428, 18429, 18430, 18431, 18432, 18433, 18434, 18435, 18436, 18437, 18438, 18439, 18440, 18441, 18442, 18443, 18444, 18445, 18446, 18447, 18448, 18449, 18450, 18451, 18452, 18453, 18454, 18455, 18456, 18457, 18458, 18459, 18460, 18461, 18462, 18463, 18464, 18465, 18466, 18467, 18468, 18469, 18470, 18471, 18472, 18473, 18474, 18475, 18476, 18477, 18478, 18479, 18480, 18481, 18482, 18483, 18484, 18485, 18486, 18487, 18488, 18489, 18490, 18491, 18492, 18493, 18494, 18495, 18496, 18497, 18498, 18499, 18500, 18501, 18502, 18503, 18504, 18505, 18506, 18507, 18508, 18509, 18510, 18511, 18512, 18513, 18514, 18515, 18516, 18517, 18518, 18519, 18520, 18521, 18522, 18523, 18524, 18525, 18526, 18527, 18528, 18529, 18530, 18531, 18532, 18533, 18534, 18535, 18536, 18537, 18538, 18539, 18540, 18541, 18542, 18543, 18544, 18545, 18546, 18547, 18548, 18549, 18550, 18551, 18552, 18553, 18554, 18555, 18556, 18557, 18558, 18559, 18560, 18561, 18562, 18563, 18564, 18565, 18566, 18567, 18568, 18569, 18570, 18571, 18572, 18573, 18574, 18575, 18576, 18577, 18578, 18579, 18580, 18581, 18582, 18583, 18584, 18585, 18586, 18587, 18588, 18589, 18590, 18591, 18592, 18593, 18594, 18595, 18596, 18597, 18598, 18599, 18600, 18601, 18602, 18603, 18604, 18605, 18606, 18607, 18608, 18609, 18610, 18611, 18612, 18613, 18614, 18615, 18616, 18617, 18618, 18619, 18620, 18621, 18622, 18623, 18624, 18625, 18626, 18627, 18628, 18629, 18630, 18631, 18632, 18633, 18634, 18635, 18636, 18637, 18638, 18639, 18640, 18641, 18642, 18643, 18644, 18645, 18646, 18647, 18648, 18649, 18650, 18651, 18652, 18653, 18654, 18655, 18656, 18657, 18658, 18659, 18660, 18661, 18662, 18663, 18664, 18665, 18666, 18667, 18668, 18669, 18670, 18671, 18672, 18673, 18674, 18675, 18676, 18677, 18678, 18679, 18680, 18681, 18682, 18683, 18684, 18685, 18686, 18687, 18688, 18689, 18690, 18691, 18692, 18693, 18694, 18695, 18696, 18697, 18698, 18699, 18700, 18701, 18702, 18703, 18704, 18705, 18706, 18707, 18708, 18709, 18710, 18711, 18712, 18713, 18714, 18715, 18716, 18717, 18718, 18719, 18720, 18721, 18722, 18723, 18724, 18725, 18726, 18727, 18728, 18729, 18730, 18731, 18732, 18733, 18734, 18735, 18736, 18737, 18738, 18739, 18740, 18741, 18742, 18743, 18744, 18745, 18746, 18747, 18748, 18749, 18750, 18751, 18752, 18753, 18754, 18755, 18756, 18757, 18758, 18759, 18760, 18761, 18762, 18763, 18764, 18765, 18766, 18767, 18768, 18769, 18770, 18771, 18772, 18773, 18774, 18775, 18776, 18777, 18778, 18779, 18780, 18781, 18782, 18783, 18784, 18785, 18786, 18787, 18788, 18789, 18790, 18791, 18792, 18793, 18794, 18795, 18796, 18797, 18798, 18799, 18800, 18801, 18802, 18803, 18804, 18805, 18806, 18807, 18808, 18809, 18810, 18811, 18812, 18813, 18814, 18815, 18816, 18817, 18818, 18819, 18820, 18821, 18822, 18823, 18824, 18825, 18826, 18827, 18828, 18829, 18830, 18831, 18832, 18833, 18834, 18835, 18836, 18837, 18838, 18839, 18840, 18841, 18842, 18843, 18844, 18845, 18846, 18847, 18848, 18849, 18850, 18851, 18852, 18853, 18854, 18855, 18856, 18857, 18858, 18859, 18860, 18861, 18862, 18863, 18864, 18865, 18866, 18867, 18868, 18869, 18870, 18871, 18872, 18873, 18874, 18875, 18876, 18877, 18878, 18879, 18880, 18881, 18882, 18883, 18884, 18885, 18886, 18887, 18888, 18889, 18890, 18891, 18892, 18893, 18894, 18895, 18896, 18897, 18898, 18899, 18900, 18901, 18902, 18903, 18904, 18905, 18906, 18907, 18908, 18909, 18910, 18911, 18912, 18913, 18914, 18915, 18916, 18917, 18918, 18919, 18920, 18921, 18922, 18923, 18924, 18925, 18926, 18927, 18928, 18929, 18930, 18931, 18932, 18933, 18934, 18935, 18936, 18937, 18938, 18939, 18940, 18941, 18942, 18943, 18944, 18945, 18946, 18947, 18948, 18949, 18950, 18951, 18952, 18953, 18954, 18955, 18956, 18957, 18958, 18959, 18960, 18961, 18962, 18963, 18964, 18965, 18966, 18967, 18968, 18969, 18970, 18971, 18972, 18973, 18974, 18975, 18976, 18977, 18978, 18979, 18980, 18981, 18982, 18983, 18984, 18985, 18986, 18987, 18988, 18989, 18990, 18991, 18992, 18993, 18994, 18995, 18996, 18997, 18998, 18999, 19000, 19001, 19002, 19003, 19004, 19005, 19006, 19007, 19008, 19009, 19010, 19011, 19012, 19013, 19014, 19015, 19016, 19017, 19018, 19019, 19020, 19021, 19022, 19023, 19024, 19025, 19026] 7 | -------------------------------------------------------------------------------- /utils/add-backstage-github.batch.yaml: -------------------------------------------------------------------------------- 1 | name: add-repo-to-backstage 2 | description: Add scaffold to add this repository to the backstage catalog 3 | 4 | # All repos from a given codehost 5 | on: 6 | - repositoriesMatchingQuery: repo:github\.com 7 | 8 | steps: 9 | # Run comby over the search results in each repository: 10 | - run: | 11 | apk add github-cli; 12 | gh auth login -h github.com; 13 | gh repo view sourcegraph/sourcegraph --json=description,url,name,owner,nameWithOwner,languages > tmp.json; 14 | python /tmp/create-catalog.py; 15 | rm tmp.json 16 | container: python:3-alpine 17 | files: 18 | /tmp/create-catalog.py: | 19 | import json 20 | 21 | TEMPLATE ="""kind: Component 22 | metadata: 23 | name: {} 24 | description: | 25 | {} 26 | links: 27 | - title: Repository 28 | url: {} 29 | annotations: 30 | github.com/project-slug: {} 31 | """ 32 | 33 | with open('tmp.json','r') as f: 34 | metadata = json.load(f) 35 | with open('catalog-info.yml','w+') as out: 36 | out.write(TEMPLATE.format(metadata["name"],metadata["description"],metadata["url"],metadata["nameWithOwner"])) 37 | 38 | # Make sure to set GH_TOKEN in your local shell 39 | # Note: setting env variables/secrets is not yet available when running server-side. Coming soon! 40 | env: 41 | - GH_TOKEN 42 | changesetTemplate: 43 | title: Add this repo to backstage catalog 44 | body: | 45 | This is a scaffold to add this repo to the backstage service catalog. 46 | It's recommended to add configuration details ([example](https://github.com/backstage/backstage/blob/master/catalog-info.yaml)), but you can also merge this changeset as is. 47 | branch: backstage 48 | commit: 49 | message: Add repo to backstage service catalog 50 | -------------------------------------------------------------------------------- /utils/add-backstage-minimal.batch.yaml: -------------------------------------------------------------------------------- 1 | name: add-repo-to-backstage 2 | description: Add scaffold to add this repository to the backstage catalog 3 | 4 | # All repos from a given codehost 5 | on: 6 | - repositoriesMatchingQuery: repo:github\.com 7 | 8 | steps: 9 | # Run comby over the search results in each repository: 10 | - run: | 11 | name=$(echo ${{repository.name}} | awk -F'/' '{print $2}') 12 | cp /tmp/catalog-info.yaml . 13 | sed -i "s/{{name}}/$name/" ./catalog-info.yaml 14 | container: alpine:3 15 | files: 16 | # Create files inside the container by specifying path and content here: 17 | /tmp/catalog-info.yaml: | 18 | kind: Component 19 | metadata: 20 | name: {{name}} 21 | links: 22 | - title: Repository 23 | url: https://www.${{repository.name}} 24 | annotations: 25 | github.com/project-slug: ${{repository.name}} 26 | changesetTemplate: 27 | title: Add this repo to backstage catalog 28 | body: | 29 | This is a scaffold to add this repo to the backstage service catalog. 30 | It's recommended to add configuration details ([example](https://github.com/backstage/backstage/blob/master/catalog-info.yaml)), but you can also merge this changeset as is. 31 | branch: backstage 32 | commit: 33 | message: Add repo to backstage service catalog 34 | -------------------------------------------------------------------------------- /utils/add-file/README.md: -------------------------------------------------------------------------------- 1 | This spec is an example of manipulating files with Batch Changes. It adds a license file along each README.md found in any repository. 2 | 3 | Two different methods are demonstrated to add the file content: 4 | 5 | 1. `add-file.batch.yaml` embeds the file content in the batch spec itself using the [`steps.files`](https://docs.sourcegraph.com/batch_changes/references/batch_spec_yaml_reference#steps-files) element. `steps.files` has been supported since Sourcegraph 3.22. 6 | 2. `mount-file.batch.yaml` mounts the file content from the host filesystem using [`steps.mount`](https://docs.sourcegraph.com/batch_changes/references/batch_spec_yaml_reference#steps-mount). This has been supported since Sourcegraph 3.41 using `src batch preview` and `src batch apply`, and since Sourcegraph 4.1 when executing batch specs [on the server using `src batch remote`](https://docs.sourcegraph.com/batch_changes/how-tos/server_side_file_mounts). 7 | 8 | Both specs also use [template variables](https://docs.sourcegraph.com/batch_changes/references/batch_spec_templating#template-variables) to generate the list of paths the license file should be added at. 9 | 10 | ### Whither `steps.files` or `steps.mount`? 11 | 12 | `steps.files` is more useful when: 13 | 14 | 1. You need to support Sourcegraph versions before `steps.mount` was added, or 15 | 1. The file content is small and self-contained, and therefore isn't a hassle to embed within a batch spec, or 16 | 1. The file content needs to be dynamically generated using [template variables](https://docs.sourcegraph.com/batch_changes/references/batch_spec_templating#template-variables). 17 | 18 | `steps.mount` is more useful when: 19 | 20 | 1. The file content is static, or 21 | 1. The file content is too large to embed in a YAML spec, or 22 | 1. The file is binary that cannot be represented within YAML. 23 | -------------------------------------------------------------------------------- /utils/add-file/add-file.batch.yaml: -------------------------------------------------------------------------------- 1 | name: add-file-at-result-path-using-embedded-file 2 | description: Add file to all paths with a search result. In this example, we add an Apache license beside each README.md file. 3 | 4 | # Find all repositories that contain a README.md file. 5 | on: 6 | - repositoriesMatchingQuery: file:README.md count:200 7 | 8 | # Besides each match, add a LICENSE.md file. Note that repository.search_result_paths is a helper variable provided by the spec templating language. 9 | steps: 10 | - run: | 11 | for result in ${{repository.search_result_paths}}; 12 | do 13 | pushd "$(dirname "$result")" 14 | cat /tmp/apache.txt > LICENSE.md 15 | popd 16 | done 17 | 18 | # We could have just added a single license at the root of each matching repository with 19 | # cat /tmp/apache.txt > LICENSE.md 20 | container: ubuntu:18.04 21 | files: 22 | /tmp/apache.txt: | 23 | Apache License 24 | Version 2.0, January 2004 25 | http://www.apache.org/licenses/ 26 | 27 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 28 | 29 | 1. Definitions. 30 | 31 | "License" shall mean the terms and conditions for use, reproduction, 32 | and distribution as defined by Sections 1 through 9 of this document. 33 | 34 | "Licensor" shall mean the copyright owner or entity authorized by 35 | the copyright owner that is granting the License. 36 | 37 | "Legal Entity" shall mean the union of the acting entity and all 38 | other entities that control, are controlled by, or are under common 39 | control with that entity. For the purposes of this definition, 40 | "control" means (i) the power, direct or indirect, to cause the 41 | direction or management of such entity, whether by contract or 42 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 43 | outstanding shares, or (iii) beneficial ownership of such entity. 44 | 45 | "You" (or "Your") shall mean an individual or Legal Entity 46 | exercising permissions granted by this License. 47 | 48 | "Source" form shall mean the preferred form for making modifications, 49 | including but not limited to software source code, documentation 50 | source, and configuration files. 51 | 52 | "Object" form shall mean any form resulting from mechanical 53 | transformation or translation of a Source form, including but 54 | not limited to compiled object code, generated documentation, 55 | and conversions to other media types. 56 | 57 | "Work" shall mean the work of authorship, whether in Source or 58 | Object form, made available under the License, as indicated by a 59 | copyright notice that is included in or attached to the work 60 | (an example is provided in the Appendix below). 61 | 62 | "Derivative Works" shall mean any work, whether in Source or Object 63 | form, that is based on (or derived from) the Work and for which the 64 | editorial revisions, annotations, elaborations, or other modifications 65 | represent, as a whole, an original work of authorship. For the purposes 66 | of this License, Derivative Works shall not include works that remain 67 | separable from, or merely link (or bind by name) to the interfaces of, 68 | the Work and Derivative Works thereof. 69 | 70 | "Contribution" shall mean any work of authorship, including 71 | the original version of the Work and any modifications or additions 72 | to that Work or Derivative Works thereof, that is intentionally 73 | submitted to Licensor for inclusion in the Work by the copyright owner 74 | or by an individual or Legal Entity authorized to submit on behalf of 75 | the copyright owner. For the purposes of this definition, "submitted" 76 | means any form of electronic, verbal, or written communication sent 77 | to the Licensor or its representatives, including but not limited to 78 | communication on electronic mailing lists, source code control systems, 79 | and issue tracking systems that are managed by, or on behalf of, the 80 | Licensor for the purpose of discussing and improving the Work, but 81 | excluding communication that is conspicuously marked or otherwise 82 | designated in writing by the copyright owner as "Not a Contribution." 83 | 84 | "Contributor" shall mean Licensor and any individual or Legal Entity 85 | on behalf of whom a Contribution has been received by Licensor and 86 | subsequently incorporated within the Work. 87 | 88 | 2. Grant of Copyright License. Subject to the terms and conditions of 89 | this License, each Contributor hereby grants to You a perpetual, 90 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 91 | copyright license to reproduce, prepare Derivative Works of, 92 | publicly display, publicly perform, sublicense, and distribute the 93 | Work and such Derivative Works in Source or Object form. 94 | 95 | 3. Grant of Patent License. Subject to the terms and conditions of 96 | this License, each Contributor hereby grants to You a perpetual, 97 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 98 | (except as stated in this section) patent license to make, have made, 99 | use, offer to sell, sell, import, and otherwise transfer the Work, 100 | where such license applies only to those patent claims licensable 101 | by such Contributor that are necessarily infringed by their 102 | Contribution(s) alone or by combination of their Contribution(s) 103 | with the Work to which such Contribution(s) was submitted. If You 104 | institute patent litigation against any entity (including a 105 | cross-claim or counterclaim in a lawsuit) alleging that the Work 106 | or a Contribution incorporated within the Work constitutes direct 107 | or contributory patent infringement, then any patent licenses 108 | granted to You under this License for that Work shall terminate 109 | as of the date such litigation is filed. 110 | 111 | 4. Redistribution. You may reproduce and distribute copies of the 112 | Work or Derivative Works thereof in any medium, with or without 113 | modifications, and in Source or Object form, provided that You 114 | meet the following conditions: 115 | 116 | (a) You must give any other recipients of the Work or 117 | Derivative Works a copy of this License; and 118 | 119 | (b) You must cause any modified files to carry prominent notices 120 | stating that You changed the files; and 121 | 122 | (c) You must retain, in the Source form of any Derivative Works 123 | that You distribute, all copyright, patent, trademark, and 124 | attribution notices from the Source form of the Work, 125 | excluding those notices that do not pertain to any part of 126 | the Derivative Works; and 127 | 128 | (d) If the Work includes a "NOTICE" text file as part of its 129 | distribution, then any Derivative Works that You distribute must 130 | include a readable copy of the attribution notices contained 131 | within such NOTICE file, excluding those notices that do not 132 | pertain to any part of the Derivative Works, in at least one 133 | of the following places: within a NOTICE text file distributed 134 | as part of the Derivative Works; within the Source form or 135 | documentation, if provided along with the Derivative Works; or, 136 | within a display generated by the Derivative Works, if and 137 | wherever such third-party notices normally appear. The contents 138 | of the NOTICE file are for informational purposes only and 139 | do not modify the License. You may add Your own attribution 140 | notices within Derivative Works that You distribute, alongside 141 | or as an addendum to the NOTICE text from the Work, provided 142 | that such additional attribution notices cannot be construed 143 | as modifying the License. 144 | 145 | You may add Your own copyright statement to Your modifications and 146 | may provide additional or different license terms and conditions 147 | for use, reproduction, or distribution of Your modifications, or 148 | for any such Derivative Works as a whole, provided Your use, 149 | reproduction, and distribution of the Work otherwise complies with 150 | the conditions stated in this License. 151 | 152 | 5. Submission of Contributions. Unless You explicitly state otherwise, 153 | any Contribution intentionally submitted for inclusion in the Work 154 | by You to the Licensor shall be under the terms and conditions of 155 | this License, without any additional terms or conditions. 156 | Notwithstanding the above, nothing herein shall supersede or modify 157 | the terms of any separate license agreement you may have executed 158 | with Licensor regarding such Contributions. 159 | 160 | 6. Trademarks. This License does not grant permission to use the trade 161 | names, trademarks, service marks, or product names of the Licensor, 162 | except as required for reasonable and customary use in describing the 163 | origin of the Work and reproducing the content of the NOTICE file. 164 | 165 | 7. Disclaimer of Warranty. Unless required by applicable law or 166 | agreed to in writing, Licensor provides the Work (and each 167 | Contributor provides its Contributions) on an "AS IS" BASIS, 168 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 169 | implied, including, without limitation, any warranties or conditions 170 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 171 | PARTICULAR PURPOSE. You are solely responsible for determining the 172 | appropriateness of using or redistributing the Work and assume any 173 | risks associated with Your exercise of permissions under this License. 174 | 175 | 8. Limitation of Liability. In no event and under no legal theory, 176 | whether in tort (including negligence), contract, or otherwise, 177 | unless required by applicable law (such as deliberate and grossly 178 | negligent acts) or agreed to in writing, shall any Contributor be 179 | liable to You for damages, including any direct, indirect, special, 180 | incidental, or consequential damages of any character arising as a 181 | result of this License or out of the use or inability to use the 182 | Work (including but not limited to damages for loss of goodwill, 183 | work stoppage, computer failure or malfunction, or any and all 184 | other commercial damages or losses), even if such Contributor 185 | has been advised of the possibility of such damages. 186 | 187 | 9. Accepting Warranty or Additional Liability. While redistributing 188 | the Work or Derivative Works thereof, You may choose to offer, 189 | and charge a fee for, acceptance of support, warranty, indemnity, 190 | or other liability obligations and/or rights consistent with this 191 | License. However, in accepting such obligations, You may act only 192 | on Your own behalf and on Your sole responsibility, not on behalf 193 | of any other Contributor, and only if You agree to indemnify, 194 | defend, and hold each Contributor harmless for any liability 195 | incurred by, or claims asserted against, such Contributor by reason 196 | of your accepting any such warranty or additional liability. 197 | 198 | END OF TERMS AND CONDITIONS 199 | 200 | APPENDIX: How to apply the Apache License to your work. 201 | 202 | To apply the Apache License to your work, attach the following 203 | boilerplate notice, with the fields enclosed by brackets "[]" 204 | replaced with your own identifying information. (Don't include 205 | the brackets!) The text should be enclosed in the appropriate 206 | comment syntax for the file format. We also recommend that a 207 | file or class name and description of purpose be included on the 208 | same "printed page" as the copyright notice for easier 209 | identification within third-party archives. 210 | 211 | Copyright 2018 Sourcegraph, Inc. 212 | 213 | Licensed under the Apache License, Version 2.0 (the "License"); 214 | you may not use this file except in compliance with the License. 215 | You may obtain a copy of the License at 216 | 217 | http://www.apache.org/licenses/LICENSE-2.0 218 | 219 | Unless required by applicable law or agreed to in writing, software 220 | distributed under the License is distributed on an "AS IS" BASIS, 221 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 222 | See the License for the specific language governing permissions and 223 | limitations under the License. 224 | 225 | # Describe the changeset (e.g., GitHub pull request) you want for each repository. 226 | changesetTemplate: 227 | title: Add Apache licenses via an embedded file 228 | body: Add Apache licenses alongside README.md files. 229 | branch: add-license-via-embedded-file 230 | commit: 231 | message: Add Apache license(s) 232 | -------------------------------------------------------------------------------- /utils/add-file/apache.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2018 Sourcegraph, Inc. 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /utils/add-file/mount-file.batch.yaml: -------------------------------------------------------------------------------- 1 | name: add-file-at-result-path-using-mounting 2 | description: Add file to all paths with a search result. In this example, we add an Apache license beside each README.md file. 3 | 4 | # Find all repositories that contain a README.md file. 5 | on: 6 | - repositoriesMatchingQuery: file:README.md count:200 7 | 8 | # Beside each match, add a LICENSE.md file. Note that repository.search_result_paths is a helper variable provided by the spec templating language. 9 | steps: 10 | - run: | 11 | for result in ${{repository.search_result_paths}}; 12 | do 13 | pushd "$(dirname "$result")" 14 | cat /tmp/apache.txt > LICENSE.md 15 | popd 16 | done 17 | 18 | # We could have just added a single license at the root of each matching repository with 19 | # cat /tmp/apache.txt > LICENSE.md 20 | container: ubuntu:18.04 21 | mount: 22 | # Note that this requires apache.txt to be available at the same level as the batch spec. 23 | # To execute on the server, use `src batch remote -f mount-file.batch.yaml`. 24 | - path: ./apache.txt 25 | mountpoint: /tmp/apache.txt 26 | 27 | # Describe the changeset (e.g., GitHub pull request) you want for each repository. 28 | changesetTemplate: 29 | title: Add Apache licenses via file mounting 30 | body: Add Apache licenses alongside README.md files. 31 | branch: add-license-via-mounted-file 32 | commit: 33 | message: Add Apache license(s) 34 | -------------------------------------------------------------------------------- /utils/branch-addressing.yaml: -------------------------------------------------------------------------------- 1 | name: branch-addressing 2 | description: Addressing a single changeset by branch name 3 | 4 | on: 5 | - repository: github.com/sourcegraph/automation-testing 6 | 7 | workspaces: 8 | - rootAtLocationOf: package.json 9 | in: github.com/sourcegraph/automation-testing 10 | 11 | steps: 12 | - run: | 13 | echo "We are in $(basename $(pwd))" >> message.txt && 14 | basename $(pwd) 15 | container: alpine:3 16 | outputs: 17 | directoryName: 18 | value: ${{ step.stdout }} 19 | 20 | changesetTemplate: 21 | title: Branch addressing 22 | body: Addressing a single changeset by branch name 23 | commit: 24 | message: Branch addressing 25 | branch: thorsten/branch-addressing-${{ outputs.directoryName }} 26 | published: 27 | - github.com/sourcegraph/automation-*@thorsten/branch-addressing-project1: draft 28 | -------------------------------------------------------------------------------- /utils/dynamic-changeset-template.batch.yaml: -------------------------------------------------------------------------------- 1 | name: dynamic-changeset-template 2 | description: Hello Outputs 3 | 4 | on: 5 | - repository: github.com/sourcegraph/src-cli 6 | 7 | steps: 8 | - run: echo "Hello there!" >> message.txt && cat message.txt 9 | container: alpine:3 10 | # NEW: 11 | outputs: 12 | friendlyMessage: 13 | value: "${{ step.stdout }}" 14 | # format: text is implicit 15 | - run: cat .goreleaser.yml >&2 16 | container: alpine:3 17 | # NEW: 18 | outputs: 19 | goreleaserConfig: 20 | value: "${{ step.stderr }}" 21 | # we will parse the value here as YAML, meaning that we can access it as an object 22 | format: yaml 23 | goreleaserConfigExists: 24 | # we can use the power of Go's text/template engine to dynamically produce complex values 25 | value: "exists: ${{ gt (len step.stderr) 0 }}" 26 | format: yaml 27 | 28 | changesetTemplate: 29 | # title allows templating 30 | title: "The friendly message is: `${{ outputs.friendlyMessage }}`" 31 | # body allows templating 32 | body: | 33 | This repository has a `gorelaserConfig`: ${{ outputs.goreleaserConfigExists.exists }}. 34 | 35 | (Since these are just Go `text/templates` and `goreleaserConfig` was parsed as YAML we can access every field) 36 | 37 | The `goreleaser.yml` defines the following `before.hooks`: 38 | 39 | ${{ range $index, $hook := outputs.goreleaserConfig.before.hooks }} 40 | - `${{ $hook }}` 41 | ${{ end }} 42 | 43 | # branch allows templating 44 | branch: thorsten/variables-${{ outputs.goreleaserConfig.dist }} 45 | published: draft 46 | commit: 47 | # commit message allows templating 48 | message: "The friendly message is: `${{ outputs.friendlyMessage }}`" 49 | -------------------------------------------------------------------------------- /utils/templated-files.batch.yaml: -------------------------------------------------------------------------------- 1 | name: templated-and-files 2 | description: Use template variables and mount files in batch change specs 3 | 4 | on: 5 | - repositoriesMatchingQuery: repo:automation-testing lang:go fmt.Sprintf("%d", :[v]) patterntype:structural -file:vendor count:5 6 | 7 | steps: 8 | # Run comby over the search results in each repository: 9 | - run: comby -in-place -config /tmp/go-sprintf.toml -f ${{ join repository.search_result_paths "," }} 10 | container: comby/comby 11 | files: 12 | # Create files inside the container by specifying path and content here: 13 | /tmp/go-sprintf.toml: | 14 | [sprintf_to_strconv] 15 | match='fmt.Sprintf("%d", :[v])' 16 | rewrite='strconv.Itoa(:[v])' 17 | 18 | - run: echo "comby found the following problems:" >> CHANGELOG.md && cat /tmp/comby-output.txt >> CHANGELOG.md 19 | container: alpine:3 20 | files: 21 | # files also support templating: 22 | /tmp/comby-output.txt: ${{ previous_step.stdout }} 23 | 24 | - run: echo $MY_MODIFIED_FILES >> modified_files.txt 25 | container: alpine:3 26 | env: 27 | # env vars also support templating: 28 | MY_MODIFIED_FILES: ${{ join previous_step.modified_files "\n" }} 29 | 30 | changesetTemplate: 31 | title: templated-and-files 32 | body: My not-first batch change! 33 | branch: batch-changetesting-files 34 | commit: 35 | message: Code your code with templates 36 | published: false 37 | -------------------------------------------------------------------------------- /utils/workspace-discovery-additional-files.yaml: -------------------------------------------------------------------------------- 1 | name: workspace-discovery 2 | description: Automatic workspace discovery 3 | 4 | on: 5 | - repositoriesMatchingQuery: repo:automation-testing$ 6 | 7 | workspaces: 8 | - rootAtLocationOf: package.json 9 | in: "github.com/sourcegraph/automation-testing" 10 | 11 | steps: 12 | - run: "echo \"pwd: $(pwd)\nfiles in /work:\n$(find /work ! -path \"/work/.git/*\")\" >> message.txt" 13 | container: alpine:3 14 | 15 | changesetTemplate: 16 | title: Only download workspace discovery 17 | body: Only download workspace discovery 18 | branch: ${{ join_if "-" "thorsten/workspace-discovery" (replace steps.path "/" "-") }} 19 | published: false 20 | commit: 21 | message: Only download workspace discovery 22 | -------------------------------------------------------------------------------- /utils/workspace-discovery.yaml: -------------------------------------------------------------------------------- 1 | name: workspace-discovery 2 | description: Automatic workspace discovery 3 | 4 | on: 5 | - repositoriesMatchingQuery: repo:automation-testing$ 6 | - repository: github.com/sourcegraph/sourcegraph 7 | 8 | workspaces: 9 | - rootAtLocationOf: go.mod 10 | in: github.com/sourcegraph/sourcegraph* 11 | - rootAtLocationOf: package.json 12 | in: "github.com/sourcegraph/automation-testing" 13 | onlyFetchWorkspace: true 14 | 15 | steps: 16 | - run: "echo \"pwd: $(pwd)\nfiles in /work:\n$(find /work ! -path \"/work/.git/*\")\" >> message.txt" 17 | container: alpine:3 18 | - run: if [[ -f "package.json" ]]; then cat package.json | jq -j .name; fi 19 | container: jiapantw/jq-alpine:latest 20 | outputs: 21 | projectName: 22 | value: ${{ step.stdout }} 23 | 24 | changesetTemplate: 25 | title: Automatic workspace discovery 26 | body: Automatic workspace discovery 27 | 28 | # If we have an `outputs.projectName` we use it, otherwise we append the path 29 | # of the workspace. If the path is emtpy (as is the case in the root folder), 30 | # we ignore it. 31 | branch: | 32 | ${{ if eq outputs.projectName "" }} 33 | ${{ join_if "-" "thorsten/workspace-discovery" (replace steps.path "/" "-") }} 34 | ${{ else }} 35 | thorsten/workspace-discovery-${{ outputs.projectName }} 36 | ${{ end }} 37 | published: false 38 | commit: 39 | message: Automatic workspace discovery 40 | -------------------------------------------------------------------------------- /xml/update-maven-dependency-with-transform-changes.yaml: -------------------------------------------------------------------------------- 1 | name: manipulating-xml 2 | description: Manipulate pom.xml files 3 | 4 | # Find the first 100 search results for README files. 5 | # This could yield less than 100 repos/workspaces if some repos contain multiple READMEs. 6 | on: 7 | - repositoriesMatchingQuery: file:pom.xml 8 | 9 | transformChanges: 10 | # Group the file diffs by directory and produce an additional changeset per group. 11 | group: 12 | # Create a separate changeset for all changes in the top-level `ambassador` directory 13 | - directory: ambassador 14 | branch: bo/lombok-upgrade-ambassador # will replace the `branch` in the `changesetTemplate` 15 | 16 | - directory: visitor 17 | branch: bo/lombok-upgrade-visitor # will replace the `branch` in the `changesetTemplate` 18 | 19 | - directory: twin 20 | branch: bo/lombok-upgrade-twin # will replace the `branch` in the `changesetTemplate` 21 | 22 | - directory: abstract-document 23 | branch: bo/lombok-upgrade-abstract-document # will replace the `branch` in the `changesetTemplate` 24 | 25 | # In each repository, run this command. Each repository's resulting diff is captured. 26 | steps: 27 | - run: | 28 | for result in "${{ join repository.search_result_paths " " }}"; do 29 | python /tmp/script.py "${result}"; 30 | done; 31 | container: bolajisourcegraph/python-lxml 32 | if: ${{ matches repository.name "*sourcegraph-testing*" }} 33 | files: 34 | /tmp/script.py: | 35 | import lxml.etree as etree 36 | import sys 37 | 38 | for filename in sys.argv[1].split(' '): 39 | # Parse the XML file 40 | tree = etree.parse(filename) 41 | root = tree.getroot() 42 | 43 | # Find the 'dependencies' element in the XML tree 44 | dependencies = root.find('{http://maven.apache.org/POM/4.0.0}dependencies') 45 | 46 | # Flag to check if the required dependency is found 47 | found_lombok = False 48 | 49 | # Check if the 'dependencies' element exists 50 | if dependencies is not None: 51 | # Iterate over each dependency in the 'dependencies' element 52 | for dep in dependencies: 53 | # Check if the current dependency matches the required criteria 54 | groupId = dep.find('{http://maven.apache.org/POM/4.0.0}groupId') 55 | hasLombokGroupID = groupId is not None and groupId.text == 'org.projectlombok' 56 | 57 | artifactId = dep.find('{http://maven.apache.org/POM/4.0.0}artifactId') 58 | hasLombokArtifactID = artifactId is not None and artifactId.text == 'lombok' 59 | 60 | version = dep.find('{http://maven.apache.org/POM/4.0.0}version') 61 | shouldUpgradeVersion = version is not None and version.text != '1.18.28' 62 | 63 | if hasLombokGroupID and hasLombokArtifactID and shouldUpgradeVersion: 64 | # Update the version of the dependency 65 | version.text = '1.18.28' 66 | tree.write(filename, xml_declaration=True, encoding=tree.docinfo.encoding) 67 | 68 | 69 | # Describe the changeset (e.g., GitHub pull request) you want for each repository. 70 | changesetTemplate: 71 | title: Upgrade lombok dependency 72 | body: | 73 | This PR upgrades the lombok dependency. 74 | commit: 75 | message: Upgrade lombok 76 | branch: bo/lombok-upgrade 77 | -------------------------------------------------------------------------------- /xml/update-maven-dependency.yaml: -------------------------------------------------------------------------------- 1 | name: manipulating-xml 2 | description: Manipulate pom.xml files 3 | 4 | # Find the first 100 search results for README files. 5 | # This could yield less than 100 repos/workspaces if some repos contain multiple READMEs. 6 | on: 7 | - repositoriesMatchingQuery: file:pom.xml repo:^github\.com/sourcegraph-testing/jdp$ 8 | 9 | # In each repository, run this command. Each repository's resulting diff is captured. 10 | steps: 11 | - run: | 12 | for result in "${{ join repository.search_result_paths " " }}"; do 13 | python /tmp/script.py "${result}"; 14 | done; 15 | container: bolajisourcegraph/python-lxml 16 | files: 17 | /tmp/script.py: | 18 | import lxml.etree as etree 19 | import sys 20 | 21 | for filename in sys.argv[1].split(' '): 22 | # Parse the XML file 23 | tree = etree.parse(filename) 24 | root = tree.getroot() 25 | 26 | # Find the 'dependencies' element in the XML tree 27 | dependencies = root.find('{http://maven.apache.org/POM/4.0.0}dependencies') 28 | 29 | # Flag to check if the required dependency is found 30 | found_lombok = False 31 | 32 | # Check if the 'dependencies' element exists 33 | if dependencies is not None: 34 | # Iterate over each dependency in the 'dependencies' element 35 | for dep in dependencies: 36 | # Check if the current dependency matches the required criteria 37 | groupId = dep.find('{http://maven.apache.org/POM/4.0.0}groupId') 38 | hasLombokGroupID = groupId is not None and groupId.text == 'org.projectlombok' 39 | 40 | artifactId = dep.find('{http://maven.apache.org/POM/4.0.0}artifactId') 41 | hasLombokArtifactID = artifactId is not None and artifactId.text == 'lombok' 42 | 43 | version = dep.find('{http://maven.apache.org/POM/4.0.0}version') 44 | shouldUpgradeVersion = version is not None and version.text != '1.18.28' 45 | 46 | if hasLombokGroupID and hasLombokArtifactID and shouldUpgradeVersion: 47 | # Update the version of the dependency 48 | version.text = '1.18.28' 49 | tree.write(filename, xml_declaration=True, encoding=tree.docinfo.encoding) 50 | 51 | 52 | # Describe the changeset (e.g., GitHub pull request) you want for each repository. 53 | changesetTemplate: 54 | title: Upgrade lombok dependency 55 | body: | 56 | This PR upgrades the lombok dependency in the following directories: 57 | 58 | ${{ range $index, $file := steps.modified_files }} 59 | - ${{ $file }} 60 | ${{ end }} 61 | commit: 62 | message: Upgrade lombok 63 | # Optional: Push the commit to a branch named after this batch change by default. 64 | branch: ${{ batch_change.name }} 65 | -------------------------------------------------------------------------------- /xml/update-xml-boilerplate.batch.yaml: -------------------------------------------------------------------------------- 1 | name: update-xml-boilerplate 2 | description: Update Microsoft.NET.Test.Sdk to 16.0.0 3 | 4 | # Repositories containing this package 5 | on: 6 | - repositoriesMatchingQuery: ' '' ${{ join repository.search_result_paths " " }}; 11 | # container: comby/comby 12 | - run: comby -in-place '' '' ${{ join repository.search_result_paths " " }}; 13 | container: comby/comby 14 | # Describe the changeset 15 | changesetTemplate: 16 | title: Update Microsoft.NET.Test.Sdk to 16.0.0 17 | body: This batch change updates Microsoft.NET.Test.Sdk to 16.0.0 18 | branch: batch-changes/update-package # Push the commit to this branch. 19 | commit: 20 | message: update-namespace-target-package 21 | published: false 22 | -------------------------------------------------------------------------------- /yaml/README.md: -------------------------------------------------------------------------------- 1 | # Modify YAML files with a Ruby script 2 | 3 | This batch change demonstrates how to modify YAML files. 4 | 5 | It uses a short Ruby script to read in the `docker-compose.yaml` files returned 6 | by the Sourcegraph search, parse them, and add a new `entrypoint` argument to 7 | existing `services` definitions. 8 | 9 | It then uses a second container to install [prettier](https://prettier.io/) to 10 | format the files that were rewritten by the previous step. 11 | 12 | There are three main ways to pass long scripts to a batch change: 13 | - add the script in the spec using the `file` property, see [modify-yaml](modify-yaml.batch.yaml) 14 | - from Sourcegraph 3.41, mount a local script on the container, see [modify-yaml-mount-file](modify-yaml-mount-file.batch.yaml) 15 | - bake them inside the container -------------------------------------------------------------------------------- /yaml/modify-yaml-mount-file.batch.yaml: -------------------------------------------------------------------------------- 1 | # This spec requires Sourcegraph 3.41 and above. 2 | 3 | name: docker-compose-debug-entrypoint 4 | description: Modify `docker-compose.yaml` files to add the `--debug` argument to `services.entrypoint`s if an `entrypoint` is defined. 5 | 6 | on: 7 | - repositoriesMatchingQuery: 'file:docker-compose.yaml entrypoint: count:10' 8 | 9 | steps: 10 | - run: | 11 | for result in "${{ join repository.search_result_paths " " }}"; do 12 | ruby /tmp/update.rb "${result}" > "${result}.new" 13 | mv "${result}.new" "${result}" 14 | done; 15 | container: ruby 16 | mount: 17 | - path: ./update-yaml.rb 18 | mountpoint: /tmp/update.rb 19 | - run: | 20 | npm install -g prettier && 21 | (npx prettier --write "${{ join previous_step.modified_files " "}}" || exit 0) 22 | container: node 23 | 24 | changesetTemplate: 25 | title: Add `--debug` to entrypoints in docker-compose.yaml 26 | body: | 27 | This adds the `--debug` flag to all service entrypoints in the 28 | `docker-compose.yaml`, if they have a `entrypoint` defined. 29 | branch: batch-changes/docker-compose-debug-entrypoint 30 | published: false 31 | commit: 32 | message: Add `--debug` to existing `entrypoint`s in `docker-compose.yaml` 33 | -------------------------------------------------------------------------------- /yaml/modify-yaml.batch.yaml: -------------------------------------------------------------------------------- 1 | name: docker-compose-debug-entrypoint 2 | description: Modify `docker-compose.yaml` files to add the `--debug` argument to `services.entrypoint`s if an `entrypoint` is defined. 3 | 4 | on: 5 | - repositoriesMatchingQuery: 'file:docker-compose.yaml entrypoint:' 6 | 7 | steps: 8 | - run: | 9 | for result in "${{ join repository.search_result_paths " " }}"; do 10 | ruby /tmp/script "${result}" > "${result}.new" 11 | mv "${result}.new" "${result}" 12 | done; 13 | container: ruby 14 | files: 15 | /tmp/script: | 16 | #! /usr/bin/env ruby 17 | 18 | require 'yaml' 19 | 20 | content = YAML.load(ARGF.read) 21 | content['services'].each do |name, vals| 22 | vals["entrypoint"].is_a?(Array) && vals["entrypoint"] << "--debug" 23 | vals["entrypoint"].is_a?(String) && vals["entrypoint"] += " --debug" 24 | end 25 | puts content.to_yaml 26 | - run: | 27 | npm install -g prettier && 28 | (npx prettier --write "${{ join previous_step.modified_files " "}}" || exit 0) 29 | container: node 30 | 31 | changesetTemplate: 32 | title: Add `--debug` to entrypoints in docker-compose.yaml 33 | body: | 34 | This adds the `--debug` flag to all service entrypoints in the 35 | `docker-compose.yaml`, if they have a `entrypoint` defined. 36 | branch: batch-changes/docker-compose-debug-entrypoint 37 | published: false 38 | commit: 39 | message: Add `--debug` to existing `entrypoint`s in `docker-compose.yaml` 40 | -------------------------------------------------------------------------------- /yaml/update-k8s-manifest.yaml: -------------------------------------------------------------------------------- 1 | # https://docs.sourcegraph.com/batch_changes/references/batch_spec_yaml_reference#transformchanges 2 | name: update-k8s-yaml 3 | description: | 4 | Add namespace and modify metadata annotations. 5 | 6 | This is an arbitrary script used to insert some made up values that Bolaji created into 7 | kubernetes spec files. 8 | The script doesn't explicitly check which YAML is used by k8s because it assumes every YAML 9 | in the `sourcegraph-testing/k8s-examples` repo is a kubernetes spec file. 10 | 11 | # Find the first 100 search results for README files. 12 | # This could yield less than 100 repos/workspaces if some repos contain multiple READMEs. 13 | on: 14 | - repositoriesMatchingQuery: lang:YAML r:^github\.com/sourcegraph-testing/k8s-examples$ 15 | - repository: github.com/sourcegraph-testing/k8s-workshop-tfc 16 | branch: dev 17 | 18 | workspaces: 19 | - rootAtLocationOf: .gitkeep 20 | in: github.com/sourcegraph-testing/k8s-workshop-tfc 21 | 22 | transformChanges: 23 | group: 24 | - directory: cassandra 25 | branch: bo/cassandra-update 26 | repository: github.com/sourcegraph-testing/k8s-examples 27 | 28 | - directory: dev/cloudbuild 29 | branch: bo/dev/cloudbuild-update 30 | repository: github.com/sourcegraph-testing/k8s-examples 31 | 32 | - directory: staging/cluster-dns 33 | branch: bo/staging/cluster-dns-update 34 | repository: github.com/sourcegraph-testing/k8s-examples 35 | 36 | - directory: staging/cloud-controller-manager 37 | branch: bo/staging/cloud-controller-manager-update 38 | repository: github.com/sourcegraph-testing/k8s-examples 39 | 40 | - directory: staging/cockroach-db 41 | branch: bo/staging/cockroach-db-update 42 | repository: github.com/sourcegraph-testing/k8s-examples 43 | 44 | - directory: staging/explorer 45 | branch: bo/staging/explorer-update 46 | repository: github.com/sourcegraph-testing/k8s-examples 47 | 48 | - directory: staging/spark/spark-gluster 49 | branch: bo/staging/spark/spark-gluster-update 50 | repository: github.com/sourcegraph-testing/k8s-examples 51 | 52 | - directory: volumes/iscsi 53 | branch: bo/volumes/iscsi-update 54 | repository: github.com/sourcegraph-testing/k8s-examples 55 | 56 | - directory: volumes/cephfs 57 | branch: bo/volumes/cephfs-update 58 | repository: github.com/sourcegraph-testing/k8s-examples 59 | 60 | - directory: volumes/storageos 61 | branch: bo/volumes/storageos-update 62 | repository: github.com/sourcegraph-testing/k8s-examples 63 | 64 | # In each repository, run this command. Each repository's resulting diff is captured. 65 | steps: 66 | - run: | 67 | for result in "${{ join repository.search_result_paths " " }}"; do 68 | python /tmp/script.py "${result}"; 69 | done; 70 | container: bolajisourcegraph/pycustom 71 | if: ${{ matches repository.name "*sourcegraph-testing/k8s-exam*" }} 72 | files: 73 | /tmp/script.py: | 74 | import yaml 75 | import sys 76 | 77 | # Function to load a YAML file 78 | def load_yaml_file(file_path): 79 | with open(file_path, 'r') as file: 80 | docs = yaml.safe_load_all(file) 81 | return list(docs) 82 | 83 | # Function to save a YAML file 84 | def save_yaml_file(data, file_path): 85 | with open(file_path, 'w') as file: 86 | yaml.dump_all(data, file) 87 | 88 | for file_path in sys.argv[1].split(' '): 89 | data = load_yaml_file(file_path) 90 | 91 | for datum in data: 92 | # Perform manipulations on the YAML data 93 | # Example: Modify the namespace 94 | datum['metadata'] = datum.get('metadata', {}) 95 | datum['metadata']['namespace'] = 'my-namespace' 96 | 97 | # Example: Add or modify annotations 98 | annotations = datum['metadata'].get('annotations', {}) 99 | annotations['my-key'] = 'my-value' 100 | datum['metadata']['annotations'] = annotations 101 | 102 | save_yaml_file(data, file_path) 103 | 104 | - run: cp -r /tmp/k8s . 105 | container: ubuntu:18.04 106 | if: ${{ eq repository.name "github.com/sourcegraph-testing/k8s-workshop-tfc" }} 107 | files: 108 | /tmp/k8s/pods.yaml: | 109 | apiVersion: v1 110 | kind: Pod 111 | metadata: 112 | name: nginx 113 | spec: 114 | containers: 115 | - name: nginx 116 | image: nginx:1.14.2 117 | ports: 118 | - containerPort: 80 119 | 120 | /tmp/k8s/deployments.yaml: | 121 | apiVersion: apps/v1 122 | kind: Deployment 123 | metadata: 124 | name: nginx-deployment 125 | labels: 126 | app: nginx 127 | spec: 128 | replicas: 3 129 | selector: 130 | matchLabels: 131 | app: nginx 132 | template: 133 | metadata: 134 | labels: 135 | app: nginx 136 | spec: 137 | containers: 138 | - name: nginx 139 | image: nginx:1.14.2 140 | ports: 141 | - containerPort: 80 142 | 143 | # Describe the changeset (e.g., GitHub pull request) you want for each repository. 144 | changesetTemplate: 145 | title: | 146 | batches: update k8s manifest in repos (demo) 147 | 148 | # The repository.name is a template variable available in the changesetTemplate . It points to the full name of the repository in which the step is being executed. 149 | # (github.com/foo/bar) 150 | # I use the helper function split to split by the first . and this should return an array. Assuming the different codehosts are github.com , 151 | # gitlab.com and bitbucket.coom, it'll return github, gitlaband bitbucket. The I get the item at the first index and check if it's equal to gitlab, 152 | body: | 153 | Not my first batch change. 154 | 155 | ${{ batch_change.description }} 156 | 157 | ${{ if eq repository.name "github.com/sourcegraph-testing/k8s-workshop-tfc" }} 158 | @BolajiOlajide please check this out. 159 | 160 | #### Added Files 161 | ${{ range $index, $file := steps.added_files }} 162 | - ${{ $file }} 163 | 164 | ${{ end }} 165 | ${{end}} 166 | 167 | ${{ if eq repository.name "github.com/sourcegraph-testing/k8s-examples" }} 168 | #### Modified Files 169 | ${{ range $index, $file := steps.modified_files }} 170 | - ${{ $file }} 171 | 172 | ${{ end }} 173 | ${{ end }} 174 | commit: 175 | message: do some magic 176 | # Optional: Push the commit to a branch named after this batch change by default. 177 | branch: bo/demo-commit${{ replace steps.path "/" "-" }} 178 | -------------------------------------------------------------------------------- /yaml/update-yaml.rb: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env ruby 2 | 3 | require 'yaml' 4 | 5 | content = YAML.load(ARGF.read) 6 | content['services'].each do |name, vals| 7 | vals["entrypoint"].is_a?(Array) && vals["entrypoint"] << "--debug" 8 | vals["entrypoint"].is_a?(String) && vals["entrypoint"] += " --debug" 9 | end 10 | puts content.to_yaml --------------------------------------------------------------------------------