├── .editorconfig ├── .envrc ├── .gitattributes ├── .github ├── CODEOWNERS └── workflows │ ├── ci.yml │ └── stale.yml ├── .gitignore ├── .markdownlint-cli2.yaml ├── .mdlrc ├── .overcommit.yml ├── .vscode └── extensions.json ├── .yamllint ├── Berksfile ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Dangerfile ├── LICENSE ├── README.md ├── TESTING.md ├── chefignore ├── documentation ├── .gitkeep ├── archive.md ├── asset.md └── deploy.md ├── kitchen.dokken.yml ├── kitchen.exec.yml ├── kitchen.global.yml ├── kitchen.yml ├── libraries ├── github_archive.rb ├── github_asset.rb └── github_errors.rb ├── metadata.rb ├── renovate.json ├── resources ├── archive.rb ├── asset.rb └── deploy.rb ├── spec ├── libraries │ └── github_archive_spec.rb └── spec_helper.rb └── test ├── fixtures └── cookbooks │ └── test │ ├── metadata.rb │ └── recipes │ └── default.rb └── integration └── default ├── controls └── default.rb └── inspec.yml /.editorconfig: -------------------------------------------------------------------------------- 1 | # https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root=true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | 11 | # 2 space indentation 12 | indent_style = space 13 | indent_size = 2 14 | 15 | # Avoid issues parsing cookbook files later 16 | charset = utf-8 17 | 18 | # Avoid cookstyle warnings 19 | trim_trailing_whitespace = true 20 | -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | use chefworkstation 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @sous-chefs/maintainers 2 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: ci 3 | 4 | "on": 5 | pull_request: 6 | push: 7 | branches: 8 | - main 9 | 10 | jobs: 11 | lint-unit: 12 | uses: sous-chefs/.github/.github/workflows/lint-unit.yml@3.1.1 13 | permissions: 14 | actions: write 15 | checks: write 16 | pull-requests: write 17 | statuses: write 18 | issues: write 19 | 20 | integration: 21 | needs: lint-unit 22 | runs-on: ubuntu-latest 23 | strategy: 24 | matrix: 25 | os: 26 | - "ubuntu-2004" 27 | suite: 28 | - "default" 29 | fail-fast: false 30 | 31 | steps: 32 | - name: Check out code 33 | uses: actions/checkout@v4 34 | - name: Install Chef 35 | uses: actionshub/chef-install@3.0.0 36 | - name: Dokken 37 | uses: actionshub/test-kitchen@3.0.0 38 | env: 39 | CHEF_LICENSE: accept-no-persist 40 | KITCHEN_LOCAL_YAML: kitchen.dokken.yml 41 | with: 42 | suite: ${{ matrix.suite }} 43 | os: ${{ matrix.os }} 44 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Mark stale issues and pull requests 3 | 4 | "on": 5 | schedule: [cron: "0 0 * * *"] 6 | 7 | jobs: 8 | stale: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/stale@v9 12 | with: 13 | repo-token: ${{ secrets.GITHUB_TOKEN }} 14 | close-issue-message: > 15 | Closing due to inactivity. 16 | If this is still an issue please reopen or open another issue. 17 | Alternatively drop by the #sous-chefs channel on the [Chef Community Slack](http://community-slack.chef.io/) and we'll be happy to help! 18 | Thanks, Sous-Chefs. 19 | days-before-close: 7 20 | days-before-stale: 365 21 | stale-issue-message: > 22 | Marking stale due to inactivity. 23 | Remove stale label or comment or this will be closed in 7 days. 24 | Alternatively drop by the #sous-chefs channel on the [Chef Community Slack](http://community-slack.chef.io/) and we'll be happy to help! 25 | Thanks, Sous-Chefs. 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.rbc 2 | .config 3 | InstalledFiles 4 | pkg 5 | test/tmp 6 | test/version_tmp 7 | tmp 8 | _Store 9 | *~ 10 | *# 11 | .#* 12 | \#*# 13 | *.un~ 14 | *.tmp 15 | *.bk 16 | *.bkup 17 | 18 | # editor files 19 | .idea 20 | .*.sw[a-z] 21 | 22 | # ruby/bundler/rspec files 23 | .ruby-version 24 | .ruby-gemset 25 | .rvmrc 26 | Gemfile.lock 27 | .bundle 28 | *.gem 29 | coverage 30 | spec/reports 31 | 32 | # YARD / rdoc artifacts 33 | .yardoc 34 | _yardoc 35 | doc/ 36 | rdoc 37 | 38 | # chef infra stuff 39 | Berksfile.lock 40 | .kitchen 41 | kitchen.local.yml 42 | vendor/ 43 | .coverage/ 44 | .zero-knife.rb 45 | Policyfile.lock.json 46 | 47 | # vagrant stuff 48 | .vagrant/ 49 | .vagrant.d/ 50 | -------------------------------------------------------------------------------- /.markdownlint-cli2.yaml: -------------------------------------------------------------------------------- 1 | config: 2 | ul-indent: false # MD007 3 | line-length: false # MD013 4 | no-duplicate-heading: false # MD024 5 | reference-links-images: false # MD052 6 | -------------------------------------------------------------------------------- /.mdlrc: -------------------------------------------------------------------------------- 1 | rules "~MD013", "~MD024", "~MD026", "~MD029", "~MD033" 2 | -------------------------------------------------------------------------------- /.overcommit.yml: -------------------------------------------------------------------------------- 1 | --- 2 | PreCommit: 3 | TrailingWhitespace: 4 | enabled: true 5 | YamlLint: 6 | enabled: true 7 | required_executable: "yamllint" 8 | ChefSpec: 9 | enabled: true 10 | required_executable: "chef" 11 | command: ["chef", "exec", "rspec"] 12 | Cookstyle: 13 | enabled: true 14 | required_executable: "cookstyle" 15 | command: ["cookstyle"] 16 | MarkdownLint: 17 | enabled: false 18 | required_executable: "npx" 19 | command: ["npx", "markdownlint-cli2", "'**/*.md'"] 20 | include: ["**/*.md"] 21 | 22 | CommitMsg: 23 | HardTabs: 24 | enabled: true 25 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "chef-software.chef", 4 | "rebornix.ruby", 5 | "editorconfig.editorconfig", 6 | "DavidAnson.vscode-markdownlint" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /.yamllint: -------------------------------------------------------------------------------- 1 | --- 2 | extends: default 3 | rules: 4 | line-length: 5 | max: 256 6 | level: warning 7 | document-start: disable 8 | braces: 9 | forbid: false 10 | min-spaces-inside: 0 11 | max-spaces-inside: 1 12 | min-spaces-inside-empty: -1 13 | max-spaces-inside-empty: -1 14 | comments: 15 | min-spaces-from-content: 1 16 | -------------------------------------------------------------------------------- /Berksfile: -------------------------------------------------------------------------------- 1 | source 'https://supermarket.chef.io' 2 | 3 | metadata 4 | 5 | group :integration do 6 | cookbook 'test', path: 'test/fixtures/cookbooks/test' 7 | end 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # GitHub Cookbook CHANGELOG 2 | 3 | This file is used to list changes made in each version of the GitHub cookbook. 4 | 5 | ## Unreleased 6 | 7 | ## 1.1.15 - *2024-05-02* 8 | 9 | ## 1.1.14 - *2024-05-02* 10 | 11 | ## 1.1.13 - *2024-05-01* 12 | 13 | ## 1.1.12 - *2024-05-01* 14 | 15 | ## 1.1.11 - *2024-05-01* 16 | 17 | ## 1.1.10 - *2023-10-30* 18 | 19 | ## 1.1.9 - *2023-10-30* 20 | 21 | ## 1.1.8 - *2023-10-26* 22 | 23 | ## 1.1.7 - *2023-09-28* 24 | 25 | ## 1.1.6 - *2023-09-04* 26 | 27 | ## 1.1.5 - *2023-06-08* 28 | 29 | Standardise files with files in sous-chefs/repo-management 30 | 31 | ## 1.1.4 - *2023-05-17* 32 | 33 | ## 1.1.3 - *2023-05-03* 34 | 35 | ## 1.1.2 - *2023-04-01* 36 | 37 | ## 1.1.1 - *2023-03-02* 38 | 39 | ## 1.1.0 - *2022-01-24* 40 | 41 | - Add :extract action to github_asset resource 42 | 43 | ## 1.0.1 - *2021-11-02* 44 | 45 | - Fix typo 46 | 47 | ## 1.0.0 - *2021-09-08* 48 | 49 | - Sous-Chefs adoption 50 | - Migrate to modern custom resources and enable `unified_mode` 51 | - Remove dependency on libarchive 52 | - Cookstyle fixes 53 | - Fix URI deprecation issues 54 | - Replace `extract` method with using the `archive_file` native resource 55 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Community Guidelines 2 | 3 | This project follows the Chef Community Guidelines 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Please refer to 4 | [https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/CONTRIBUTING.MD](https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/CONTRIBUTING.MD) 5 | -------------------------------------------------------------------------------- /Dangerfile: -------------------------------------------------------------------------------- 1 | # Reference: http://danger.systems/reference.html 2 | 3 | # A pull request summary is required. Add a description of the pull request purpose. 4 | # Changelog must be updated for each pull request that changes code. 5 | # Warnings will be issued for: 6 | # Pull request with more than 400 lines of code changed 7 | # Pull reqest that change more than 5 lines without test changes 8 | # Failures will be issued for: 9 | # Pull request without summary 10 | # Pull requests with code changes without changelog entry 11 | 12 | def code_changes? 13 | code = %w(libraries attributes recipes resources files templates) 14 | code.each do |location| 15 | return true unless git.modified_files.grep(/#{location}/).empty? 16 | end 17 | false 18 | end 19 | 20 | def test_changes? 21 | tests = %w(spec test kitchen.yml kitchen.dokken.yml) 22 | tests.each do |location| 23 | return true unless git.modified_files.grep(/#{location}/).empty? 24 | end 25 | false 26 | end 27 | 28 | failure 'Please provide a summary of your Pull Request.' if github.pr_body.length < 10 29 | 30 | warn 'This is a big Pull Request.' if git.lines_of_code > 400 31 | 32 | warn 'This is a Table Flip.' if git.lines_of_code > 2000 33 | 34 | # Require a CHANGELOG entry for non-test changes. 35 | if !git.modified_files.include?('CHANGELOG.md') && code_changes? 36 | failure 'Please include a CHANGELOG entry.' 37 | end 38 | 39 | # Require Major Minor Patch version labels 40 | unless github.pr_labels.grep /minor|major|patch/i 41 | warn 'Please add a release label to this pull request' 42 | end 43 | 44 | # A sanity check for tests. 45 | if git.lines_of_code > 5 && code_changes? && !test_changes? 46 | warn 'This Pull Request is probably missing tests.' 47 | end 48 | -------------------------------------------------------------------------------- /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 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # github Cookbook 2 | 3 | [![Cookbook Version](https://img.shields.io/cookbook/v/github.svg)](https://supermarket.chef.io/cookbooks/github) 4 | [![CI State](https://github.com/sous-chefs/github/workflows/ci/badge.svg)](https://github.com/sous-chefs/github/actions?query=workflow%3Aci) 5 | [![OpenCollective](https://opencollective.com/sous-chefs/backers/badge.svg)](#backers) 6 | [![OpenCollective](https://opencollective.com/sous-chefs/sponsors/badge.svg)](#sponsors) 7 | [![License](https://img.shields.io/badge/License-Apache%202.0-green.svg)](https://opensource.org/licenses/Apache-2.0) 8 | 9 | A Library Cookbook for downloading assets, archives or deploying from GitHub repositories 10 | 11 | ## Maintainers 12 | 13 | This cookbook is maintained by the Sous Chefs. The Sous Chefs are a community of Chef cookbook maintainers working together to maintain important cookbooks. If you’d like to know more please visit [sous-chefs.org](https://sous-chefs.org/) or come chat with us on the Chef Community Slack in [#sous-chefs](https://chefcommunity.slack.com/messages/C2V7B88SF). 14 | 15 | ## Supported Platforms 16 | 17 | * Any chef supported platform 18 | 19 | ## Resources 20 | 21 | The following resources are provided: 22 | 23 | * [archive](documentation/archive.md) 24 | * [asset](documentation/asset.md) 25 | * [deploy](documentation/deploy.md) 26 | 27 | ## Contributors 28 | 29 | This project exists thanks to all the people who [contribute.](https://opencollective.com/sous-chefs/contributors.svg?width=890&button=false) 30 | 31 | ### Backers 32 | 33 | Thank you to all our backers! 34 | 35 | ![https://opencollective.com/sous-chefs#backers](https://opencollective.com/sous-chefs/backers.svg?width=600&avatarHeight=40) 36 | 37 | ### Sponsors 38 | 39 | Support this project by becoming a sponsor. Your logo will show up here with a link to your website. 40 | 41 | ![https://opencollective.com/sous-chefs/sponsor/0/website](https://opencollective.com/sous-chefs/sponsor/0/avatar.svg?avatarHeight=100) 42 | ![https://opencollective.com/sous-chefs/sponsor/1/website](https://opencollective.com/sous-chefs/sponsor/1/avatar.svg?avatarHeight=100) 43 | ![https://opencollective.com/sous-chefs/sponsor/2/website](https://opencollective.com/sous-chefs/sponsor/2/avatar.svg?avatarHeight=100) 44 | ![https://opencollective.com/sous-chefs/sponsor/3/website](https://opencollective.com/sous-chefs/sponsor/3/avatar.svg?avatarHeight=100) 45 | ![https://opencollective.com/sous-chefs/sponsor/4/website](https://opencollective.com/sous-chefs/sponsor/4/avatar.svg?avatarHeight=100) 46 | ![https://opencollective.com/sous-chefs/sponsor/5/website](https://opencollective.com/sous-chefs/sponsor/5/avatar.svg?avatarHeight=100) 47 | ![https://opencollective.com/sous-chefs/sponsor/6/website](https://opencollective.com/sous-chefs/sponsor/6/avatar.svg?avatarHeight=100) 48 | ![https://opencollective.com/sous-chefs/sponsor/7/website](https://opencollective.com/sous-chefs/sponsor/7/avatar.svg?avatarHeight=100) 49 | ![https://opencollective.com/sous-chefs/sponsor/8/website](https://opencollective.com/sous-chefs/sponsor/8/avatar.svg?avatarHeight=100) 50 | ![https://opencollective.com/sous-chefs/sponsor/9/website](https://opencollective.com/sous-chefs/sponsor/9/avatar.svg?avatarHeight=100) 51 | -------------------------------------------------------------------------------- /TESTING.md: -------------------------------------------------------------------------------- 1 | # Testing 2 | 3 | Please refer to [the community cookbook documentation on testing](https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/TESTING.MD). 4 | -------------------------------------------------------------------------------- /chefignore: -------------------------------------------------------------------------------- 1 | # Put files/directories that should be ignored in this file when uploading 2 | # to a Chef Infra Server or Supermarket. 3 | # Lines that start with '# ' are comments. 4 | 5 | # OS generated files # 6 | ###################### 7 | .DS_Store 8 | ehthumbs.db 9 | Icon? 10 | nohup.out 11 | Thumbs.db 12 | .envrc 13 | 14 | # EDITORS # 15 | ########### 16 | .#* 17 | .project 18 | .settings 19 | *_flymake 20 | *_flymake.* 21 | *.bak 22 | *.sw[a-z] 23 | *.tmproj 24 | *~ 25 | \#* 26 | REVISION 27 | TAGS* 28 | tmtags 29 | .vscode 30 | .editorconfig 31 | 32 | ## COMPILED ## 33 | ############## 34 | *.class 35 | *.com 36 | *.dll 37 | *.exe 38 | *.o 39 | *.pyc 40 | *.so 41 | */rdoc/ 42 | a.out 43 | mkmf.log 44 | 45 | # Testing # 46 | ########### 47 | .circleci/* 48 | .codeclimate.yml 49 | .delivery/* 50 | .foodcritic 51 | .kitchen* 52 | .mdlrc 53 | .overcommit.yml 54 | .rspec 55 | .rubocop.yml 56 | .travis.yml 57 | .watchr 58 | .yamllint 59 | azure-pipelines.yml 60 | Dangerfile 61 | examples/* 62 | features/* 63 | Guardfile 64 | kitchen*.yml 65 | mlc_config.json 66 | Procfile 67 | Rakefile 68 | spec/* 69 | test/* 70 | 71 | # SCM # 72 | ####### 73 | .git 74 | .gitattributes 75 | .gitconfig 76 | .github/* 77 | .gitignore 78 | .gitkeep 79 | .gitmodules 80 | .svn 81 | */.bzr/* 82 | */.git 83 | */.hg/* 84 | */.svn/* 85 | 86 | # Berkshelf # 87 | ############# 88 | Berksfile 89 | Berksfile.lock 90 | cookbooks/* 91 | tmp 92 | 93 | # Bundler # 94 | ########### 95 | vendor/* 96 | Gemfile 97 | Gemfile.lock 98 | 99 | # Policyfile # 100 | ############## 101 | Policyfile.rb 102 | Policyfile.lock.json 103 | 104 | # Documentation # 105 | ############# 106 | CODE_OF_CONDUCT* 107 | CONTRIBUTING* 108 | documentation/* 109 | TESTING* 110 | UPGRADING* 111 | 112 | # Vagrant # 113 | ########### 114 | .vagrant 115 | Vagrantfile 116 | -------------------------------------------------------------------------------- /documentation/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sous-chefs/github/8c4aceb70f43bb55b923d600497f896aefd8ced7/documentation/.gitkeep -------------------------------------------------------------------------------- /documentation/archive.md: -------------------------------------------------------------------------------- 1 | # github_archive 2 | 3 | [Back to resource list](../README.md#resources) 4 | 5 | Downloads and extracts an archive from a Github repository 6 | 7 | ## Actions 8 | 9 | | Action | Description | 10 | | ---------- | ---------------------------------------------------------- | 11 | | `:extract` | Downloads and extracts an archive from a Github repository | 12 | | `:delete` | Deletes an extracted archive from a Github repository | 13 | 14 | ## Properties 15 | 16 | | Name | Type | Default | Description | 17 | | -------------- | --------------- | -------------------- | ---------------------------------------- | 18 | | `repo` | String | Resource name | Repository org and name | 19 | | `version` | String | `master` | Git ref (branch, tag, etc) | 20 | | `github_user` | String | | Github user for authentication | 21 | | `github_token` | String | | Github token for authentication | 22 | | `host` | String | `https://github.com` | Github endpoint host | 23 | | `owner` | String | | Owner for extracted archive | 24 | | `group` | String | | Group for extracted archive | 25 | | `extract_to` | String | | Path to extract archive to (required) | 26 | | `force` | `true`, `false` | `false` | Force downloading and extracting archive | 27 | 28 | ## Examples 29 | 30 | ```ruby 31 | github_archive 'elixir-lang/elixir' do 32 | extract_to '/tmp/test' 33 | end 34 | 35 | github_archive 'elixir-lang/elixir' do 36 | extract_to '/tmp/test' 37 | action :delete 38 | end 39 | ``` 40 | -------------------------------------------------------------------------------- /documentation/asset.md: -------------------------------------------------------------------------------- 1 | # github_asset 2 | 3 | [Back to resource list](../README.md#resources) 4 | 5 | Downloads an asset from a Github repository 6 | 7 | ## Actions 8 | 9 | | Action | Description | 10 | | ----------- | -------------------------------------------------------- | 11 | | `:download` | Downloads an asset from a Github repository | 12 | | `:extract` | Downloads and extracts an asset from a Github repository | 13 | | `:delete` | Deletes a local asset from a Github repository | 14 | 15 | ## Properties 16 | 17 | | Name | Type | Default | Description | 18 | | -------------- | --------------- | ------------- | ---------------------------------------- | 19 | | `file` | String | Resource name | File name of the asset | 20 | | `release` | String | | Release name of the asset (required) | 21 | | `repo` | String | | Repository org and name | 22 | | `github_user` | String | | Github user for authentication | 23 | | `github_token` | String | | Github token for authentication | 24 | | `owner` | String | | Owner for extracted archive | 25 | | `group` | String | | Group for extracted archive | 26 | | `force` | `true`, `false` | `false` | Force downloading and extracting archive | 27 | | `extract_to` | String | | Path to extract asset to | 28 | 29 | ## Examples 30 | 31 | ```ruby 32 | github_asset 'Precompiled.zip' do 33 | repo 'elixir-lang/elixir' 34 | release 'v1.12.2' 35 | end 36 | 37 | github_asset 'Precompiled.zip' do 38 | repo 'elixir-lang/elixir' 39 | release 'v1.12.2' 40 | action :delete 41 | end 42 | 43 | github_asset 'Precompiled.zip' do 44 | repo 'elixir-lang/elixir' 45 | release 'v1.12.2' 46 | extract_to '/opt/elixir' 47 | action :extract 48 | end 49 | ``` 50 | -------------------------------------------------------------------------------- /documentation/deploy.md: -------------------------------------------------------------------------------- 1 | # github_deploy 2 | 3 | [Back to resource list](../README.md#resources) 4 | 5 | Downloads an asset from a Github repository and then deploys it as an application 6 | 7 | ## Actions 8 | 9 | | Action | Description | 10 | | --------- | --------------------------------------------------------------- | 11 | | `:deploy` | Downloads an asset from a Github repository and then deploys it | 12 | 13 | ## Properties 14 | 15 | | Name | Type | Default | Description | 16 | | -------------------- | --------------- | -------------------- | ------------------------------------------- | 17 | | `repo` | String | Resource name | Repository org and name | 18 | | `version` | String | | Git ref (branch, tag, etc) (required) | 19 | | `github_user` | String | | Github user for authentication | 20 | | `github_token` | String | | Github token for authentication | 21 | | `host` | String | `https://github.com` | Github endpoint host | 22 | | `path` | String | | Path to deploy the application | 23 | | `owner` | String | | Owner for extracted archive | 24 | | `group` | String | | Group for extracted archive | 25 | | `shared_directories` | Array | `['pids', 'logs']` | Shared directories to create an symlink | 26 | | `configure` | Proc | | Block of code to run in a configure phase | 27 | | `before_migrate` | Proc | | Block of code to run before migration phase | 28 | | `after_migrate` | Proc | | Block of code to run after migration phase | 29 | | `migrate` | Proc | | Block of code to run during migration phase | 30 | | `force` | `true`, `false` | `false` | Force downloading and extracting archive | 31 | 32 | ## Examples 33 | 34 | ```ruby 35 | github_deploy 'elixir-lang/elixir' do 36 | version 'v1.12' 37 | path '/tmp/deploy' 38 | end 39 | ``` 40 | -------------------------------------------------------------------------------- /kitchen.dokken.yml: -------------------------------------------------------------------------------- 1 | driver: 2 | name: dokken 3 | privileged: true 4 | chef_version: <%= ENV['CHEF_VERSION'] || 'current' %> 5 | 6 | transport: { name: dokken } 7 | provisioner: { name: dokken } 8 | 9 | platforms: 10 | - name: almalinux-8 11 | driver: 12 | image: dokken/almalinux-8 13 | pid_one_command: /usr/lib/systemd/systemd 14 | 15 | - name: almalinux-9 16 | driver: 17 | image: dokken/almalinux-9 18 | pid_one_command: /usr/lib/systemd/systemd 19 | 20 | - name: amazonlinux-2023 21 | driver: 22 | image: dokken/amazonlinux-2023 23 | pid_one_command: /usr/lib/systemd/systemd 24 | 25 | - name: centos-7 26 | driver: 27 | image: dokken/centos-7 28 | pid_one_command: /usr/lib/systemd/systemd 29 | 30 | - name: centos-stream-8 31 | driver: 32 | image: dokken/centos-stream-8 33 | pid_one_command: /usr/lib/systemd/systemd 34 | 35 | - name: centos-stream-9 36 | driver: 37 | image: dokken/centos-stream-9 38 | pid_one_command: /usr/lib/systemd/systemd 39 | 40 | - name: debian-9 41 | driver: 42 | image: dokken/debian-9 43 | pid_one_command: /bin/systemd 44 | 45 | - name: debian-10 46 | driver: 47 | image: dokken/debian-10 48 | pid_one_command: /bin/systemd 49 | 50 | - name: debian-11 51 | driver: 52 | image: dokken/debian-11 53 | pid_one_command: /bin/systemd 54 | 55 | - name: debian-12 56 | driver: 57 | image: dokken/debian-12 58 | pid_one_command: /bin/systemd 59 | 60 | - name: fedora-latest 61 | driver: 62 | image: dokken/fedora-latest 63 | pid_one_command: /usr/lib/systemd/systemd 64 | 65 | - name: opensuse-leap-15 66 | driver: 67 | image: dokken/opensuse-leap-15 68 | pid_one_command: /usr/lib/systemd/systemd 69 | 70 | - name: oraclelinux-7 71 | driver: 72 | image: dokken/oraclelinux-7 73 | pid_one_command: /usr/lib/systemd/systemd 74 | 75 | - name: oraclelinux-8 76 | driver: 77 | image: dokken/oraclelinux-8 78 | pid_one_command: /usr/lib/systemd/systemd 79 | 80 | - name: oraclelinux-9 81 | driver: 82 | image: dokken/oraclelinux-9 83 | pid_one_command: /usr/lib/systemd/systemd 84 | 85 | - name: rockylinux-8 86 | driver: 87 | image: dokken/rockylinux-8 88 | pid_one_command: /usr/lib/systemd/systemd 89 | 90 | - name: rockylinux-9 91 | driver: 92 | image: dokken/rockylinux-9 93 | pid_one_command: /usr/lib/systemd/systemd 94 | 95 | - name: ubuntu-18.04 96 | driver: 97 | image: dokken/ubuntu-18.04 98 | pid_one_command: /bin/systemd 99 | 100 | - name: ubuntu-20.04 101 | driver: 102 | image: dokken/ubuntu-20.04 103 | pid_one_command: /bin/systemd 104 | 105 | - name: ubuntu-22.04 106 | driver: 107 | image: dokken/ubuntu-22.04 108 | pid_one_command: /bin/systemd 109 | 110 | - name: ubuntu-23.04 111 | driver: 112 | image: dokken/ubuntu-23.04 113 | pid_one_command: /bin/systemd 114 | -------------------------------------------------------------------------------- /kitchen.exec.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: { name: exec } 3 | transport: { name: exec } 4 | 5 | platforms: 6 | - name: macos-latest 7 | - name: windows-latest 8 | -------------------------------------------------------------------------------- /kitchen.global.yml: -------------------------------------------------------------------------------- 1 | --- 2 | provisioner: 3 | name: chef_infra 4 | product_name: chef 5 | product_version: <%= ENV['CHEF_VERSION'] || 'latest' %> 6 | channel: stable 7 | install_strategy: once 8 | chef_license: accept 9 | enforce_idempotency: <%= ENV['ENFORCE_IDEMPOTENCY'] || true %> 10 | multiple_converge: <%= ENV['MULTIPLE_CONVERGE'] || 2 %> 11 | deprecations_as_errors: true 12 | log_level: <%= ENV['CHEF_LOG_LEVEL'] || 'auto' %> 13 | 14 | verifier: 15 | name: inspec 16 | 17 | platforms: 18 | - name: almalinux-8 19 | - name: almalinux-9 20 | - name: amazonlinux-2023 21 | - name: centos-7 22 | - name: centos-stream-8 23 | - name: centos-stream-9 24 | - name: debian-9 25 | - name: debian-10 26 | - name: debian-11 27 | - name: debian-12 28 | - name: fedora-latest 29 | - name: opensuse-leap-15 30 | - name: oraclelinux-7 31 | - name: oraclelinux-8 32 | - name: oraclelinux-9 33 | - name: rockylinux-8 34 | - name: rockylinux-9 35 | - name: ubuntu-18.04 36 | - name: ubuntu-20.04 37 | - name: ubuntu-22.04 38 | - name: ubuntu-23.04 39 | -------------------------------------------------------------------------------- /kitchen.yml: -------------------------------------------------------------------------------- 1 | driver: 2 | name: vagrant 3 | 4 | provisioner: 5 | name: chef_infra 6 | product_name: chef 7 | enforce_idempotency: true 8 | multiple_converge: 2 9 | deprecations_as_errors: true 10 | chef_license: accept-no-persist 11 | 12 | verifier: 13 | name: inspec 14 | 15 | platforms: 16 | - name: ubuntu-20.04 17 | 18 | suites: 19 | - name: default 20 | run_list: 21 | - recipe[test] 22 | -------------------------------------------------------------------------------- /libraries/github_archive.rb: -------------------------------------------------------------------------------- 1 | require 'open-uri' 2 | require 'uri' 3 | require 'fileutils' 4 | require_relative 'github_errors' 5 | 6 | module GithubCB 7 | class Archive 8 | class << self 9 | def default_host 10 | @default_host ||= 'https://github.com' 11 | end 12 | end 13 | 14 | attr_reader :fqrn 15 | attr_reader :organization 16 | attr_reader :repo 17 | attr_reader :version 18 | attr_reader :host 19 | 20 | def initialize(fqrn, options = {}) 21 | @fqrn = fqrn 22 | @organization, @repo = fqrn.split('/') 23 | @version = options[:version] ||= 'master' 24 | @host = options[:host] ||= self.class.default_host 25 | end 26 | 27 | # @option options [String] :user 28 | # @option options [String] :token 29 | # @option options [Boolean] :force 30 | def download(options = {}) 31 | if options[:force] 32 | FileUtils.rm_rf(local_archive_path) 33 | end 34 | 35 | FileUtils.mkdir_p(File.dirname(local_archive_path)) 36 | file = ::File.open(local_archive_path, 'wb') 37 | 38 | URI.open(download_uri, http_basic_authentication: [options[:user], options[:token]]) do |source| 39 | IO.copy_stream(source, file) 40 | end 41 | rescue OpenURI::HTTPError => ex 42 | case ex.message 43 | when /406 Not Acceptable/ 44 | raise GithubCB::AuthenticationError 45 | else 46 | raise ex 47 | end 48 | ensure 49 | file.close unless file.nil? 50 | end 51 | 52 | def downloaded? 53 | File.exist?(local_archive_path) 54 | end 55 | 56 | def local_archive_path 57 | File.join(archive_cache_path, "#{repo}-#{version}.tar.gz") 58 | end 59 | 60 | alias_method :path, :local_archive_path 61 | 62 | private 63 | 64 | def archive_cache_path 65 | File.join(Chef::Config[:file_cache_path], 'github_deploy', 'archives') 66 | end 67 | 68 | def download_uri 69 | uri = URI.parse(host) 70 | uri.path = "/#{fqrn}/archive/#{URI.encode_www_form_component(version)}.tar.gz" 71 | uri 72 | end 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /libraries/github_asset.rb: -------------------------------------------------------------------------------- 1 | require 'net/http' 2 | require 'open-uri' 3 | require 'uri' 4 | require 'fileutils' 5 | require_relative 'github_errors' 6 | 7 | module GithubCB 8 | class Asset 9 | class << self 10 | def asset_cache 11 | ::File.join(Chef::Config[:file_cache_path], 'github_assets') 12 | end 13 | 14 | def asset_path(fqrn, tag, name) 15 | ::File.join(asset_cache, fqrn, tag, name) 16 | end 17 | 18 | def default_host 19 | @default_host ||= 'https://github.com' 20 | end 21 | end 22 | 23 | attr_reader :fqrn 24 | attr_reader :organization 25 | attr_reader :repo 26 | attr_reader :tag_name 27 | attr_reader :name 28 | attr_reader :host 29 | 30 | def initialize(fqrn, options = {}) 31 | @fqrn = fqrn 32 | @organization, @repo = fqrn.split('/') 33 | @tag_name = options[:release] 34 | @name = options[:name] 35 | @host = options[:host] ||= self.class.default_host 36 | end 37 | 38 | def asset_url(options) 39 | require 'octokit' 40 | 41 | Octokit.configure do |c| 42 | c.login = options[:user] 43 | c.access_token = options[:token] 44 | end 45 | 46 | release = Octokit.releases(fqrn).find do |r| 47 | r.tag_name == tag_name 48 | end 49 | 50 | raise GithubCB::ReleaseNotFound, 'release not found' if release.nil? 51 | 52 | asset = release.rels[:assets].get.data.find do |a| 53 | a.name == name 54 | end 55 | 56 | raise GithubCB::AssetNotFound, 'asset not found' if asset.nil? 57 | 58 | asset.rels[:self].href 59 | end 60 | 61 | # @option options [String] :path 62 | # @option options [String] :user 63 | # @option options [String] :token 64 | # @option options [Boolean] :force 65 | def download(options = {}) 66 | if options[:force] 67 | FileUtils.rm_rf(options[:path]) 68 | end 69 | 70 | return false if downloaded?(options[:path]) 71 | 72 | proxy_uri = ENV['https_proxy'] ? URI.parse(ENV['https_proxy']) : URI('') 73 | proxy_uri = URI.parse(ENV['HTTPS_PROXY']) if ENV['HTTPS_PROXY'] 74 | p_user, p_pass = proxy_uri.userinfo.split(/:/) if proxy_uri.userinfo 75 | uri = URI(asset_url(options)) 76 | res = Net::HTTP::Proxy(proxy_uri.host, proxy_uri.port, p_user, p_pass).start(uri.hostname, uri.port, use_ssl: true) do |http| 77 | req = Net::HTTP::Get.new(uri.to_s) 78 | req['Authorization'] = "token #{options[:token]}" unless options[:token].nil? 79 | req['Accept'] = 'application/octet-stream' 80 | 81 | http.request(req) 82 | end 83 | 84 | FileUtils.mkdir_p(::File.dirname(options[:path])) 85 | file = ::File.open(options[:path], 'wb') 86 | 87 | URI.open(res['location']) { |source| IO.copy_stream(source, file) } 88 | true 89 | rescue OpenURI::HTTPError => ex 90 | case ex.message 91 | when /406 Not Acceptable/ 92 | raise GithubCB::AuthenticationError 93 | else 94 | raise ex 95 | end 96 | ensure 97 | file.close unless file.nil? 98 | end 99 | 100 | def downloaded?(path) 101 | ::File.exist?(path) 102 | end 103 | end 104 | end 105 | -------------------------------------------------------------------------------- /libraries/github_errors.rb: -------------------------------------------------------------------------------- 1 | module GithubCB 2 | class GHError < StandardError; end 3 | 4 | class AuthenticationError < GHError 5 | def initialize 6 | super('Unable to authenticate with Github API. Check your username/password and try again.') 7 | end 8 | end 9 | 10 | class ReleaseNotFound < GHError; end 11 | class AssetNotFound < GHError; end 12 | end 13 | -------------------------------------------------------------------------------- /metadata.rb: -------------------------------------------------------------------------------- 1 | name 'github' 2 | maintainer 'Sous Chefs' 3 | maintainer_email 'help@sous-chefs.org' 4 | license 'Apache-2.0' 5 | description 'A Library Cookbook for interacting with the Github API' 6 | version '1.1.15' 7 | source_url 'https://github.com/sous-chefs/github' 8 | issues_url 'https://github.com/sous-chefs/github/issues' 9 | chef_version '>= 15.3' 10 | 11 | supports 'amazon' 12 | supports 'centos' 13 | supports 'debian' 14 | supports 'freebsd' 15 | supports 'mac_os_x' 16 | supports 'opensuse' 17 | supports 'opensuseleap' 18 | supports 'oracle' 19 | supports 'redhat' 20 | supports 'scientific' 21 | supports 'smartos' 22 | supports 'suse' 23 | supports 'ubuntu' 24 | supports 'windows' 25 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": ["config:base"], 4 | "packageRules": [ 5 | { 6 | "groupName": "Actions", 7 | "matchUpdateTypes": ["minor", "patch", "pin"], 8 | "automerge": true, 9 | "addLabels": ["Release: Patch", "Skip: Announcements"] 10 | }, 11 | { 12 | "groupName": "Actions", 13 | "matchUpdateTypes": ["major"], 14 | "automerge": false, 15 | "addLabels": ["Release: Patch", "Skip: Announcements"] 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /resources/archive.rb: -------------------------------------------------------------------------------- 1 | unified_mode true 2 | 3 | default_action :extract 4 | 5 | property :repo, String, name_property: true 6 | property :version, String, default: 'master' 7 | property :github_user, String 8 | property :github_token, String 9 | property :host, String 10 | property :owner, String 11 | property :group, String 12 | property :extract_to, String, required: true 13 | property :force, [true, false], default: false 14 | 15 | action :extract do 16 | unless new_resource.force || archive.downloaded? 17 | converge_by "downloading archive #{new_resource.name} to #{archive.path}" do 18 | archive.download( 19 | user: new_resource.github_user, 20 | token: new_resource.github_token, 21 | force: new_resource.force 22 | ) 23 | end 24 | end 25 | 26 | unless new_resource.force || ::File.exist?(new_resource.extract_to) 27 | converge_by "extracting archive #{archive.path} to #{new_resource.extract_to}" do 28 | archive_file archive.path do 29 | destination new_resource.extract_to 30 | overwrite new_resource.force 31 | owner new_resource.owner 32 | group new_resource.group 33 | end 34 | end 35 | end 36 | end 37 | 38 | action :delete do 39 | file archive.path do 40 | action :delete 41 | end 42 | 43 | directory new_resource.extract_to do 44 | recursive true 45 | action :delete 46 | end 47 | end 48 | 49 | action_class do 50 | def archive 51 | GithubCB::Archive.new(new_resource.repo, version: new_resource.version, host: new_resource.host) 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /resources/asset.rb: -------------------------------------------------------------------------------- 1 | unified_mode true 2 | 3 | default_action :download 4 | 5 | property :file, String, name_property: true 6 | property :release, String, required: true 7 | property :repo, String, required: true 8 | property :github_user, String 9 | property :github_token, String 10 | property :owner, String 11 | property :group, String 12 | property :force, [true, false], default: false 13 | property :extract_to, String, required: [:extract] 14 | 15 | action :download do 16 | do_download 17 | end 18 | 19 | action :extract do 20 | do_download 21 | 22 | unless new_resource.force || ::File.exist?(new_resource.extract_to) 23 | converge_by "extracting #{new_resource.file} to #{new_resource.extract_to}" do 24 | archive_file asset_path do 25 | destination new_resource.extract_to 26 | overwrite new_resource.force 27 | owner new_resource.owner 28 | group new_resource.group 29 | end 30 | end 31 | end 32 | end 33 | 34 | action :delete do 35 | file asset_path do 36 | action :delete 37 | end 38 | 39 | directory ::File.dirname(asset_path) do 40 | recursive true 41 | action :delete 42 | end 43 | end 44 | 45 | action_class do 46 | def do_download 47 | chef_gem 'octokit' do 48 | compile_time true 49 | end 50 | 51 | unless asset.downloaded?(asset_path) 52 | converge_by "downloading #{new_resource.file} to #{asset_path}" do 53 | asset.download( 54 | user: new_resource.github_user, 55 | token: new_resource.github_token, 56 | force: new_resource.force, 57 | path: asset_path 58 | ) 59 | end 60 | end 61 | end 62 | 63 | def asset 64 | GithubCB::Asset.new(new_resource.repo, name: new_resource.file, release: new_resource.release) 65 | end 66 | 67 | def asset_path 68 | GithubCB::Asset.asset_path(new_resource.repo, new_resource.release, new_resource.file) 69 | end 70 | end 71 | -------------------------------------------------------------------------------- /resources/deploy.rb: -------------------------------------------------------------------------------- 1 | unified_mode true 2 | 3 | default_action :deploy 4 | 5 | property :repo, String, name_property: true 6 | property :version, String, required: true 7 | property :github_user, String 8 | property :github_token, String 9 | property :host, String 10 | property :path, String, required: true 11 | property :owner, String 12 | property :group, String 13 | property :shared_directories, Array, default: %w(pids log) 14 | property :force, [true, false], default: false 15 | 16 | property :configure, Proc 17 | property :before_migrate, Proc 18 | property :after_migrate, Proc 19 | property :migrate, Proc 20 | 21 | action_class do 22 | def deploy_path 23 | ::File.join(release_path, new_resource.version) 24 | end 25 | 26 | def release_path 27 | ::File.join(new_resource.path, 'releases') 28 | end 29 | 30 | def shared_path 31 | ::File.join(new_resource.path, 'shared') 32 | end 33 | 34 | def current_path 35 | ::File.join(new_resource.path, 'current') 36 | end 37 | end 38 | 39 | action :deploy do 40 | [ release_path, shared_path ].each do |path| 41 | directory path do 42 | owner new_resource.owner 43 | group new_resource.group 44 | mode '770' 45 | recursive true 46 | end 47 | end 48 | 49 | new_resource.shared_directories.each do |path| 50 | directory "#{shared_path}/#{path}" do 51 | owner new_resource.owner 52 | group new_resource.group 53 | mode '770' 54 | recursive true 55 | end 56 | end 57 | 58 | github_archive new_resource.repo do 59 | should_force = new_resource.version == 'master' || new_resource.force 60 | 61 | version new_resource.version 62 | github_user new_resource.github_user 63 | github_token new_resource.github_token 64 | host new_resource.host 65 | extract_to deploy_path 66 | force should_force 67 | 68 | if should_force 69 | action [ :delete, :extract ] 70 | else 71 | action :extract 72 | end 73 | notifies :run, 'ruby_block[configure]' 74 | notifies :run, 'ruby_block[before-migrate]' 75 | notifies :run, 'ruby_block[migrate]' 76 | notifies :run, 'ruby_block[after-migrate]' 77 | end 78 | 79 | ruby_block 'configure' do 80 | block do 81 | if new_resource.configure 82 | Chef::Log.info "github_deploy[#{new_resource.name}] Running configure proc" 83 | recipe_eval(&new_resource.configure.to_proc) 84 | end 85 | end 86 | action :nothing 87 | end 88 | 89 | ruby_block 'before-migrate' do 90 | block do 91 | if new_resource.before_migrate 92 | Chef::Log.info "github_deploy[#{new_resource.name}] Running before migrate proc" 93 | recipe_eval(&new_resource.before_migrate.to_proc) 94 | end 95 | end 96 | action :nothing 97 | end 98 | 99 | ruby_block 'migrate' do 100 | block do 101 | if new_resource.migrate 102 | Chef::Log.info "github_deploy[#{new_resource.name}] Running migrate proc" 103 | recipe_eval(&new_resource.migrate.to_proc) 104 | end 105 | end 106 | action :nothing 107 | end 108 | 109 | ruby_block 'after-migrate' do 110 | block do 111 | if new_resource.after_migrate 112 | Chef::Log.info "github_deploy[#{new_resource.name}] Running after migrate proc" 113 | recipe_eval(&new_resource.after_migrate.to_proc) 114 | end 115 | end 116 | action :nothing 117 | end 118 | 119 | link current_path do 120 | to deploy_path 121 | owner new_resource.owner 122 | group new_resource.group 123 | end 124 | end 125 | -------------------------------------------------------------------------------- /spec/libraries/github_archive_spec.rb: -------------------------------------------------------------------------------- 1 | # require 'spec_helper' 2 | # 3 | # describe GithubCB::Archive do 4 | # describe 'ClassMethods' do 5 | # describe '::new' do 6 | # let(:fqrn) { 'berkshelf/berkshelf-cookbook' } 7 | # let(:options) { {} } 8 | # subject { described_class.new(fqrn, options) } 9 | # 10 | # its(:organization) { should eq('berkshelf') } 11 | # its(:repo) { should eq('berkshelf-cookbook') } 12 | # its(:host) { should eq('https://github.com') } 13 | # its(:version) { should eq('master') } 14 | # 15 | # context 'given an explicit host' do 16 | # let(:host) { 'https://github.vialstudios.com' } 17 | # before { options[:host] = host } 18 | # 19 | # its(:host) { should eq(host) } 20 | # end 21 | # 22 | # context 'given an explicit version' do 23 | # let(:version) { '1.2.3' } 24 | # before { options[:version] = version } 25 | # 26 | # its(:version) { should eq(version) } 27 | # end 28 | # end 29 | # end 30 | # 31 | # subject { described_class.new('berkshelf/berkshelf-cookbook') } 32 | # 33 | # describe '#download' do 34 | # before { subject.download } 35 | # 36 | # it 'creates downloads the archive into the chef cache' do 37 | # target = File.join(Chef::Config[:file_cache_path], 38 | # 'github_deploy', 'archives', 'berkshelf-cookbook-master.tar.gz') 39 | # 40 | # expect(File.exist?(target)).to be_true 41 | # end 42 | # end 43 | # 44 | # describe '#downloaded?' do 45 | # context 'when the archive is present on disk' do 46 | # before { subject.download } 47 | # 48 | # it 'returns true' do 49 | # expect(subject.downloaded?).to be_true 50 | # end 51 | # end 52 | # 53 | # context 'when it is not present on disk' do 54 | # it 'returns false' do 55 | # expect(subject.downloaded?).to be_false 56 | # end 57 | # end 58 | # end 59 | # 60 | # describe '#extract' do 61 | # before { subject.download } 62 | # let(:target) { File.join(tmp_path, 'berkshelf-extract') } 63 | # 64 | # it 'extracts the contents of the archive into the target directory' do 65 | # subject.extract(target) 66 | # expect(File.exist?(File.join(target, 'metadata.rb'))).to be_true 67 | # end 68 | # end 69 | # end 70 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # require 'rubygems' 2 | # require 'bundler' 3 | # require 'rspec' 4 | # require 'spork' 5 | # require 'chef' 6 | # 7 | # Spork.prefork do 8 | # Dir[File.join(File.expand_path('../spec/support/**/*.rb', __dir__))].each { |f| require f } 9 | # 10 | # RSpec.configure do |config| 11 | # config.expect_with :rspec do |c| 12 | # c.syntax = :expect 13 | # end 14 | # 15 | # config.mock_with :rspec 16 | # config.treat_symbols_as_metadata_keys_with_true_values = true 17 | # config.filter_run focus: true 18 | # config.run_all_when_everything_filtered = true 19 | # 20 | # config.before(:each) do 21 | # Chef::Config[:file_cache_path] = File.join(tmp_path, 'chef_cache') 22 | # FileUtils.rm_rf(tmp_path) 23 | # FileUtils.mkdir_p(tmp_path) 24 | # FileUtils.mkdir_p(Chef::Config[:file_cache_path]) 25 | # end 26 | # end 27 | # 28 | # def tmp_path 29 | # File.expand_path(File.join(File.dirname(__FILE__), '../tmp')) 30 | # end 31 | # end 32 | # 33 | # Spork.each_run do 34 | # Dir["#{File.expand_path('..', File.dirname(__FILE__))}/libraries/*.rb"].sort.each do |path| 35 | # require_relative "../libraries/#{File.basename(path, '.rb')}" 36 | # end 37 | # end 38 | -------------------------------------------------------------------------------- /test/fixtures/cookbooks/test/metadata.rb: -------------------------------------------------------------------------------- 1 | name 'test' 2 | maintainer 'Sous Chefs' 3 | maintainer_email 'help@sous-chefs.org' 4 | license 'Apache-2.0' 5 | description 'Testing cookbook' 6 | version '0.0.1' 7 | depends 'github' 8 | -------------------------------------------------------------------------------- /test/fixtures/cookbooks/test/recipes/default.rb: -------------------------------------------------------------------------------- 1 | github_asset 'Precompiled.zip' do 2 | repo 'elixir-lang/elixir' 3 | release 'v1.12.2' 4 | end 5 | 6 | github_asset 'Precompiled.zip-delete' do 7 | file 'Precompiled.zip' 8 | repo 'elixir-lang/elixir' 9 | release 'v1.12.1' 10 | action :delete 11 | end 12 | 13 | github_asset 'Precompiled.zip-extract' do 14 | file 'Precompiled.zip' 15 | repo 'elixir-lang/elixir' 16 | release 'v1.13.0' 17 | extract_to '/tmp/extract' 18 | action :extract 19 | end 20 | 21 | github_archive 'elixir-lang/elixir' do 22 | extract_to '/tmp/test' 23 | end 24 | 25 | github_archive 'elixir-lang/elixir-delete' do 26 | repo 'elixir-lang/elixir' 27 | version 'delete' 28 | extract_to '/tmp/delete' 29 | action :delete 30 | end 31 | 32 | github_deploy 'elixir-lang/elixir' do 33 | version 'v1.12' 34 | path '/tmp/deploy' 35 | end 36 | -------------------------------------------------------------------------------- /test/integration/default/controls/default.rb: -------------------------------------------------------------------------------- 1 | cache_dir = inspec.file('/opt/kitchen').exist? ? '/opt/kitchen/cache' : '/tmp/kitchen/cache' 2 | 3 | control 'github-cookbook' do 4 | [ 5 | "#{cache_dir}/github_assets/elixir-lang/elixir/v1.12.2/Precompiled.zip", 6 | "#{cache_dir}/github_assets/elixir-lang/elixir/v1.13.0/Precompiled.zip", 7 | "#{cache_dir}/github_deploy/archives/elixir-master.tar.gz", 8 | "#{cache_dir}/github_deploy/archives/elixir-v1.12.tar.gz", 9 | '/tmp/test/elixir-main/README.md', 10 | '/tmp/deploy/releases/v1.12/elixir-1.12/README.md', 11 | '/tmp/extract/bin/elixir', 12 | ].each do |f| 13 | describe file f do 14 | it { should exist } 15 | its('size') { should > 0 } 16 | end 17 | end 18 | 19 | [ 20 | "#{cache_dir}/github_assets/elixir-lang/elixir/v1.12.1/Precompiled.zip", 21 | "#{cache_dir}/github_deploy/archives/elixir-delete.tar.gz", 22 | ].each do |f| 23 | describe file f do 24 | it { should_not exist } 25 | end 26 | end 27 | 28 | %w( 29 | /tmp/test 30 | /tmp/deploy/releases/v1.12 31 | ).each do |d| 32 | describe directory d do 33 | it { should exist } 34 | end 35 | end 36 | 37 | describe directory '/tmp/delete' do 38 | it { should_not exist } 39 | end 40 | 41 | %w( 42 | /tmp/deploy/releases 43 | /tmp/deploy/shared 44 | /tmp/deploy/shared/pids 45 | /tmp/deploy/shared/log 46 | ).each do |d| 47 | describe directory d do 48 | it { should exist } 49 | its('mode') { should cmp '0770' } 50 | end 51 | end 52 | 53 | describe file '/tmp/deploy/current' do 54 | its('link_path') { should eq '/tmp/deploy/releases/v1.12' } 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /test/integration/default/inspec.yml: -------------------------------------------------------------------------------- 1 | name: github-cookbook 2 | --------------------------------------------------------------------------------