Giter Site home page Giter Site logo

halite's Introduction

Halite

Build Status Gem Version Coverage Gemnasium License

Write as a gem, release as a cookbook.

Quick Start

Create a gem as per normal and add a dependency on halite. Add require 'halite/rake_tasks' to your Rakefile. Run rake build and the converted cookbook will be written to pkg/.

All Ruby code in the gem will be converted in to libraries/ files. You can add cookbook-specific files by add them to a chef/ folder in the root of the gem.

Why?

Developing cookbooks as gems allows using the full Ruby development ecosystem and tooling more directly. This includes things like Simplecov for coverage testing, YARD for documentation, and Gemnasium for dependency monitoring. For a cookbook that is already mostly library files, this is a natural transition, with few cookbook-specific pieces to start with. This also allows using Bundler to manage versions instead of Berkshelf.

Cookbook Dependencies

To add cookbook dependencies either add them to the gem requirements or use the halite_dependencies metadata field:

Gem::Specification.new do |spec|
  spec.requirements = %w{apache2 mysql}
  # or
  spec.metadata['halite_dependencies'] = 'php >= 2.0.0, chef-client'
end

Additionally if you gem depends on other Halite-based gems those will automatically converted to cookbook dependencies.

Cookbook Files

Any files under chef/ in the gem will be written as is in to the cookbook. For example you can add a recipe to your gem via chef/recipes/default.rb.

Chef Version

By default cookbooks will be generated with chef_version '~> 12' to require Chef 12.x. This can be overridden using the halite_chef_version metadata field:

Gem::Specification.new do |spec|
  spec.metadata['halite_chef_version'] = '>= 12.0.0'
end

Rake Tasks

The halite/rake_tasks module provides quick defaults. Gem name will be auto-detected from the .gemspec file and the cookbook name will be based on the gem name.

rake build

The build command will convert the gem to a cookbook and write it to the pkg/ folder.

Advanced Usage

You can also pass custom arguments to the Rake tasks. All parameters are optional:

require 'halite/rake_helper'
Halite::RakeHelper.install(
  gem_name: 'name', # Name of the gem to convert
  base: File.basename(__FILE__), # Base folder for the gem
)

Berkshelf Extension

Halite includes a Berkshelf extension to pull in any gem-based cookbooks that are available on the system.

To activate it, include the extension in your Berksfile:

extension 'halite'

Spec Helper

Halite includes a set of helpers for RSpec tests. You can enable them in your spec_helper.rb:

require 'halite/spec_helper'

RSpec.configure do |config|
  config.include Halite::SpecHelper
end

recipe

Recipes to converge for the test can be defined inline on example groups:

describe 'cookbook recipe' do
  recipe 'myrecipe'
  it { is_expected.to create_file('/myfile') }
end

describe 'inline recipe' do
  recipe do
    file '/myfile' do
      content 'mycontent'
    end
  end
  it { is_expected.to create_file('/myfile') }
end

step_into

A resource can be added to the list to step in to via the step_into helper:

describe 'mycookbook' do
  recipe 'mycookbook::server'
  step_into :mycookbook_lwrp
  it { is_expected.to ... }
end

resource and provider

For testing mixin-based cookbooks, new resource and provider classes can be declared on an example group:

describe MyMixin do
  resource(:test_resource) do
    include MyMixin
    def foo(val=nil)
      set_or_return(:foo, val, {})
    end
  end
  provider(:test_resource) do
    def action_run
      # ...
    end
  end
  recipe do
    test_resource 'test' do
      foo 1
      action :run
    end
  end
  it { is_expected.to ... }
end

These helper resources and providers are only available within the scope of recipes defined on that example group or groups nested inside it. Helper resources are automatically step_into'd.

Using a Pre-release Version of a Cookbook

When a Halite-based cookbook is released, a converted copy is generally uploaded to the Supermarket. To use unreleased versions, you need to pull in the code from git via bundler and then tell the Berkshelf extension to convert it for you.

To grab the pre-release gem, add a line like the following to your Gemfile:

