From fe75b0ec0250ee46aeaef2a58f8e9611b4fe59e5 Mon Sep 17 00:00:00 2001 From: Lance Albertson Date: Wed, 8 Sep 2021 12:47:08 -0700 Subject: [PATCH] Sous Chefs Adoption (#15) * Cookstyle fixes Signed-off-by: Lance Albertson * Standardize files for Sous Chefs Signed-off-by: Lance Albertson * Update README.md Signed-off-by: Lance Albertson * Update metadata.rb to Sous Chefs Signed-off-by: Lance Albertson * Comment out broken ChefSpec Signed-off-by: Lance Albertson * Remove Guardfile Signed-off-by: Lance Albertson * Migrate to modern custom resources Signed-off-by: Lance Albertson * Switch to just testing on Ubuntu Signed-off-by: Lance Albertson * Add InSpec tests Signed-off-by: Lance Albertson * Add GH CI config Signed-off-by: Lance Albertson * Update CHANGELOG Signed-off-by: Lance Albertson * Add documentation Signed-off-by: Lance Albertson * Remove kind_of references in resources in resources in resources in resources Signed-off-by: Lance Albertson --- .circleci/config.yml | 10 + .delivery/project.toml | 9 + .editorconfig | 19 ++ .envrc | 1 + .gitattributes | 1 + .github/CODEOWNERS | 1 + .github/workflows/ci.yml | 60 +++++ .github/workflows/md-links.yml | 19 ++ .github/workflows/stale.yml | 25 +++ .gitignore | 51 ++++- .mdlrc | 1 + .overcommit.yml | 20 ++ .vscode/extensions.json | 7 + .yamllint | 13 ++ Berksfile | 6 +- CHANGELOG.md | 5 + CODE_OF_CONDUCT.md | 3 + CONTRIBUTING.md | 4 + Dangerfile | 47 ++++ Gemfile | 13 -- Guardfile | 12 - LICENSE | 209 +++++++++++++++++- README.md | 55 +++-- TESTING.md | 3 + chefignore | 101 +++++---- documentation/.gitkeep | 0 documentation/archive.md | 39 ++++ documentation/asset.md | 40 ++++ documentation/deploy.md | 39 ++++ kitchen.dokken.yml | 23 ++ kitchen.yml | 21 ++ libraries/github_archive.rb | 30 +-- libraries/github_asset.rb | 2 +- metadata.rb | 30 ++- providers/archive.rb | 36 --- providers/asset.rb | 28 --- providers/deploy.rb | 84 ------- resources/archive.rb | 62 +++++- resources/asset.rb | 61 +++-- resources/deploy.rb | 143 +++++++++--- spec/libraries/github_archive_spec.rb | 138 ++++++------ spec/spec_helper.rb | 74 +++---- test/fixtures/cookbooks/test/metadata.rb | 7 + .../cookbooks/test/recipes/default.rb | 27 +++ test/integration/default/controls/default.rb | 54 +++++ test/integration/default/inspec.yml | 1 + 46 files changed, 1189 insertions(+), 445 deletions(-) create mode 100644 .circleci/config.yml create mode 100644 .delivery/project.toml create mode 100755 .editorconfig create mode 100644 .envrc create mode 100644 .gitattributes create mode 100644 .github/CODEOWNERS create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/md-links.yml create mode 100644 .github/workflows/stale.yml create mode 100644 .mdlrc create mode 100644 .overcommit.yml create mode 100644 .vscode/extensions.json create mode 100644 .yamllint create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 Dangerfile delete mode 100644 Gemfile delete mode 100644 Guardfile create mode 100644 TESTING.md create mode 100644 documentation/.gitkeep create mode 100644 documentation/archive.md create mode 100644 documentation/asset.md create mode 100644 documentation/deploy.md create mode 100644 kitchen.dokken.yml create mode 100644 kitchen.yml delete mode 100644 providers/archive.rb delete mode 100644 providers/asset.rb delete mode 100644 providers/deploy.rb create mode 100644 test/fixtures/cookbooks/test/metadata.rb create mode 100644 test/fixtures/cookbooks/test/recipes/default.rb create mode 100644 test/integration/default/controls/default.rb create mode 100644 test/integration/default/inspec.yml diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..8af810e --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,10 @@ +--- +version: 2.1 +orbs: + kitchen: sous-chefs/kitchen@2 +workflows: + danger: + jobs: + - kitchen/danger: + name: danger + context: Danger-Minimal diff --git a/.delivery/project.toml b/.delivery/project.toml new file mode 100644 index 0000000..0d6f0ae --- /dev/null +++ b/.delivery/project.toml @@ -0,0 +1,9 @@ +[local_phases] +unit = "rspec spec/" +lint = 'cookstyle --display-cop-names --extra-details' +syntax = "echo skipping" +provision = "echo skipping" +deploy = "echo skipping" +smoke = "echo skipping" +functional = "echo skipping" +cleanup = "echo skipping" diff --git a/.editorconfig b/.editorconfig new file mode 100755 index 0000000..cc21b04 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,19 @@ +# https://EditorConfig.org + +# top-most EditorConfig file +root=true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true + +# 2 space indentation +indent_style = space +indent_size = 2 + +# Avoid issues parsing cookbook files later +charset = utf-8 + +# Avoid cookstyle warnings +trim_trailing_whitespace = true diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..6ed589e --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use chefworkstation diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..6313b56 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..7cc52a9 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @sous-chefs/maintainers diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..3562722 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,60 @@ +--- +name: ci + +"on": + pull_request: + push: + branches: + - main + +jobs: + delivery: + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v2 + - name: Run Chef Delivery + uses: actionshub/chef-delivery@main + env: + CHEF_LICENSE: accept-no-persist + + yamllint: + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v2 + - name: Run yaml Lint + uses: actionshub/yamllint@main + + mdl: + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v2 + - name: Run Markdown Lint + uses: actionshub/markdownlint@main + + integration: + needs: [mdl, yamllint, delivery] + runs-on: ubuntu-latest + strategy: + matrix: + os: + - 'ubuntu-2004' + suite: + - 'default' + fail-fast: false + + steps: + - name: Check out code + uses: actions/checkout@v2 + - name: Install Chef + uses: actionshub/chef-install@main + - name: Dokken + uses: actionshub/test-kitchen@main + env: + CHEF_LICENSE: accept-no-persist + KITCHEN_LOCAL_YAML: kitchen.dokken.yml + with: + suite: ${{ matrix.suite }} + os: ${{ matrix.os }} diff --git a/.github/workflows/md-links.yml b/.github/workflows/md-links.yml new file mode 100644 index 0000000..ba887a1 --- /dev/null +++ b/.github/workflows/md-links.yml @@ -0,0 +1,19 @@ +--- +name: md-links + +"on": + pull_request: + push: + branches: [main] + +jobs: + md-links: + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v2 + - name: markdown-link-check + uses: gaurav-nelson/github-action-markdown-link-check@v1 + with: + use-verbose-mode: "yes" + folder-path: "documentation" diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000..9e2ff38 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,25 @@ +--- +name: Mark stale issues and pull requests + +"on": + schedule: [cron: "0 0 * * *"] + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v3 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + close-issue-message: > + Closing due to inactivity. + If this is still an issue please reopen or open another issue. + Alternatively drop by the #sous-chefs channel on the [Chef Community Slack](http://community-slack.chef.io/) and we'll be happy to help! + Thanks, Sous-Chefs. + days-before-close: 7 + days-before-stale: 365 + stale-issue-message: > + Marking stale due to inactivity. + Remove stale label or comment or this will be closed in 7 days. + Alternatively drop by the #sous-chefs channel on the [Chef Community Slack](http://community-slack.chef.io/) and we'll be happy to help! + Thanks, Sous-Chefs. diff --git a/.gitignore b/.gitignore index 1fc8803..be3b9a8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,18 +1,49 @@ -.vagrant -Berksfile.lock +*.rbc +.config +InstalledFiles +pkg +test/tmp +test/version_tmp +tmp +_Store *~ *# .#* \#*# -.*.sw[a-z] *.un~ -/cookbooks +*.tmp +*.bk +*.bkup + +# editor files +.idea +.*.sw[a-z] -# Bundler +# ruby/bundler/rspec files +.ruby-version +.ruby-gemset +.rvmrc Gemfile.lock -bin/* -.bundle/* +.bundle +*.gem +coverage +spec/reports + +# YARD / rdoc artifacts +.yardoc +_yardoc +doc/ +rdoc + +# chef infra stuff +Berksfile.lock +.kitchen +kitchen.local.yml +vendor/ +.coverage/ +.zero-knife.rb +Policyfile.lock.json -.kitchen/ -.kitchen.local.yml -/tmp +# vagrant stuff +.vagrant/ +.vagrant.d/ diff --git a/.mdlrc b/.mdlrc new file mode 100644 index 0000000..4e491d9 --- /dev/null +++ b/.mdlrc @@ -0,0 +1 @@ +rules "~MD013", "~MD024", "~MD026", "~MD029", "~MD033" diff --git a/.overcommit.yml b/.overcommit.yml new file mode 100644 index 0000000..1d27ed8 --- /dev/null +++ b/.overcommit.yml @@ -0,0 +1,20 @@ +--- +PreCommit: + TrailingWhitespace: + enabled: true + YamlLint: + enabled: true + Rspec: + enabled: true + required_executable: 'rspec' + Cookstyle: + enabled: true + required_executable: 'cookstyle' + command: ["cookstyle"] + Delivery: + enabled: true + required_executable: 'delivery' + flags: ['local', 'all'] +CommitMsg: + HardTabs: + enabled: true diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..cd77725 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + "recommendations": [ + "chef-software.chef", + "rebornix.ruby", + "editorconfig.editorconfig" + ] +} diff --git a/.yamllint b/.yamllint new file mode 100644 index 0000000..1b5cea0 --- /dev/null +++ b/.yamllint @@ -0,0 +1,13 @@ +--- +extends: default +rules: + line-length: + max: 256 + level: warning + document-start: disable + braces: + forbid: false + min-spaces-inside: 0 + max-spaces-inside: 1 + min-spaces-inside-empty: -1 + max-spaces-inside-empty: -1 diff --git a/Berksfile b/Berksfile index b5d5531..e09849c 100644 --- a/Berksfile +++ b/Berksfile @@ -1,3 +1,7 @@ -source 'http://api.berkshelf.com' +source 'https://supermarket.chef.io' metadata + +group :integration do + cookbook 'test', path: 'test/fixtures/cookbooks/test' +end diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fe0fb8..3abf92e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,3 +5,8 @@ This file is used to list changes made in each version of the GitHub cookbook. ## Unreleased - Sous-Chefs adoption +- Migrate to modern custom resources and enable `unified_mode` +- Remove dependency on libarchive +- Cookstyle fixes +- Fix URI deprecation issues +- Replace `extract` method with using the `archive_file` native resource diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..20b4adb --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,3 @@ +# Community Guidelines + +This project follows the Chef Community Guidelines diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..a946aea --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,4 @@ +# Contributing + +Please refer to +[https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/CONTRIBUTING.MD](https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/CONTRIBUTING.MD) diff --git a/Dangerfile b/Dangerfile new file mode 100644 index 0000000..bc08b7a --- /dev/null +++ b/Dangerfile @@ -0,0 +1,47 @@ +# Reference: http://danger.systems/reference.html + +# A pull request summary is required. Add a description of the pull request purpose. +# Changelog must be updated for each pull request that changes code. +# Warnings will be issued for: +# Pull request with more than 400 lines of code changed +# Pull reqest that change more than 5 lines without test changes +# Failures will be issued for: +# Pull request without summary +# Pull requests with code changes without changelog entry + +def code_changes? + code = %w(libraries attributes recipes resources files templates) + code.each do |location| + return true unless git.modified_files.grep(/#{location}/).empty? + end + false +end + +def test_changes? + tests = %w(spec test kitchen.yml kitchen.dokken.yml) + tests.each do |location| + return true unless git.modified_files.grep(/#{location}/).empty? + end + false +end + +failure 'Please provide a summary of your Pull Request.' if github.pr_body.length < 10 + +warn 'This is a big Pull Request.' if git.lines_of_code > 400 + +warn 'This is a Table Flip.' if git.lines_of_code > 2000 + +# Require a CHANGELOG entry for non-test changes. +if !git.modified_files.include?('CHANGELOG.md') && code_changes? + failure 'Please include a CHANGELOG entry.' +end + +# Require Major Minor Patch version labels +unless github.pr_labels.grep /minor|major|patch/i + warn 'Please add a release label to this pull request' +end + +# A sanity check for tests. +if git.lines_of_code > 5 && code_changes? && !test_changes? + warn 'This Pull Request is probably missing tests.' +end diff --git a/Gemfile b/Gemfile deleted file mode 100644 index 47d05d6..0000000 --- a/Gemfile +++ /dev/null @@ -1,13 +0,0 @@ -source 'https://rubygems.org' - -group :test do - gem 'libarchive-ruby' - gem 'chef' - gem 'rspec' - gem 'spork' - gem 'guard' - gem 'guard-rspec' - gem 'guard-spork', platforms: :ruby - gem 'coolline' - gem 'fuubar' -end diff --git a/Guardfile b/Guardfile deleted file mode 100644 index ce00f67..0000000 --- a/Guardfile +++ /dev/null @@ -1,12 +0,0 @@ -guard 'spork' do - watch('Gemfile') - watch('spec/spec_helper.rb') { :rspec } - watch(%r{^spec/support/.+\.rb$}) { :rspec } -end - -guard 'rspec', cli: "--color --drb --format Fuubar", all_on_start: false, all_after_pass: false do - watch(%r{^spec/libraries/.+_spec\.rb$}) - - watch(%r{^libraries/(.+)\.rb$}) { |m| "spec/libraries/#{m[1]}_spec.rb" } - watch('spec/spec_helper.rb') { "spec" } -end diff --git a/LICENSE b/LICENSE index 19b445b..8f71f43 100644 --- a/LICENSE +++ b/LICENSE @@ -1,13 +1,202 @@ -Copyright 2013, Jamie Winsor + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - http://www.apache.org/licenses/LICENSE-2.0 + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/README.md b/README.md index f9bb571..730004e 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,50 @@ -# github-cookbook +# github Cookbook -A Library Cookbook for interacting with the Github API +[![Cookbook Version](https://img.shields.io/cookbook/v/github.svg)](https://supermarket.chef.io/cookbooks/github) +[![CI State](https://github.com/sous-chefs/github/workflows/ci/badge.svg)](https://github.com/sous-chefs/github/actions?query=workflow%3Aci) +[![OpenCollective](https://opencollective.com/sous-chefs/backers/badge.svg)](#backers) +[![OpenCollective](https://opencollective.com/sous-chefs/sponsors/badge.svg)](#sponsors) +[![License](https://img.shields.io/badge/License-Apache%202.0-green.svg)](https://opensource.org/licenses/Apache-2.0) + +A Library Cookbook for downloading assets, archives or deploying from Github repositories + +## Maintainers + +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). ## Supported Platforms -* Ubuntu +* Any chef supported platform + +## Resources -## github_asset Resource/Provider +The following resources are provided: -Downloads an asset from a Github release +* [archive](documentation/archive.md) +* [asset](documentation/asset.md) +* [deploy](documentation/deploy.md) -### Actions +## Contributors -- **download** - downloads the asset from the Github releaseto disk. (default) +This project exists thanks to all the people who [contribute.](https://opencollective.com/sous-chefs/contributors.svg?width=890&button=false) -### Parameter Attributes +### Backers -- **name** - name of the asset to download (name attribute) -- **release** - name of the release the asset is a part of -- **repo** - repository the release is a part of (required for private repositories) -- **github_token** - Github token to perform the download with (required for private repositories) -- **owner** - owner of the downloaded asset on disk -- **group** - group of the downloaded asset on disk -- **force** - force downloading even if the asset already exists on disk +Thank you to all our backers! -## HTTP proxy support +![https://opencollective.com/sous-chefs#backers](https://opencollective.com/sous-chefs/backers.svg?width=600&avatarHeight=40) -Ensure the `HTTPS_PROXY` environment variable is set for the shell executing `chef-client` or `chef-solo`. The value should be a fully qualified URL containing the host, port, username, and password for your proxy. +### Sponsors -# Author +Support this project by becoming a sponsor. Your logo will show up here with a link to your website. -Author:: Jamie Winsor () +![https://opencollective.com/sous-chefs/sponsor/0/website](https://opencollective.com/sous-chefs/sponsor/0/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/1/website](https://opencollective.com/sous-chefs/sponsor/1/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/2/website](https://opencollective.com/sous-chefs/sponsor/2/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/3/website](https://opencollective.com/sous-chefs/sponsor/3/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/4/website](https://opencollective.com/sous-chefs/sponsor/4/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/5/website](https://opencollective.com/sous-chefs/sponsor/5/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/6/website](https://opencollective.com/sous-chefs/sponsor/6/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/7/website](https://opencollective.com/sous-chefs/sponsor/7/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/8/website](https://opencollective.com/sous-chefs/sponsor/8/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/9/website](https://opencollective.com/sous-chefs/sponsor/9/avatar.svg?avatarHeight=100) diff --git a/TESTING.md b/TESTING.md new file mode 100644 index 0000000..920e381 --- /dev/null +++ b/TESTING.md @@ -0,0 +1,3 @@ +# Testing + +Please refer to [the community cookbook documentation on testing](https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/TESTING.MD). diff --git a/chefignore b/chefignore index a6de142..cc170ea 100644 --- a/chefignore +++ b/chefignore @@ -1,69 +1,85 @@ # Put files/directories that should be ignored in this file when uploading -# or sharing to the community site. +# to a Chef Infra Server or Supermarket. # Lines that start with '# ' are comments. # OS generated files # ###################### .DS_Store +ehthumbs.db Icon? nohup.out -ehthumbs.db Thumbs.db - -# SASS # -######## -.sass-cache +.envrc # EDITORS # ########### -\#* .#* -*~ -*.sw[a-z] +.project +.settings +*_flymake +*_flymake.* *.bak +*.sw[a-z] +*.tmproj +*~ +\#* REVISION TAGS* tmtags -*_flymake.* -*_flymake -*.tmproj -.project -.settings -mkmf.log +.vscode +.editorconfig ## COMPILED ## ############## -a.out -*.o -*.pyc -*.so -*.com *.class +*.com *.dll *.exe +*.o +*.pyc +*.so */rdoc/ +a.out +mkmf.log # Testing # ########### -.watchr +.circleci/* +.codeclimate.yml +.delivery/* +.foodcritic +.kitchen* +.mdlrc +.overcommit.yml .rspec -spec/* -spec/fixtures/* -test/* +.rubocop.yml +.travis.yml +.watchr +.yamllint +azure-pipelines.yml +Dangerfile +examples/* features/* Guardfile +kitchen.yml* +mlc_config.json Procfile +Rakefile +spec/* +test/* # SCM # ####### .git -*/.git +.gitattributes +.gitconfig +.github/* .gitignore +.gitkeep .gitmodules -.gitconfig -.gitattributes .svn */.bzr/* +*/.git */.hg/* */.svn/* @@ -74,23 +90,26 @@ Berksfile.lock cookbooks/* tmp -# Cookbooks # -############# -CONTRIBUTING -CHANGELOG* +# Bundler # +########### +vendor/* +Gemfile +Gemfile.lock + +# Policyfile # +############## +Policyfile.rb +Policyfile.lock.json -# Strainer # -############ -Colanderfile -Strainerfile -.colander -.strainer +# Documentation # +############# +CODE_OF_CONDUCT* +CONTRIBUTING* +documentation/* +TESTING* +UPGRADING* # Vagrant # ########### .vagrant Vagrantfile - -# Travis # -########## -.travis.yml diff --git a/documentation/.gitkeep b/documentation/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/documentation/archive.md b/documentation/archive.md new file mode 100644 index 0000000..540262e --- /dev/null +++ b/documentation/archive.md @@ -0,0 +1,39 @@ +[Back to resource list](../README.md#resources) + +# github_archive + +Downloads and extracts an archive from a Github repository + +## Actions + +| Action | Description | +| ---------- | ---------------------------------------------------------- | +| `:extract` | Downloads and extracts an archive from a Github repository | +| `:delete` | Deletes an extracted archive from a Github repository | + +## Properties + +| Name | Type | Default | Description | +| -------------- | --------------- | -------------------- | ---------------------------------------- | +| `repo` | String | Resource name | Repository org and name | +| `version` | String | `master` | Git ref (branch, tag, etc) | +| `github_user` | String | | Github user for authentication | +| `github_token` | String | | Github token for authentication | +| `host` | String | `https://github.com` | Github endpoint host | +| `owner` | String | | Owner for extracted archive | +| `group` | String | | Group for extracted archive | +| `extract_to` | String | | Path to extract archive to (required) | +| `force` | `true`, `false` | `false` | Force downloading and extracting archive | + +## Examples + +```ruby +github_archive 'elixir-lang/elixir' do + extract_to '/tmp/test' +end + +github_archive 'elixir-lang/elixir' do + extract_to '/tmp/test' + action :delete +end +``` diff --git a/documentation/asset.md b/documentation/asset.md new file mode 100644 index 0000000..5ee73fa --- /dev/null +++ b/documentation/asset.md @@ -0,0 +1,40 @@ +[Back to resource list](../README.md#resources) + +# github_asset + +Downloads an asset from a Github repository + +## Actions + +| Action | Description | +| ----------- | ---------------------------------------------- | +| `:download` | Downloads an asset from a Github repository | +| `:delete` | Deletes a local asset from a Github repository | + +## Properties + +| Name | Type | Default | Description | +| -------------- | --------------- | ------------- | ---------------------------------------- | +| `file` | String | Resource name | File name of the asset | +| `release` | String | | Release name of the asset (required) | +| `repo` | String | | Repository org and name | +| `github_user` | String | | Github user for authentication | +| `github_token` | String | | Github token for authentication | +| `owner` | String | | Owner for extracted archive | +| `group` | String | | Group for extracted archive | +| `force` | `true`, `false` | `false` | Force downloading and extracting archive | + +## Examples + +```ruby +github_asset 'Precompiled.zip' do + repo 'elixir-lang/elixir' + release 'v1.12.2' +end + +github_asset 'Precompiled.zip' do + repo 'elixir-lang/elixir' + release 'v1.12.2' + action :delete +end +``` diff --git a/documentation/deploy.md b/documentation/deploy.md new file mode 100644 index 0000000..e1a840b --- /dev/null +++ b/documentation/deploy.md @@ -0,0 +1,39 @@ +[Back to resource list](../README.md#resources) + +# github_deploy + +Downloads an asset from a Github repository and then deploys it as an application + +## Actions + +| Action | Description | +| --------- | --------------------------------------------------------------- | +| `:deploy` | Downloads an asset from a Github repository and then deploys it | + +## Properties + +| Name | Type | Default | Description | +| -------------------- | --------------- | -------------------- | ------------------------------------------- | +| `repo` | String | Resource name | Repository org and name | +| `version` | String | | Git ref (branch, tag, etc) (required) | +| `github_user` | String | | Github user for authentication | +| `github_token` | String | | Github token for authentication | +| `host` | String | `https://github.com` | Github endpoint host | +| `path` | String | | Path to deploy the application | +| `owner` | String | | Owner for extracted archive | +| `group` | String | | Group for extracted archive | +| `shared_directories` | Array | `['pids', 'logs']` | Shared directories to create an symlink | +| `configure` | Proc | | Block of code to run in a configure phase | +| `before_migrate` | Proc | | Block of code to run before migration phase | +| `after_migrate` | Proc | | Block of code to run after migration phase | +| `migrate` | Proc | | Block of code to run during migration phase | +| `force` | `true`, `false` | `false` | Force downloading and extracting archive | + +## Examples + +```ruby +github_deploy 'elixir-lang/elixir' do + version 'v1.12' + path '/tmp/deploy' +end +``` diff --git a/kitchen.dokken.yml b/kitchen.dokken.yml new file mode 100644 index 0000000..2c23c30 --- /dev/null +++ b/kitchen.dokken.yml @@ -0,0 +1,23 @@ +driver: + name: dokken + privileged: true # because Docker and SystemD + chef_version: <%= ENV['CHEF_VERSION'] || 'current' %> + chef_license: accept-no-persist + +transport: + name: dokken + +provisioner: + name: dokken + deprecations_as_errors: true + +verifier: + name: inspec + +platforms: + - name: ubuntu-20.04 + driver: + image: dokken/ubuntu-20.04 + pid_one_command: /bin/systemd + intermediate_instructions: + - RUN /usr/bin/apt-get update diff --git a/kitchen.yml b/kitchen.yml new file mode 100644 index 0000000..120aea4 --- /dev/null +++ b/kitchen.yml @@ -0,0 +1,21 @@ +driver: + name: vagrant + +provisioner: + name: chef_infra + product_name: chef + enforce_idempotency: true + multiple_converge: 2 + deprecations_as_errors: true + chef_license: accept-no-persist + +verifier: + name: inspec + +platforms: + - name: ubuntu-20.04 + +suites: + - name: default + run_list: + - recipe[test] diff --git a/libraries/github_archive.rb b/libraries/github_archive.rb index c2fd403..09f1d78 100644 --- a/libraries/github_archive.rb +++ b/libraries/github_archive.rb @@ -35,7 +35,7 @@ def download(options = {}) FileUtils.mkdir_p(File.dirname(local_archive_path)) file = ::File.open(local_archive_path, 'wb') - open(download_uri, http_basic_authentication: [options[:user], options[:token]]) do |source| + URI.open(download_uri, http_basic_authentication: [options[:user], options[:token]]) do |source| IO.copy_stream(source, file) end rescue OpenURI::HTTPError => ex @@ -53,34 +53,10 @@ def downloaded? File.exist?(local_archive_path) end - # @param [String] target - # - # @option options [String] :owner - # @option options [String] :group - def extract(target, options = {}) - require 'archive' - - if options[:force] - FileUtils.rm_rf(target) - end - - Dir.mktmpdir do |tmpdir| - Dir.chdir(tmpdir) do - ::Archive.new(local_archive_path).extract - end - - FileUtils.mkdir_p(target) - File.rename(Dir.glob("#{tmpdir}/**").first, target) - end - - if options[:owner] || options[:group] - FileUtils.chown_R(options[:owner], options[:group], target) - end - end - def local_archive_path File.join(archive_cache_path, "#{repo}-#{version}.tar.gz") end + alias_method :path, :local_archive_path private @@ -91,7 +67,7 @@ def archive_cache_path def download_uri uri = URI.parse(host) - uri.path = "/#{fqrn}/archive/#{URI.encode(version)}.tar.gz" + uri.path = "/#{fqrn}/archive/#{URI.encode_www_form_component(version)}.tar.gz" uri end end diff --git a/libraries/github_asset.rb b/libraries/github_asset.rb index ca8478a..0dd2fee 100644 --- a/libraries/github_asset.rb +++ b/libraries/github_asset.rb @@ -84,7 +84,7 @@ def download(options = {}) FileUtils.mkdir_p(::File.dirname(options[:path])) file = ::File.open(options[:path], 'wb') - open(res['location']) { |source| IO.copy_stream(source, file) } + URI.open(res['location']) { |source| IO.copy_stream(source, file) } true rescue OpenURI::HTTPError => ex case ex.message diff --git a/metadata.rb b/metadata.rb index 526a523..e40031f 100644 --- a/metadata.rb +++ b/metadata.rb @@ -1,10 +1,24 @@ -name 'github' -maintainer 'Sous-Chefs' -maintainer_email 'help@sous-chefs.org' -license 'Apache-2.0' -description 'A Library Cookbook for interacting with the Github API' -version '0.3.2' -chef_version '>= 15.3' +name 'github' +maintainer 'Sous Chefs' +maintainer_email 'help@sous-chefs.org' +license 'Apache-2.0' +description 'A Library Cookbook for interacting with the Github API' +version '0.3.2' +source_url 'https://github.com/sous-chefs/github' +issues_url 'https://github.com/sous-chefs/github/issues' +chef_version '>= 15.3' +supports 'amazon' +supports 'centos' +supports 'debian' +supports 'freebsd' +supports 'mac_os_x' +supports 'opensuse' +supports 'opensuseleap' +supports 'oracle' +supports 'redhat' +supports 'scientific' +supports 'smartos' +supports 'suse' supports 'ubuntu' -depends 'libarchive' +supports 'windows' diff --git a/providers/archive.rb b/providers/archive.rb deleted file mode 100644 index fae72c4..0000000 --- a/providers/archive.rb +++ /dev/null @@ -1,36 +0,0 @@ -attr_reader :archive - -def load_current_resource - @archive = GithubCB::Archive.new(new_resource.repo, version: new_resource.version, host: new_resource.host) -end - -action :extract do - recipe_eval do - run_context.include_recipe 'libarchive::default' - end - - unless !new_resource.force || archive.downloaded? - Chef::Log.info "github_archive[#{new_resource.name}] downloading archive" - archive.download(user: new_resource.github_user, token: new_resource.github_token, - force: new_resource.force) - new_resource.updated_by_last_action(true) - end - - unless !new_resource.force || ::File.exist?(new_resource.extract_to) - Chef::Log.info "github_archive[#{new_resource.name}] extracting archive to #{new_resource.extract_to}" - archive.extract(new_resource.extract_to, force: new_resource.force, - owner: new_resource.owner, group: new_resource.group) - new_resource.updated_by_last_action(true) - end -end - -action :delete do - file @archive.path do - action :delete - end - - directory new_resource.extract_to do - recursive true - action :delete - end -end diff --git a/providers/asset.rb b/providers/asset.rb deleted file mode 100644 index 2816a44..0000000 --- a/providers/asset.rb +++ /dev/null @@ -1,28 +0,0 @@ -attr_reader :asset - -def load_current_resource - @asset = GithubCB::Asset.new(new_resource.repo, name: new_resource.name, - release: new_resource.release) -end - -action :download do - chef_gem 'octokit' do - compile_time true - end - - Chef::Log.info "github_asset[#{new_resource.name}] downloading asset" - updated = asset.download(user: new_resource.github_user, token: new_resource.github_token, - force: new_resource.force, path: new_resource.asset_path) - new_resource.updated_by_last_action(updated) -end - -action :delete do - file @asset.asset_path do - action :delete - end - - directory new_resource.extract_to do - recursive true - action :delete - end -end diff --git a/providers/deploy.rb b/providers/deploy.rb deleted file mode 100644 index 0f60f22..0000000 --- a/providers/deploy.rb +++ /dev/null @@ -1,84 +0,0 @@ -action :deploy do - [ new_resource.release_path, new_resource.shared_path ].each do |path| - directory path do - owner new_resource.owner - group new_resource.group - mode '770' - recursive true - end - end - - new_resource.shared_directories.each do |path| - directory "#{new_resource.shared_path}/#{path}" do - owner new_resource.owner - group new_resource.group - mode '770' - recursive true - end - end - - github_archive new_resource.repo do - @should_force = new_resource.version == 'master' || new_resource.force - - version new_resource.version - github_user new_resource.github_user - github_token new_resource.github_token - host new_resource.host - extract_to new_resource.deploy_path - force @should_force - - if @should_force - action [ :delete, :extract ] - else - action :extract - end - end - - ruby_block 'configure' do - block do - if new_resource.configure - Chef::Log.info "github_deploy[#{new_resource.name}] Running configure proc" - recipe_eval(&new_resource.configure.to_proc) - end - end - end - - ruby_block 'before-migrate' do - block do - if new_resource.before_migrate - Chef::Log.info "github_deploy[#{new_resource.name}] Running before migrate proc" - recipe_eval(&new_resource.before_migrate.to_proc) - end - end - end - - ruby_block 'migrate' do - block do - if new_resource.migrate - Chef::Log.info "github_deploy[#{new_resource.name}] Running migrate proc" - recipe_eval(&new_resource.migrate.to_proc) - end - end - end - - ruby_block 'after-migrate' do - block do - if new_resource.after_migrate - Chef::Log.info "github_deploy[#{new_resource.name}] Running after migrate proc" - recipe_eval(&new_resource.after_migrate.to_proc) - end - end - end - - link current_path do - to new_resource.deploy_path - owner new_resource.owner - group new_resource.group - end -end - -private - -def current_path - ::File.join(new_resource.path, 'current') -end diff --git a/resources/archive.rb b/resources/archive.rb index 6dafd32..9196b20 100644 --- a/resources/archive.rb +++ b/resources/archive.rb @@ -1,13 +1,53 @@ -unified_mode false -actions :extract, :delete +unified_mode true + default_action :extract -attribute :repo, kind_of: String, name_attribute: true -attribute :version, kind_of: String, default: 'master' -attribute :github_user, kind_of: String -attribute :github_token, kind_of: String -attribute :host, kind_of: String -attribute :owner, kind_of: String -attribute :group, kind_of: String -attribute :extract_to, kind_of: String, required: true -attribute :force, kind_of: [TrueClass, FalseClass], default: false +property :repo, String, name_property: true +property :version, String, default: 'master' +property :github_user, String +property :github_token, String +property :host, String +property :owner, String +property :group, String +property :extract_to, String, required: true +property :force, [true, false], default: false + +action :extract do + unless new_resource.force || archive.downloaded? + converge_by "downloading archive #{new_resource.name} to #{archive.path}" do + archive.download( + user: new_resource.github_user, + token: new_resource.github_token, + force: new_resource.force + ) + end + end + + unless new_resource.force || ::File.exist?(new_resource.extract_to) + converge_by "extracting archive #{archive.path} to #{new_resource.extract_to}" do + archive_file archive.path do + destination new_resource.extract_to + overwrite new_resource.force + owner new_resource.owner + group new_resource.group + end + end + end +end + +action :delete do + file archive.path do + action :delete + end + + directory new_resource.extract_to do + recursive true + action :delete + end +end + +action_class do + def archive + GithubCB::Archive.new(new_resource.repo, version: new_resource.version, host: new_resource.host) + end +end diff --git a/resources/asset.rb b/resources/asset.rb index 7f87d27..d151529 100644 --- a/resources/asset.rb +++ b/resources/asset.rb @@ -1,15 +1,50 @@ -actions :download, :delete +unified_mode true + default_action :download -unified_mode false - -attribute :release, kind_of: String, required: true -attribute :repo, kind_of: String, required: true -attribute :github_user, kind_of: String -attribute :github_token, kind_of: String -attribute :owner, kind_of: String -attribute :group, kind_of: String -attribute :force, kind_of: [TrueClass, FalseClass], default: false - -def asset_path - GithubCB::Asset.asset_path(@repo, @release, @name) + +property :file, String, name_property: true +property :release, String, required: true +property :repo, String, required: true +property :github_user, String +property :github_token, String +property :owner, String +property :group, String +property :force, [true, false], default: false + +action :download do + chef_gem 'octokit' do + compile_time true + end + + unless asset.downloaded?(asset_path) + converge_by "downloading #{new_resource.file} to #{asset_path}" do + asset.download( + user: new_resource.github_user, + token: new_resource.github_token, + force: new_resource.force, + path: asset_path + ) + end + end +end + +action :delete do + file asset_path do + action :delete + end + + directory ::File.dirname(asset_path) do + recursive true + action :delete + end +end + +action_class do + def asset + GithubCB::Asset.new(new_resource.repo, name: new_resource.file, release: new_resource.release) + end + + def asset_path + GithubCB::Asset.asset_path(new_resource.repo, new_resource.release, new_resource.file) + end end diff --git a/resources/deploy.rb b/resources/deploy.rb index ab60289..1b90eb0 100644 --- a/resources/deploy.rb +++ b/resources/deploy.rb @@ -1,31 +1,124 @@ -unified_mode false -actions :deploy +unified_mode true + default_action :deploy -attribute :repo, kind_of: String, name_attribute: true -attribute :version, kind_of: String, required: true -attribute :github_user, kind_of: String -attribute :github_token, kind_of: String -attribute :host, kind_of: String -attribute :path, kind_of: String, required: true -attribute :owner, kind_of: String -attribute :group, kind_of: String -attribute :shared_directories, kind_of: Array, default: %w(pids log) -attribute :force, kind_of: [TrueClass, FalseClass], default: false - -attribute :configure, kind_of: Proc -attribute :before_migrate, kind_of: Proc -attribute :after_migrate, kind_of: Proc -attribute :migrate, kind_of: Proc - -def deploy_path - ::File.join(release_path, version) -end +property :repo, String, name_property: true +property :version, String, required: true +property :github_user, String +property :github_token, String +property :host, String +property :path, String, required: true +property :owner, String +property :group, String +property :shared_directories, Array, default: %w(pids log) +property :force, [true, false], default: false + +property :configure, Proc +property :before_migrate, Proc +property :after_migrate, Proc +property :migrate, Proc + +action_class do + def deploy_path + ::File.join(release_path, new_resource.version) + end -def release_path - ::File.join(path, 'releases') + def release_path + ::File.join(new_resource.path, 'releases') + end + + def shared_path + ::File.join(new_resource.path, 'shared') + end + + def current_path + ::File.join(new_resource.path, 'current') + end end -def shared_path - ::File.join(path, 'shared') +action :deploy do + [ release_path, shared_path ].each do |path| + directory path do + owner new_resource.owner + group new_resource.group + mode '770' + recursive true + end + end + + new_resource.shared_directories.each do |path| + directory "#{shared_path}/#{path}" do + owner new_resource.owner + group new_resource.group + mode '770' + recursive true + end + end + + github_archive new_resource.repo do + should_force = new_resource.version == 'master' || new_resource.force + + version new_resource.version + github_user new_resource.github_user + github_token new_resource.github_token + host new_resource.host + extract_to deploy_path + force should_force + + if should_force + action [ :delete, :extract ] + else + action :extract + end + notifies :run, 'ruby_block[configure]' + notifies :run, 'ruby_block[before-migrate]' + notifies :run, 'ruby_block[migrate]' + notifies :run, 'ruby_block[after-migrate]' + end + + ruby_block 'configure' do + block do + if new_resource.configure + Chef::Log.info "github_deploy[#{new_resource.name}] Running configure proc" + recipe_eval(&new_resource.configure.to_proc) + end + end + action :nothing + end + + ruby_block 'before-migrate' do + block do + if new_resource.before_migrate + Chef::Log.info "github_deploy[#{new_resource.name}] Running before migrate proc" + recipe_eval(&new_resource.before_migrate.to_proc) + end + end + action :nothing + end + + ruby_block 'migrate' do + block do + if new_resource.migrate + Chef::Log.info "github_deploy[#{new_resource.name}] Running migrate proc" + recipe_eval(&new_resource.migrate.to_proc) + end + end + action :nothing + end + + ruby_block 'after-migrate' do + block do + if new_resource.after_migrate + Chef::Log.info "github_deploy[#{new_resource.name}] Running after migrate proc" + recipe_eval(&new_resource.after_migrate.to_proc) + end + end + action :nothing + end + + link current_path do + to deploy_path + owner new_resource.owner + group new_resource.group + end end diff --git a/spec/libraries/github_archive_spec.rb b/spec/libraries/github_archive_spec.rb index 4617fb3..ecc8e73 100644 --- a/spec/libraries/github_archive_spec.rb +++ b/spec/libraries/github_archive_spec.rb @@ -1,69 +1,69 @@ -require 'spec_helper' - -describe GithubCB::Archive do - describe 'ClassMethods' do - describe '::new' do - let(:fqrn) { 'berkshelf/berkshelf-cookbook' } - let(:options) { {} } - subject { described_class.new(fqrn, options) } - - its(:organization) { should eq('berkshelf') } - its(:repo) { should eq('berkshelf-cookbook') } - its(:host) { should eq('https://github.com') } - its(:version) { should eq('master') } - - context 'given an explicit host' do - let(:host) { 'https://github.vialstudios.com' } - before { options[:host] = host } - - its(:host) { should eq(host) } - end - - context 'given an explicit version' do - let(:version) { '1.2.3' } - before { options[:version] = version } - - its(:version) { should eq(version) } - end - end - end - - subject { described_class.new('berkshelf/berkshelf-cookbook') } - - describe '#download' do - before { subject.download } - - it 'creates downloads the archive into the chef cache' do - target = File.join(Chef::Config[:file_cache_path], - 'github_deploy', 'archives', 'berkshelf-cookbook-master.tar.gz') - - expect(File.exist?(target)).to be_true - end - end - - describe '#downloaded?' do - context 'when the archive is present on disk' do - before { subject.download } - - it 'returns true' do - expect(subject.downloaded?).to be_true - end - end - - context 'when it is not present on disk' do - it 'returns false' do - expect(subject.downloaded?).to be_false - end - end - end - - describe '#extract' do - before { subject.download } - let(:target) { File.join(tmp_path, 'berkshelf-extract') } - - it 'extracts the contents of the archive into the target directory' do - subject.extract(target) - expect(File.exist?(File.join(target, 'metadata.rb'))).to be_true - end - end -end +# require 'spec_helper' +# +# describe GithubCB::Archive do +# describe 'ClassMethods' do +# describe '::new' do +# let(:fqrn) { 'berkshelf/berkshelf-cookbook' } +# let(:options) { {} } +# subject { described_class.new(fqrn, options) } +# +# its(:organization) { should eq('berkshelf') } +# its(:repo) { should eq('berkshelf-cookbook') } +# its(:host) { should eq('https://github.com') } +# its(:version) { should eq('master') } +# +# context 'given an explicit host' do +# let(:host) { 'https://github.vialstudios.com' } +# before { options[:host] = host } +# +# its(:host) { should eq(host) } +# end +# +# context 'given an explicit version' do +# let(:version) { '1.2.3' } +# before { options[:version] = version } +# +# its(:version) { should eq(version) } +# end +# end +# end +# +# subject { described_class.new('berkshelf/berkshelf-cookbook') } +# +# describe '#download' do +# before { subject.download } +# +# it 'creates downloads the archive into the chef cache' do +# target = File.join(Chef::Config[:file_cache_path], +# 'github_deploy', 'archives', 'berkshelf-cookbook-master.tar.gz') +# +# expect(File.exist?(target)).to be_true +# end +# end +# +# describe '#downloaded?' do +# context 'when the archive is present on disk' do +# before { subject.download } +# +# it 'returns true' do +# expect(subject.downloaded?).to be_true +# end +# end +# +# context 'when it is not present on disk' do +# it 'returns false' do +# expect(subject.downloaded?).to be_false +# end +# end +# end +# +# describe '#extract' do +# before { subject.download } +# let(:target) { File.join(tmp_path, 'berkshelf-extract') } +# +# it 'extracts the contents of the archive into the target directory' do +# subject.extract(target) +# expect(File.exist?(File.join(target, 'metadata.rb'))).to be_true +# end +# end +# end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 64c3057..8b0212c 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,37 +1,37 @@ -require 'rubygems' -require 'bundler' -require 'rspec' -require 'spork' -require 'chef' - -Spork.prefork do - Dir[File.join(File.expand_path('../spec/support/**/*.rb', __dir__))].each { |f| require f } - - RSpec.configure do |config| - config.expect_with :rspec do |c| - c.syntax = :expect - end - - config.mock_with :rspec - config.treat_symbols_as_metadata_keys_with_true_values = true - config.filter_run focus: true - config.run_all_when_everything_filtered = true - - config.before(:each) do - Chef::Config[:file_cache_path] = File.join(tmp_path, 'chef_cache') - FileUtils.rm_rf(tmp_path) - FileUtils.mkdir_p(tmp_path) - FileUtils.mkdir_p(Chef::Config[:file_cache_path]) - end - end - - def tmp_path - File.expand_path(File.join(File.dirname(__FILE__), '../tmp')) - end -end - -Spork.each_run do - Dir["#{File.expand_path('..', File.dirname(__FILE__))}/libraries/*.rb"].sort.each do |path| - require_relative "../libraries/#{File.basename(path, '.rb')}" - end -end +# require 'rubygems' +# require 'bundler' +# require 'rspec' +# require 'spork' +# require 'chef' +# +# Spork.prefork do +# Dir[File.join(File.expand_path('../spec/support/**/*.rb', __dir__))].each { |f| require f } +# +# RSpec.configure do |config| +# config.expect_with :rspec do |c| +# c.syntax = :expect +# end +# +# config.mock_with :rspec +# config.treat_symbols_as_metadata_keys_with_true_values = true +# config.filter_run focus: true +# config.run_all_when_everything_filtered = true +# +# config.before(:each) do +# Chef::Config[:file_cache_path] = File.join(tmp_path, 'chef_cache') +# FileUtils.rm_rf(tmp_path) +# FileUtils.mkdir_p(tmp_path) +# FileUtils.mkdir_p(Chef::Config[:file_cache_path]) +# end +# end +# +# def tmp_path +# File.expand_path(File.join(File.dirname(__FILE__), '../tmp')) +# end +# end +# +# Spork.each_run do +# Dir["#{File.expand_path('..', File.dirname(__FILE__))}/libraries/*.rb"].sort.each do |path| +# require_relative "../libraries/#{File.basename(path, '.rb')}" +# end +# end diff --git a/test/fixtures/cookbooks/test/metadata.rb b/test/fixtures/cookbooks/test/metadata.rb new file mode 100644 index 0000000..691cb42 --- /dev/null +++ b/test/fixtures/cookbooks/test/metadata.rb @@ -0,0 +1,7 @@ +name 'test' +maintainer 'Sous Chefs' +maintainer_email 'help@sous-chefs.org' +license 'Apache-2.0' +description 'Testing cookbook' +version '0.0.1' +depends 'github' diff --git a/test/fixtures/cookbooks/test/recipes/default.rb b/test/fixtures/cookbooks/test/recipes/default.rb new file mode 100644 index 0000000..a034201 --- /dev/null +++ b/test/fixtures/cookbooks/test/recipes/default.rb @@ -0,0 +1,27 @@ +github_asset 'Precompiled.zip' do + repo 'elixir-lang/elixir' + release 'v1.12.2' +end + +github_asset 'Precompiled.zip-delete' do + file 'Precompiled.zip' + repo 'elixir-lang/elixir' + release 'v1.12.1' + action :delete +end + +github_archive 'elixir-lang/elixir' do + extract_to '/tmp/test' +end + +github_archive 'elixir-lang/elixir-delete' do + repo 'elixir-lang/elixir' + version 'delete' + extract_to '/tmp/delete' + action :delete +end + +github_deploy 'elixir-lang/elixir' do + version 'v1.12' + path '/tmp/deploy' +end diff --git a/test/integration/default/controls/default.rb b/test/integration/default/controls/default.rb new file mode 100644 index 0000000..b4a7941 --- /dev/null +++ b/test/integration/default/controls/default.rb @@ -0,0 +1,54 @@ +cache_dir = inspec.file('/opt/kitchen').exist? ? '/opt/kitchen/cache' : '/tmp/kitchen/cache' + +control 'github-cookbook' do + [ + "#{cache_dir}/github_assets/elixir-lang/elixir/v1.12.2/Precompiled.zip", + "#{cache_dir}/github_deploy/archives/elixir-master.tar.gz", + "#{cache_dir}/github_deploy/archives/elixir-v1.12.tar.gz", + '/tmp/test/elixir-master/README.md', + '/tmp/deploy/releases/v1.12/elixir-1.12/README.md', + ].each do |f| + describe file f do + it { should exist } + its('size') { should > 0 } + end + end + + [ + "#{cache_dir}/github_assets/elixir-lang/elixir/v1.12.1/Precompiled.zip", + "#{cache_dir}/github_deploy/archives/elixir-delete.tar.gz", + ].each do |f| + describe file f do + it { should_not exist } + end + end + + %w( + /tmp/test + /tmp/deploy/releases/v1.12 + ).each do |d| + describe directory d do + it { should exist } + end + end + + describe directory '/tmp/delete' do + it { should_not exist } + end + + %w( + /tmp/deploy/releases + /tmp/deploy/shared + /tmp/deploy/shared/pids + /tmp/deploy/shared/log + ).each do |d| + describe directory d do + it { should exist } + its('mode') { should cmp '0770' } + end + end + + describe file '/tmp/deploy/current' do + its('link_path') { should eq '/tmp/deploy/releases/v1.12' } + end +end diff --git a/test/integration/default/inspec.yml b/test/integration/default/inspec.yml new file mode 100644 index 0000000..e5a69ef --- /dev/null +++ b/test/integration/default/inspec.yml @@ -0,0 +1 @@ +name: github-cookbook