├── .gitignore ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── config └── github_labels.json ├── delivery └── project.toml ├── tools ├── cookbook_releases.rb ├── fetch_contributors.rb ├── org-labels │ └── README.md ├── pull_all_supermarket_cookbooks.rb └── stove │ ├── .stove │ └── README.md └── vagrant_update.sh /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | /.config 4 | /coverage/ 5 | /InstalledFiles 6 | /pkg/ 7 | /spec/reports/ 8 | /spec/examples.txt 9 | /test/tmp/ 10 | /test/version_tmp/ 11 | /tmp/ 12 | 13 | # Used by dotenv library to load environment variables. 14 | # .env 15 | 16 | ## Specific to RubyMotion: 17 | .dat* 18 | .repl_history 19 | build/ 20 | *.bridgesupport 21 | build-iPhoneOS/ 22 | build-iPhoneSimulator/ 23 | 24 | ## Specific to RubyMotion (use of CocoaPods): 25 | # 26 | # We recommend against adding the Pods directory to your .gitignore. However 27 | # you should judge for yourself, the pros and cons are mentioned at: 28 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 29 | # 30 | # vendor/Pods/ 31 | 32 | ## Documentation cache and generated files: 33 | /.yardoc/ 34 | /_yardoc/ 35 | /doc/ 36 | /rdoc/ 37 | 38 | ## Environment normalization: 39 | /.bundle/ 40 | /vendor/bundle 41 | /lib/bundler/man/ 42 | 43 | # for a library or gem, you might want to ignore these files since the code is 44 | # intended to run in multiple environments; otherwise, check them in: 45 | # Gemfile.lock 46 | # .ruby-version 47 | # .ruby-gemset 48 | 49 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: 50 | .rvmrc 51 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | Please refer to the Chef Community Code of Conduct at https://www.chef.io/code-of-conduct/ 2 | -------------------------------------------------------------------------------- /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 | # community_cookbook_tools 2 | 3 | This repo is a collection of documentation, scripts, and configuration for the various tools we use on the Chef Community Engineering team to manage repositories. 4 | -------------------------------------------------------------------------------- /config/github_labels.json: -------------------------------------------------------------------------------- 1 | [ 2 | { "name": "Status: Abandoned", "color": "000000" }, 3 | { "name": "Status: Blocked", "color": "cc0000" }, 4 | { "name": "Status: In Progress", "color": "99ff99" }, 5 | { "name": "Status: On Hold", "color": "996633" }, 6 | { "name": "Status: Maintainer Review Needed", "color": "fbca04" }, 7 | { "name": "Status: Pending Contributor Response", "color": "cc00cc" }, 8 | { "name": "Priority: Low", "color": "4d0000" }, 9 | { "name": "Priority: Medium", "color": "800000" }, 10 | { "name": "Priority: High", "color": "b30000" }, 11 | { "name": "Priority: Critical", "color": "ff0000" }, 12 | { "name": "Type: Bug", "color": "e11d21" }, 13 | { "name": "Type: Maintenance", "color": "fbca04" }, 14 | { "name": "Type: Enhancement", "color": "84b6eb" }, 15 | { "name": "Type: Question", "color": "cc317c" }, 16 | { "name": "Type: Feature Request", "color": "cc317c" }, 17 | { "name": "Type: Jump In", "color": "bfe5bf" } 18 | ] 19 | -------------------------------------------------------------------------------- /delivery/project.toml: -------------------------------------------------------------------------------- 1 | [local_phases] 2 | unit = "rspec spec/" 3 | lint = 'cookstyle --display-cop-names --extra-details' 4 | syntax = "echo syntax checking with foodcritic has been replaced with cookstyle. skipping" 5 | provision = "echo skipping" 6 | deploy = "echo skipping" 7 | smoke = "echo skipping" 8 | functional = "echo skipping" 9 | cleanup = "echo skipping" 10 | -------------------------------------------------------------------------------- /tools/cookbook_releases.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "net/http" 4 | require "json" 5 | require "date" 6 | 7 | def cookbooks 8 | uri = URI("https://supermarket.chef.io/api/v1/users/chef") 9 | response = Net::HTTP.get(uri) 10 | JSON.parse(response)["cookbooks"]["owns"].keys 11 | end 12 | 13 | def versions(cb_name) 14 | uri = URI("https://supermarket.chef.io/api/v1/cookbooks/#{cb_name}") 15 | response = Net::HTTP.get(uri) 16 | JSON.parse(response)["versions"].map! { |x| x.split("/")[-1] } 17 | end 18 | 19 | def cb_version_publish_date(cb, version) 20 | uri = URI("https://supermarket.chef.io/api/v1/cookbooks/#{cb}/versions/#{version}") 21 | response = Net::HTTP.get(uri) 22 | DateTime.parse(JSON.parse(response)["published_at"]) 23 | end 24 | 25 | def deprecated_date(cb) 26 | uri = URI("https://supermarket.chef.io/api/v1/cookbooks/#{cb}") 27 | response = JSON.parse(Net::HTTP.get(uri)) 28 | return DateTime.parse(response["updated_at"]) if response["deprecated"] 29 | end 30 | 31 | if ARGV.empty? 32 | puts "You must pass two dates in format: 2017-10-01" 33 | exit! 34 | end 35 | 36 | since_date = DateTime.parse(ARGV.first) 37 | till_date = DateTime.parse(ARGV[1] ? ARGV[1] : Time.now) 38 | verbose = ARGV[2] == "-v" ? true : false 39 | releases = [] 40 | deprecated = [] 41 | 42 | cookbooks.each do |cb| 43 | puts "Checking #{cb} deprecation status" 44 | dep_date = deprecated_date(cb) 45 | deprecated << cb if dep_date && dep_date >= since_date && dep_date <= till_date 46 | 47 | versions(cb).each do |version| 48 | puts "Checking #{cb} version #{version} release date" 49 | pub_date = cb_version_publish_date(cb, version) 50 | if pub_date >= since_date && pub_date <= till_date 51 | releases << { cb => version } 52 | else 53 | break 54 | end 55 | end 56 | end 57 | 58 | puts "\nThere have been #{releases.count} cookbook releases between #{since_date} and #{till_date}" 59 | puts "\nThere have been #{deprecated.count} cookbooks deprecated between #{since_date} and #{till_date}" 60 | 61 | return unless verbose 62 | puts "\nReleases:" 63 | releases.each do |c| 64 | puts "#{c.keys.first} #{c.values.first}" 65 | end 66 | -------------------------------------------------------------------------------- /tools/fetch_contributors.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | unless ENV["GITHUB_TOKEN"] 4 | puts "You must set the GITHUB_TOKEN environmental variable with a GitHub token!" 5 | exit 1 6 | end 7 | 8 | @ignore_cheffers = true 9 | 10 | begin 11 | require "octokit" 12 | require "faraday-http-cache" 13 | rescue LoadError 14 | puts "This script requires octokit and faraday-http-cache gems!" 15 | end 16 | 17 | require "date" 18 | require "time" 19 | 20 | def connection 21 | @client ||= setup_connection 22 | end 23 | 24 | def setup_connection 25 | faraday = Faraday::RackBuilder.new do |builder| 26 | builder.use Faraday::HttpCache 27 | builder.use Octokit::Response::RaiseError 28 | builder.adapter Faraday.default_adapter 29 | end 30 | 31 | connection = Octokit::Client.new(access_token: ENV["GITHUB_TOKEN"]) 32 | connection.auto_paginate = true 33 | connection.middleware = faraday 34 | connection 35 | end 36 | 37 | def chef_employee?(login) 38 | @not_employees ||= [] 39 | # start with a few users that aren't matched by the below logic, but totally work at Chef or worked at Chef recently 40 | @employees ||= %w{jonsmorrow kagarmoe robbkidd jeremiahsnapp chef-delivery NAshwini chris-rock hannah-radish tyler-ball wrightp TheLunaticScripter miah chef-ci nsdavidson jjasghar nathenharvey iennae PrajaktaPurohit Vasu1105 itmustbejj brewn thomascate dmccown phiggins paulmooring jvogt sjvreddy russellseymour mchiang0610 susanev yzl mjingle lnxchk jmassardo ChefRycar trevorghess cwebberOps smford22 apriofrost fnichol} 41 | 42 | # don't bother further processing if we know their state 43 | return true if @employees.include?(login) 44 | return false if @not_employees.include?(login) 45 | 46 | if login.match?(/msys/i) # msys contractors 47 | @employees << login 48 | return true 49 | end 50 | 51 | # the following require looking up the user with Github first 52 | user = connection.user(login) 53 | if user["company"].match?(/chef|opscode|habitat|msystechnologies|kinvolk/i) || 54 | user["email"].match?(/opscode\.com|chef\.io|getchef\.com|habitat\.sh/i) 55 | @employees << user["login"] 56 | return true 57 | end 58 | 59 | # assume not an employee now 60 | @not_employees << user["login"] 61 | false 62 | rescue NoMethodError 63 | @not_employees << user["login"] 64 | false 65 | end 66 | 67 | def skip_repo?(repo) 68 | true if %w{chef/devops-kungfu chef/community-summits chef/chef-web-docs chef/lambda_ebs_snapshot chef/compliance-workshop-environment chef/devops-transformation-workshop chef/dotscaleworkshop chef/chef-summit-2014}.include?(repo) 69 | end 70 | 71 | def verbose? 72 | ARGV[1] == "-v" ? true : false 73 | end 74 | 75 | def fetch_prs(org) 76 | puts "\nFetching all users that have opened PRs against the org #{org} in the last year. This may take a long while...\n\n" 77 | users = {} 78 | repos = {} 79 | pr_count = 0 80 | # fetch any issue ever created that's in any state and don't filter anything 81 | 82 | # fetch all public repos in the org 83 | connection.organization_repositories(org, { :type => "public" }).each do |repo| 84 | # skip if we're in a blacklisted repo 85 | if skip_repo?(repo["full_name"]) 86 | puts "skipping blacklisted repo #{repo['name']}" if verbose? 87 | break 88 | else 89 | puts "we're in #{repo['full_name']}" if verbose? 90 | end 91 | 92 | # grab all PRs in the repo 93 | connection.pull_requests(repo["full_name"], { :state => "all" }).each do |issue| 94 | # The result set is sorted from new to old so if we hit one older than a year 95 | # we can break and move onto the next repo 96 | break if DateTime.parse(issue["created_at"].to_s) < ( DateTime.now - 365 ) 97 | 98 | puts "The issue is from #{issue['created_at']}" if verbose? 99 | 100 | if @ignore_cheffers 101 | puts "#{issue["user"]["login"]} is an employee?: #{chef_employee?(issue["user"]["login"])}" if verbose? 102 | next if chef_employee?(issue["user"]["login"]) 103 | end 104 | 105 | # don't count PRs we never merged 106 | next if issue["state"] == "closed" && issue["merged_at"].nil? 107 | 108 | # bump the total PR count 109 | pr_count += 1 110 | 111 | # bump the repo PR count. 112 | if repos[repo["name"]] 113 | repos[repo["name"]] += 1 114 | else 115 | repos[repo["name"]] = 1 116 | end 117 | 118 | # add the user to the hash with several attributes 119 | unless users[issue["user"]["login"]] 120 | users[issue["user"]["login"]] = {} 121 | users[issue["user"]["login"]]["repos"] = [] 122 | users[issue["user"]["login"]]["contributions"] = 0 123 | users[issue["user"]["login"]]["username"] = issue["user"]["login"] 124 | 125 | user_details = connection.user(issue["user"]["login"]) 126 | users[issue["user"]["login"]]["e-mail"] = user_details["email"] 127 | users[issue["user"]["login"]]["name"] = user_details["name"] 128 | users[issue["user"]["login"]]["company"] = user_details["company"] 129 | end 130 | users[issue["user"]["login"]]["contributions"] += 1 131 | users[issue["user"]["login"]]["repos"] << repo["full_name"] unless users[issue["user"]["login"]]["repos"].include?(repo["full_name"]) 132 | end 133 | end 134 | 135 | [users.sort_by { |_k, v| v["contributions"] }.reverse.to_h, repos, pr_count] 136 | end 137 | 138 | if ARGV.empty? 139 | puts "You must pass the org to fetch contributors for!" 140 | exit! 141 | end 142 | 143 | users, repos, pr_count = fetch_prs(ARGV.first) 144 | 145 | puts "\n\nCONTRIBUTOR STATS\n\n" 146 | users.each_value do |user| 147 | puts "#{user['username']},#{user['name']},#{user['e-mail']},#{begin 148 | user['company'].delete(',') 149 | rescue 150 | nil 151 | end},#{user['contributions']},#{user['repos'].join(' ')}" 152 | end 153 | 154 | puts "\n\nREPO PR COUNTS\n\n" 155 | repos.each do |k, v| 156 | puts "#{k}, #{v}" 157 | end 158 | 159 | puts "\n\nTOTAL PR COUNT\n\n" 160 | puts pr_count 161 | -------------------------------------------------------------------------------- /tools/org-labels/README.md: -------------------------------------------------------------------------------- 1 | # org-labels 2 | 3 | org-labels is a node app that manages Github labels across entire orgs. It allows you to easily add/remove labels en masse. It also allows you to define your labels in a JSON file that it uses to update all repos with. This makes it easy for us to have consistent labelling on all our orgs, which other tools can consume. 4 | 5 | ## Homepage 6 | 7 | 8 | 9 | ## Installation 10 | 11 | First you'll need node on your system. If you're running OS X you can install it via brew with 12 | 13 | ``` 14 | brew install nodejs 15 | ``` 16 | 17 | Once you have node installed you can install org-labels 18 | 19 | ``` 20 | npm install -g org-labels 21 | ``` 22 | 23 | ## Configuration 24 | 25 | A configuration JSON file is located in the `community_cookbooks_tools` repo at config/github_labels.json 26 | 27 | Locally the application prompts for username / login. You should have 2 factor authentication configured for your github account. If you do, you'll need to input that code as well even though the screen implies it's optional. 28 | 29 | Example of login screen: 30 | 31 | ``` 32 | Jennifers-MBP:community_cookbook_tools sigje$ org-labels standardize chef-cookbooks chef-cookbooks/community_cookbook_tools 33 | Your GitHub username: iennae 34 | Your GitHub password: ✔✔✔✔✔✔✔✔✔✔✔✔✔✔✔✔ 35 | 36 | Your GitHub OTP/2FA Code (optional): 37 | ``` 38 | 39 | If you receive 404 errors when you run the application either: 40 | 41 | * open ~/.config/org-labels.json and add a Github token that has the appropriate privileges in place of the generated token. This will get around issues with 2 factor auth. 42 | 43 | * open and edit the token to have the appropriate privileges. The token will look something like `org-labels CLI tool (2017-09-07T23:36:35.718Z)`. 44 | 45 | Example of a 404 error indicating the token has insufficient privileges: 46 | 47 | ``` 48 | Jennifers-MBP:community_cookbook_tools sigje$ org-labels standardize chef-cookbooks chef-cookbooks/community_cookbook_tools 49 | GitHub rate limit remaining: 4830 50 | found 144 repositories in chef-cookbooks 51 | 52 | checking 15 labels across 144 repos 53 | Error: 404 - https://api.github.com/repos/chef-cookbooks/vcruntime/labels 54 | ``` 55 | 56 | Example of successful usage (output edited for length): 57 | 58 | ``` 59 | Jennifers-MBP:community_cookbook_tools sigje$ org-labels standardize chef-cookbooks chef-cookbooks/community_cookbook_tools 60 | GitHub rate limit remaining: 4641 61 | found 144 repositories in chef-cookbooks 62 | 63 | checking 15 labels across 144 repos 64 | ... 65 | label `Type: Feature Request` successfully created at /repos/chef-cookbooks/elixir/labels 66 | label `Type: Question` successfully created at /repos/chef-cookbooks/elixir/labels 67 | label `Type: Enhancement` successfully created at /repos/chef-cookbooks/elixir/labels 68 | label `Type: Maintenance` successfully created at /repos/chef-cookbooks/elixir/labels 69 | label `Type: Bug` successfully created at /repos/chef-cookbooks/elixir/labels 70 | label `Priority: Critical` successfully created at /repos/chef-cookbooks/elixir/labels 71 | label `Priority: High` successfully created at /repos/chef-cookbooks/elixir/labels 72 | label `Priority: Medium` successfully created at /repos/chef-cookbooks/elixir/labels 73 | label `Priority: Low` successfully created at /repos/chef-cookbooks/elixir/labels 74 | label `Status: Pending Contributor Response` successfully created at /repos/chef-cookbooks/elixir/labels 75 | label `Status: Maintainer Review Needed` successfully created at /repos/chef-cookbooks/elixir/labels 76 | label `Status: On Hold` successfully created at /repos/chef-cookbooks/elixir/labels 77 | label `Status: In Progress` successfully created at /repos/chef-cookbooks/elixir/labels 78 | label `Status: Blocked` successfully created at /repos/chef-cookbooks/elixir/labels 79 | label `Status: Abandoned` successfully created at /repos/chef-cookbooks/elixir/labels 80 | ... 81 | 119 label updates across 10 repos 82 | done standardizing labels 83 | 84 | ``` 85 | 86 | ## Usage 87 | 88 | The following command standardizes labels in all `chef-cookbooks` repos using the [configuration](https://github.com/chef-cookbooks/community_cookbook_tools/blob/master/config/github_labels.json) found in the `chef-cookbooks/community_cookbook_tools` repo. 89 | 90 | ``` 91 | org-labels standardize chef-cookbooks chef-cookbooks/community_cookbook_tools 92 | ``` 93 | -------------------------------------------------------------------------------- /tools/pull_all_supermarket_cookbooks.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # this pulls down and uncompresses everything on the Supermarket 4 | # it takes a while so be patient 5 | 6 | require "net/http" 7 | require "json" 8 | 9 | uri = URI("https://supermarket.chef.io/universe") 10 | response = Net::HTTP.get(uri) 11 | urls = [] 12 | JSON.parse(response).each do |cb| 13 | urls << cb[1].sort.last[1]['download_url'] 14 | end 15 | 16 | urls.each do |url| 17 | `wget -O cookbook.tgz #{url}` 18 | `tar -xzf cookbook.tgz` 19 | end 20 | 21 | `rm cookbook.tgz` 22 | -------------------------------------------------------------------------------- /tools/stove/.stove: -------------------------------------------------------------------------------- 1 | {"username":"my_supermarket_name","key":"/THE/PATH/TO/YOUR/HOMEDIR/.chef/me.pem"} 2 | -------------------------------------------------------------------------------- /tools/stove/README.md: -------------------------------------------------------------------------------- 1 | # Stove 2 | 3 | See for our thoughts on using stove to release cookbooks 4 | 5 | ## Homepage 6 | 7 | 8 | 9 | ## Installation 10 | 11 | ``` 12 | chef gem install stove 13 | ``` 14 | 15 | or 16 | 17 | ``` 18 | gem install stove 19 | ``` 20 | 21 | ## Configuration 22 | 23 | See the sample .stove file in this directory 24 | 25 | ## Usage 26 | 27 | From the cookbook directory simple run `stove` to tag the cookbook and push it to the Supermarket. If you accidentally push a cookbook that you're not authorized to push you'll need to add yourself on Supermarket and then run `stove --no-git` to skip the git tagging. If you are uploading a Chef 12+ cookbook you can use the `--extended-metadata` option to upload issues_url and source_url metadata 28 | -------------------------------------------------------------------------------- /vagrant_update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ $# -eq 0 ]; then 4 | echo "Box type must be specified (virtualbox, vmware_desktop, parallels)" 5 | exit 1 6 | fi 7 | 8 | # Find all boxes which have updates 9 | AVAILABLE_UPDATES=`vagrant box outdated --global 2>/dev/null | grep outdated | tr -d "*'" | cut -d ' ' -f 2` 10 | 11 | if [ ! ${#AVAILABLE_UPDATES[@]} -eq 0 ]; then 12 | for box in $AVAILABLE_UPDATES ; do 13 | 14 | echo "Found an update for $box" 15 | 16 | # Find all current versions 17 | VERSIONS=`vagrant box list | grep $box | cut -d ',' -f 2 | tr -d ' )'` 18 | 19 | # Add latest version 20 | vagrant box add --clean $box --provider $1 --force 21 | BOX_UPDATED="TRUE" 22 | 23 | # Remove all old versions 24 | vagrant box prune -f > /dev/null 2>&1 25 | 26 | done 27 | 28 | echo "All boxes are now up to date!" 29 | 30 | else 31 | 32 | echo "All boxes are already up to date!" 33 | 34 | fi 35 | 36 | vagrant box outdated --global 37 | --------------------------------------------------------------------------------