gem 'poise-application', github: 'poise/application'

You will need one gem line for each Halite-based cookbook you want to use, possibly including dependencies if you want to use pre-release versions of those as well.

Next you need to use Berkshelf to convert the gem to its cookbook form:

source 'https://supermarket.chef.io/'
extension 'halite'
cookbook 'application', gem: 'poise-application'

Again you will need one cookbook line per Halite based cookbook you want to use. Also make sure to check the correct names for the gem and cookbook, they may not be the same though for other Poise cookbooks they generally follow the same pattern.

If you are using something that integrates with Berkshelf like Test-Kitchen or ChefSpec, this is all you need to do. You could use berks upload to push a converted copy of all cookbooks to a Chef Server, though running pre-release code in production should be done with great care.

License

Copyright 2015, Noah Kantrowitz

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.

halite's People

Contributors

coderanger avatar lamont-granquist avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

halite's Issues

README.md Chef Version Errata

I believe this example in README.md should be changed from spec.metadata[halite_dependencies] to spec.metadata[halite_chef_version]

Original:

Chef Version

By default cookbooks will be generated with chef_version '~> 12' to require
Chef 12.x. This can be overridden using the halite_chef_version metadata field:

Gem::Specification.new do |spec|
  spec.metadata['halite_dependencies'] = '>= 12.0.0'
end

Modified:

Chef Version

By default cookbooks will be generated with chef_version '~> 12' to require
Chef 12.x. This can be overridden using the halite_chef_version metadata field:

Gem::Specification.new do |spec|
  spec.metadata['halite_chef_version'] = '>= 12.0.0'
end

Feature Request: Support platform options for ChefSpec integration

As a Halite Gem / Poise Resource Author, I would like to create a Halite Library Gem with a Resource that is specific to a Platform or Platform Version, and use the Halite ChefSpec integration to test it.

Currently, within a poise-based resource, if I specify additional options on my resource for a specific platform, e.g.:

module MyResource
  class Resource < Chef::Resource
    include Poise
    provides(:my_resource, os: 'windows')
    actions(:install)
  end
end

and later attempt to chefspec test it within the same gem:

describe MyResource::Resource do
  describe ':install' do
    context 'on windows server 2012R2' do
      recipe do
        my_resource 'myresource' do
          action :install
        end
      end

      let(:chefspec_options) { {platform: 'windows', version: '2012R2'} }

      step_into :my_resource

      it 'converges successfully' do
        expect{ chef_run }.not_to raise_error
      end

      it { is_expected.to install_my_resource('myresource') }
    end
  end
end

the resource is not found (snippet)

/.bundle/ruby/2.3.0/gems/chef-12.17.44/lib/chef/resource.rb:1544:in `resource_for_node': Cannot find a resource for my_resource on  version  (Chef::Exceptions::NoSuchResourceType)
	from /.bundle/ruby/2.3.0/gems/halite-1.3.0/lib/halite/spec_helper.rb:200:in `step_into'

