angular_config 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +7 -0
- data/Gemfile +4 -0
- data/README.md +87 -0
- data/Rakefile +12 -0
- data/angular_config.gemspec +26 -0
- data/bin/angular_config +55 -0
- data/lib/angular_config.rb +5 -0
- data/lib/angular_config/config.rb +44 -0
- data/lib/angular_config/file.rb +19 -0
- data/lib/angular_config/source.rb +33 -0
- data/lib/angular_config/version.rb +3 -0
- metadata +124 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
# AngularConfig
|
2
|
+
[](https://travis-ci.org/cultuurnet/angular-config)
|
3
|
+
|
4
|
+
This tool allows you to inject a JSON configuration into a minified Angular application. It inserts checksummed versions of the
|
5
|
+
configuration keys as values during the build process, and provides a mechanism to exchange these keys with the actual values when deploying.
|
6
|
+
|
7
|
+
This is a hackish solution, but it allows swapping configuration values without having to rebuild the application and does not require changes
|
8
|
+
to existing angular code.
|
9
|
+
If you are able to change the angular code, a solution like deferred bootstrapping is probably better suited.
|
10
|
+
|
11
|
+
I created it because, in continuous delivery fashion, I needed to be able to build an application artifact once and deploy it to a number of
|
12
|
+
different environments, with only the configuration changing. As minified Angular applications typically embed the configuration in the javascript,
|
13
|
+
this is what I came up with.
|
14
|
+
|
15
|
+
## Installation
|
16
|
+
|
17
|
+
Add this line to your application's Gemfile:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
gem 'angular_config'
|
21
|
+
```
|
22
|
+
|
23
|
+
And then execute:
|
24
|
+
|
25
|
+
$ bundle
|
26
|
+
|
27
|
+
Or install it yourself as:
|
28
|
+
|
29
|
+
$ gem install angular_config
|
30
|
+
|
31
|
+
## Usage
|
32
|
+
|
33
|
+
### Commandline tool
|
34
|
+
|
35
|
+
Create a hashed version of the config.json first:
|
36
|
+
|
37
|
+
$ angular_config hash -c config.json -t md5 > hashed_config.json
|
38
|
+
|
39
|
+
Now build the angular app using the hashed configuration file.
|
40
|
+
|
41
|
+
After that, exchange the config values for the real ones:
|
42
|
+
|
43
|
+
$ angular_config resolve -t md5 -c config_production.json -f scripts.js
|
44
|
+
|
45
|
+
If you use cache busting (embedding the md5 hash of the file source in the filename and
|
46
|
+
referencing that from the index.html), you will need the calculate a new md5 sum for the
|
47
|
+
changed file, rename and reference accordingly.
|
48
|
+
|
49
|
+
### Programmatically
|
50
|
+
|
51
|
+
Create a hashed version of the config.json first:
|
52
|
+
|
53
|
+
```
|
54
|
+
require 'angular_config'
|
55
|
+
|
56
|
+
config = AngularConfig::Config.load('config.json', 'md5')
|
57
|
+
puts config.hash_values.content.to_json
|
58
|
+
```
|
59
|
+
|
60
|
+
Now build the angular app using the hashed configuration file.
|
61
|
+
|
62
|
+
After that, exchange the config values for the real ones:
|
63
|
+
|
64
|
+
```
|
65
|
+
require 'angular_config'
|
66
|
+
|
67
|
+
config_hashed_keys = AngularConfig::Config.load('config.json', 'md5').hash_keys
|
68
|
+
file = AngularConfig::Source.load('source.js')
|
69
|
+
|
70
|
+
puts file.resolve(config_hashed_keys).content
|
71
|
+
```
|
72
|
+
|
73
|
+
If you use cache busting (embedding the md5 hash of the file source in the filename and
|
74
|
+
referencing that from the index.html), you will need the calculate a new md5 sum for the
|
75
|
+
changed file, rename and reference accordingly.
|
76
|
+
|
77
|
+
## Development
|
78
|
+
|
79
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
80
|
+
|
81
|
+
## Contributing
|
82
|
+
|
83
|
+
1. Fork it ( https://github.com/cultuurnet/angular_config/fork )
|
84
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
85
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
86
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
87
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
|
4
|
+
RSpec::Core::RakeTask.new(:test) do |t|
|
5
|
+
t.pattern = Dir.glob('spec/**/*_spec.rb')
|
6
|
+
t.rspec_opts = '--format documentation'
|
7
|
+
end
|
8
|
+
|
9
|
+
desc "Default task prints the available targets."
|
10
|
+
task :default do
|
11
|
+
system("rake -T")
|
12
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
require 'angular_config/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = "angular_config"
|
9
|
+
spec.version = AngularConfig::VERSION
|
10
|
+
spec.authors = ["Kristof Willaert"]
|
11
|
+
spec.email = ["kristof.willaert@cultuurnet.be"]
|
12
|
+
|
13
|
+
spec.summary = %q{Manage configuration in minified/uglified Angular apps}
|
14
|
+
spec.description = %q{Manage configuration in minified/uglified Angular apps by swapping out cryptographically hashed values}
|
15
|
+
spec.homepage = "https://github.com/cultuurnet/angular_config"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = "bin"
|
19
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler"
|
23
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
24
|
+
spec.add_development_dependency "rspec", "~> 3.4"
|
25
|
+
spec.add_development_dependency "fakefs", "~> 0.10"
|
26
|
+
end
|
data/bin/angular_config
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'angular_config'
|
5
|
+
|
6
|
+
options = {:type => 'SHA256'}
|
7
|
+
|
8
|
+
angular_config = OptionParser.new do |ac|
|
9
|
+
ac.banner = "Usage: angular_config COMMAND [OPTIONS]"
|
10
|
+
ac.separator ""
|
11
|
+
ac.separator "Commands"
|
12
|
+
ac.separator " hash: convert values of a JSON hash to hashed representations of the keys"
|
13
|
+
ac.separator " resolve: resolve hashed keys in a file with actual values"
|
14
|
+
ac.separator ""
|
15
|
+
ac.separator "Options"
|
16
|
+
|
17
|
+
ac.on("-c","--config CONFIG","Configuration file containing source JSON hash") do |config|
|
18
|
+
options[:source_config] = config
|
19
|
+
end
|
20
|
+
|
21
|
+
ac.on("-f","--file FILE","File to resolve") do |file|
|
22
|
+
options[:file] = file
|
23
|
+
end
|
24
|
+
|
25
|
+
ac.on("-t","--type TYPE","Checksum type to use") do |type|
|
26
|
+
options[:type] = type
|
27
|
+
end
|
28
|
+
|
29
|
+
ac.on("-h","--help","help") do
|
30
|
+
puts angular_config
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
angular_config.parse!
|
35
|
+
|
36
|
+
case ARGV[0]
|
37
|
+
when "hash"
|
38
|
+
unless options[:source_config].nil?
|
39
|
+
source_config = AngularConfig::Config.load(options[:source_config], options[:type])
|
40
|
+
puts source_config.hash_values.content.to_json
|
41
|
+
else
|
42
|
+
puts angular_config
|
43
|
+
end
|
44
|
+
when "resolve"
|
45
|
+
unless options[:source_config].nil? or options[:file].nil?
|
46
|
+
config_hashed_keys = AngularConfig::Config.load(options[:source_config], options[:type]).hash_keys
|
47
|
+
file = AngularConfig::Source.load(options[:file])
|
48
|
+
|
49
|
+
puts file.resolve(config_hashed_keys).content
|
50
|
+
else
|
51
|
+
puts angular_config
|
52
|
+
end
|
53
|
+
else
|
54
|
+
puts angular_config
|
55
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module AngularConfig
|
2
|
+
class Config
|
3
|
+
attr_reader :content
|
4
|
+
attr_reader :checksum_type
|
5
|
+
|
6
|
+
def initialize(config = {}, type = 'SHA256')
|
7
|
+
@content = config
|
8
|
+
@checksum_type = type.upcase
|
9
|
+
end
|
10
|
+
|
11
|
+
def hash_keys
|
12
|
+
hashed_keys = content.each_with_object({}) do |(key, value), result|
|
13
|
+
digest = load_constant("Digest::#{checksum_type}").new
|
14
|
+
result[digest.hexdigest(key)] = value
|
15
|
+
end
|
16
|
+
AngularConfig::Config.new(hashed_keys)
|
17
|
+
end
|
18
|
+
|
19
|
+
def hash_values
|
20
|
+
hashed_values = content.each_with_object({}) do |(key, value), result|
|
21
|
+
digest = load_constant("Digest::#{checksum_type}").new
|
22
|
+
result[key] = digest.hexdigest(key)
|
23
|
+
end
|
24
|
+
AngularConfig::Config.new(hashed_values)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.load(path, type = 'SHA256')
|
28
|
+
AngularConfig::Config.new(JSON.load(AngularConfig::File.new(path).content), type)
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.save(data, path)
|
32
|
+
AngularConfig::File.new(path).content = data.to_json
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def load_constant(name)
|
38
|
+
parts = name.split('::')
|
39
|
+
klass = Module.const_get(parts.shift)
|
40
|
+
klass = klass.const_get(parts.shift) until parts.empty?
|
41
|
+
klass
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module AngularConfig
|
2
|
+
class File
|
3
|
+
attr_reader :path
|
4
|
+
|
5
|
+
def initialize(source_path)
|
6
|
+
@path = ::File.expand_path(source_path)
|
7
|
+
end
|
8
|
+
|
9
|
+
def content
|
10
|
+
::File.read(path).chomp
|
11
|
+
end
|
12
|
+
|
13
|
+
def content=(data)
|
14
|
+
::File.open(path, "w") do |file|
|
15
|
+
file.write(data)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module AngularConfig
|
2
|
+
class Source
|
3
|
+
attr_reader :content
|
4
|
+
|
5
|
+
def initialize(content)
|
6
|
+
@content = content
|
7
|
+
end
|
8
|
+
|
9
|
+
def md5
|
10
|
+
Digest::MD5.hexdigest(content)
|
11
|
+
end
|
12
|
+
|
13
|
+
def resolve(hashed_keys)
|
14
|
+
hashed_keys.content.each do |key, value|
|
15
|
+
if value.is_a?(String)
|
16
|
+
self.content.gsub!(key, value)
|
17
|
+
else
|
18
|
+
self.content.gsub!("\"#{key}\"", value.to_json)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.load(path)
|
26
|
+
AngularConfig::Source.new AngularConfig::File.new(path).content
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.save(data, path)
|
30
|
+
AngularConfig::File.new(path).content = data
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
metadata
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: angular_config
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Kristof Willaert
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2017-05-11 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '10.0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '10.0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '3.4'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.4'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: fakefs
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0.10'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0.10'
|
78
|
+
description: Manage configuration in minified/uglified Angular apps by swapping out
|
79
|
+
cryptographically hashed values
|
80
|
+
email:
|
81
|
+
- kristof.willaert@cultuurnet.be
|
82
|
+
executables:
|
83
|
+
- angular_config
|
84
|
+
extensions: []
|
85
|
+
extra_rdoc_files: []
|
86
|
+
files:
|
87
|
+
- .gitignore
|
88
|
+
- .rspec
|
89
|
+
- .travis.yml
|
90
|
+
- Gemfile
|
91
|
+
- README.md
|
92
|
+
- Rakefile
|
93
|
+
- angular_config.gemspec
|
94
|
+
- bin/angular_config
|
95
|
+
- lib/angular_config.rb
|
96
|
+
- lib/angular_config/config.rb
|
97
|
+
- lib/angular_config/file.rb
|
98
|
+
- lib/angular_config/source.rb
|
99
|
+
- lib/angular_config/version.rb
|
100
|
+
homepage: https://github.com/cultuurnet/angular_config
|
101
|
+
licenses: []
|
102
|
+
post_install_message:
|
103
|
+
rdoc_options: []
|
104
|
+
require_paths:
|
105
|
+
- lib
|
106
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
107
|
+
none: false
|
108
|
+
requirements:
|
109
|
+
- - ! '>='
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
requirements: []
|
119
|
+
rubyforge_project:
|
120
|
+
rubygems_version: 1.8.23.2
|
121
|
+
signing_key:
|
122
|
+
specification_version: 3
|
123
|
+
summary: Manage configuration in minified/uglified Angular apps
|
124
|
+
test_files: []
|