[bug] Doesn't work with chef 14.3 (its ruby version)

       Unpacking chef (14.3.37-1) ...
       Setting up chef (14.3.37-1) ...
       ================================================================================
       Recipe Compile Error in /tmp/kitchen/cache/cookbooks/poise-python/libraries/default.rb
       ================================================================================
       
       FrozenError
       -----------
       can't modify frozen Array
       
       Cookbook Trace:
       ---------------
         /tmp/kitchen/cache/cookbooks/poise/files/halite_gem/poise/helpers/subresources/container.rb:220:in `included'
         /tmp/kitchen/cache/cookbooks/poise/files/halite_gem/poise/resource.rb:51:in `include'
         /tmp/kitchen/cache/cookbooks/poise/files/halite_gem/poise/resource.rb:51:in `poise_subresource_container'
         /tmp/kitchen/cache/cookbooks/poise/files/halite_gem/poise.rb:93:in `block in Poise'
         /tmp/kitchen/cache/cookbooks/poise-python/files/halite_gem/poise_python/resources/python_runtime.rb:34:in `include'
         /tmp/kitchen/cache/cookbooks/poise-python/files/halite_gem/poise_python/resources/python_runtime.rb:34:in `<class:Resource>'
         /tmp/kitchen/cache/cookbooks/poise-python/files/halite_gem/poise_python/resources/python_runtime.rb:33:in `<module:PythonRuntime>'
         /tmp/kitchen/cache/cookbooks/poise-python/files/halite_gem/poise_python/resources/python_runtime.rb:25:in `<module:Resources>'
         /tmp/kitchen/cache/cookbooks/poise-python/files/halite_gem/poise_python/resources/python_runtime.rb:22:in `<module:PoisePython>'
         /tmp/kitchen/cache/cookbooks/poise-python/files/halite_gem/poise_python/resources/python_runtime.rb:21:in `<top (required)>'
         /tmp/kitchen/cache/cookbooks/poise-python/files/halite_gem/poise_python/resources.rb:19:in `<top (required)>'
         /tmp/kitchen/cache/cookbooks/poise-python/files/halite_gem/poise_python/cheftie.rb:17:in `<top (required)>'
         /tmp/kitchen/cache/cookbooks/poise-python/libraries/default.rb:6:in `<top (required)>'
       
       Relevant File Content:
       ----------------------
       /tmp/kitchen/cache/cookbooks/poise/files/halite_gem/poise/helpers/subresources/container.rb:
       
       213:                @container_default
       214:              end
       215:            end
       216:  
       217:            def included(klass)
       218:              super
       219:              klass.extend(ClassMethods)
       220>>             klass.const_get(:HIDDEN_IVARS) << :@subcontexts
       221:              klass.const_get(:FORBIDDEN_IVARS) << :@subcontexts
       222:            end
       223:          end
       224:  
       225:          extend ClassMethods
       226:        end
       227:      end
       228:    end
       229:  end

gems in metadata.rb

As it stands, it's unclear what the proper way is to propagate gem dependencies used for the cookbook from the gem itself into the generated cookbook.

e.g. in my gemspec I can require a gem:

spec.add_runtime_dependency 'my_org-my_utils'

and I can force it to a local path in the Gemfile:

gem 'my_org-my_utils', :path => '/Users/username/Documents/dev/local/my-org-util-gem'

However, this doesn't seem to pass that requirement into the cookbook that gets generated.

Chef supports a gem field for metadata.rb which will automatically use chef_gem to load gems.

However, it doesn't appear that I can append gem entries to the generated metadata.rb

So, what is the proper/recommended way of propagating these dependencies?

Halite fails to initialize with Berkshelf 6.1+

The initialize function for ::Berkshelf::Source now takes 2 parameters, but Halite::Berkshelf::Source only passes 1.

Locking the Berkshelf gem to ~> 6.0 is useable as a workaround.

The resulting error is:

ArgumentError:
  wrong number of arguments (given 1, expected 2)
# .../gems/halite-1.7.0/lib/halite/berkshelf/source.rb:33:in `initialize'
# .../gems/halite-1.7.0/lib/halite/berkshelf/helper.rb:52:in `new'
# .../gems/halite-1.7.0/lib/halite/berkshelf/helper.rb:52:in `block (2 levels) in install'

chefspec missing dependency

I'm requiring halite in my gemspec spec.add_runtime_dependency 'halite', '~> 1.8'

I've ran bundle install

I have a spec_helper generated with bundle gem

I've added require 'halite/spec_helper' and config.include Halite::SpecHelper

require "bundler/setup"
require "my_org/my_gem"
require 'halite/spec_helper'

RSpec.configure do |config|
  # Enable flags like --only-failures and --next-failure
  config.example_status_persistence_file_path = ".rspec_status"

  # Disable RSpec exposing methods globally on `Module` and `main`
  config.disable_monkey_patching!

  config.expect_with :rspec do |c|
    c.syntax = :expect
  end

  config.include Halite::SpecHelper
end

I've added require 'halite/rake_tasks' to my rakefile

When running rake from the project folder

/Users/username/.chefdk/gem/ruby/2.4.0/gems/halite-1.8.0/lib/halite/spec_helper.rb:18:in `require': cannot load such file -- chefspec (LoadError)
	from /Users/username/.chefdk/gem/ruby/2.4.0/gems/halite-1.8.0/lib/halite/spec_helper.rb:18:in `<top (required)>'

If I'm parsing this correctly then it appears that chefspec is not being specified as a dependency in the gemspec, and thus isn't getting installed by bundle install.

rake build fails when gem isn't installed

I'm working out of a halite gem my_org-example_cookbook and attempting to use rake build from the gem's source directory

It appears that it's attempting to get the spec for the gem from the local gem repo rather than the gemspec that's present in the current folder.

→ rake build
rake aborted!
Halite::Error: Cannot find a gem to satisfy my_org-example_cookbook (>= 0): Gem::MissingSpecError
/Users/username/.chefdk/gem/ruby/2.4.0/gems/halite-1.8.0/lib/halite/gem.rb:268:in `rescue in dependency_to_spec'
/Users/username/.chefdk/gem/ruby/2.4.0/gems/halite-1.8.0/lib/halite/gem.rb:264:in `dependency_to_spec'
/Users/username/.chefdk/gem/ruby/2.4.0/gems/halite-1.8.0/lib/halite/gem.rb:63:in `spec'
/Users/username/.chefdk/gem/ruby/2.4.0/gems/halite-1.8.0/lib/halite/gem.rb:58:in `initialize'
/Users/username/.chefdk/gem/ruby/2.4.0/gems/halite-1.8.0/lib/halite.rb:43:in `new'
/Users/username/.chefdk/gem/ruby/2.4.0/gems/halite-1.8.0/lib/halite.rb:43:in `convert'
/Users/username/.chefdk/gem/ruby/2.4.0/gems/halite-1.8.0/lib/halite/rake_helper.rb:127:in `build_cookbook'
/Users/username/.chefdk/gem/ruby/2.4.0/gems/halite-1.8.0/lib/halite/rake_helper.rb:43:in `block in install'

Caused by:
Gem::MissingSpecError: Could not find 'my_org-example_cookbook' (>= 0) among 269 total gem(s)
Checked in 'GEM_PATH=/Users/username/.chefdk/gem/ruby/2.4.0:/opt/chefdk/embedded/lib/ruby/gems/2.4.0', execute `gem env` for more information
/Users/username/.chefdk/gem/ruby/2.4.0/gems/halite-1.8.0/lib/halite/gem.rb:264:in `dependency_to_spec'
/Users/username/.chefdk/gem/ruby/2.4.0/gems/halite-1.8.0/lib/halite/gem.rb:63:in `spec'
/Users/username/.chefdk/gem/ruby/2.4.0/gems/halite-1.8.0/lib/halite/gem.rb:58:in `initialize'
/Users/username/.chefdk/gem/ruby/2.4.0/gems/halite-1.8.0/lib/halite.rb:43:in `new'
/Users/username/.chefdk/gem/ruby/2.4.0/gems/halite-1.8.0/lib/halite.rb:43:in `convert'
/Users/username/.chefdk/gem/ruby/2.4.0/gems/halite-1.8.0/lib/halite/rake_helper.rb:127:in `build_cookbook'
/Users/username/.chefdk/gem/ruby/2.4.0/gems/halite-1.8.0/lib/halite/rake_helper.rb:43:in `block in install'
Tasks: TOP => build => chef:build
(See full trace by running task with --trace)

when if I run a bundle info my_org-example_cookbook you can see that it's resolved

→ bundle info my_org-example_cookbook
Resolving dependencies...
  * my_org-example_cookbook (0.0.0)
	Summary: example cookbook
	Homepage: https://github.com/my_org/example-cookbook
	Path: /Users/username/Documents/dev/local/example-cookbook

Should I have to install the gem I'm working on into the local gem repository just to build the cookbook for it?

Feature Request: Support 'supports' for generated metadata.rb

As a Halite Gem Author, targeting a specific Platform and or Platform Version, I want to specify the value or values for the supports field, and have those values appear within the generated metadata.rb file.

Example use cases:

  1. Writing a Library Halite Gem (Cookbook) for the Windows Platform

I want supports 'windows' to appear in my generated metadata.rb file.

  1. Writing a Library Halite Gem (Cookbook) for the Ubuntu 14.04 Platform

I want supports 'ubuntu', '= 14.04' to appear in my generated metadata.rb file.

External reference: https://docs.chef.io/config_rb_metadata.html 'supports'

Fails when reading subdirectories under lib/

This is against 1.0.0.rc.1. I haven't traced to confirm my diagnosis in the title, but the stacktrace at least seems clear enough :) My gem has lib/crazytown.rb and lib/crazytown/. You can see the halite branch here: https://github.com/jkeiser/crazytown/tree/cookbook

When I run bundle exec rake build --trace, I get:

Errno::EISDIR: Is a directory @ io_fread - /Users/jkeiser/src/crazytown/lib/crazytown
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/halite-1.0.0.rc.1/lib/halite/converter/libraries.rb:34:in `read'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/halite-1.0.0.rc.1/lib/halite/converter/libraries.rb:34:in `block in write'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/halite-1.0.0.rc.1/lib/halite/gem.rb:62:in `call'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/halite-1.0.0.rc.1/lib/halite/gem.rb:62:in `block in each_file'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/halite-1.0.0.rc.1/lib/halite/gem.rb:50:in `each'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/halite-1.0.0.rc.1/lib/halite/gem.rb:50:in `each_file'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/halite-1.0.0.rc.1/lib/halite/gem.rb:69:in `each_library_file'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/halite-1.0.0.rc.1/lib/halite/converter/libraries.rb:33:in `write'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/halite-1.0.0.rc.1/lib/halite/converter.rb:11:in `write'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/halite-1.0.0.rc.1/lib/halite.rb:10:in `convert'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/halite-1.0.0.rc.1/lib/halite/rake_helper.rb:124:in `build_cookbook'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/halite-1.0.0.rc.1/lib/halite/rake_helper.rb:62:in `block in install'
Add halite
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/task.rb:240:in `call'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/task.rb:240:in `block in execute'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/task.rb:235:in `each'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/task.rb:235:in `execute'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/task.rb:179:in `block in invoke_with_call_chain'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/2.1.0/monitor.rb:211:in `mon_synchronize'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/task.rb:172:in `invoke_with_call_chain'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/task.rb:201:in `block in invoke_prerequisites'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/task.rb:199:in `each'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/task.rb:199:in `invoke_prerequisites'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/task.rb:178:in `block in invoke_with_call_chain'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/2.1.0/monitor.rb:211:in `mon_synchronize'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/task.rb:172:in `invoke_with_call_chain'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/task.rb:165:in `invoke'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/application.rb:150:in `invoke_task'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/application.rb:106:in `block (2 levels) in top_level'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/application.rb:106:in `each'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/application.rb:106:in `block in top_level'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/application.rb:115:in `run_with_threads'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/application.rb:100:in `top_level'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/application.rb:78:in `block in run'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/application.rb:176:in `standard_exception_handling'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/lib/rake/application.rb:75:in `run'
/usr/local/var/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rake-10.4.2/bin/rake:33:in `<top (required)>'
/usr/local/var/rbenv/versions/2.1.5/bin/rake:23:in `load'
/usr/local/var/rbenv/versions/2.1.5/bin/rake:23:in `<main>'
Tasks: TOP => build => chef:build

Getting an error while trying to use halite extension in berkshelf

I've installed the halite gem and added extension 'halite' to the top of the Berksfile file, but running berks update give the following error:
/opt/chefdk/embedded/lib/ruby/gems/2.1.0/gems/berkshelf-4.0.1/lib/berkshelf/berksfile.rb:89:inrescue in extension': Could not load an extension by the name halite'. Please make sure it is installed. (LoadError)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.