[DRE-commits] [ruby-uglifier] 07/09: manually import github tarball 3.0.4

Praveen Arimbrathodiyil praveen at moszumanska.debian.org
Sat Jan 28 20:20:53 UTC 2017


This is an automated email from the git hooks/post-receive script.

praveen pushed a commit to branch master
in repository ruby-uglifier.

commit 6f8e9c92a79a4f5e372e7b2b143822201b8dcf6a
Author: Pirate Praveen <praveen at debian.org>
Date:   Sun Jan 29 01:31:06 2017 +0530

    manually import github tarball 3.0.4
---
 gemfiles/alaska                |   4 +
 gemfiles/rubyracer             |   4 +
 gemfiles/rubyrhino             |   4 +
 patches/es5-string-split.patch |  23 +++
 spec/source_map_spec.rb        | 226 ++++++++++++++++++++++
 spec/spec_helper.rb            |  32 ++++
 spec/uglifier_spec.rb          | 412 +++++++++++++++++++++++++++++++++++++++++
 7 files changed, 705 insertions(+)

diff --git a/gemfiles/alaska b/gemfiles/alaska
new file mode 100644
index 0000000..455d547
--- /dev/null
+++ b/gemfiles/alaska
@@ -0,0 +1,4 @@
+source "https://rubygems.org"
+
+gemspec :path=> "../"
+gem "alaska", github: "mavenlink/alaska"
diff --git a/gemfiles/rubyracer b/gemfiles/rubyracer
new file mode 100644
index 0000000..3697faf
--- /dev/null
+++ b/gemfiles/rubyracer
@@ -0,0 +1,4 @@
+source "https://rubygems.org"
+
+gemspec :path=> "../"
+gem 'therubyracer'
diff --git a/gemfiles/rubyrhino b/gemfiles/rubyrhino
new file mode 100644
index 0000000..afb5a22
--- /dev/null
+++ b/gemfiles/rubyrhino
@@ -0,0 +1,4 @@
+source "https://rubygems.org"
+
+gemspec :path => "../"
+gem 'therubyrhino'
diff --git a/patches/es5-string-split.patch b/patches/es5-string-split.patch
new file mode 100644
index 0000000..402269f
--- /dev/null
+++ b/patches/es5-string-split.patch
@@ -0,0 +1,23 @@
+diff --git a/lib/split.js b/lib/split.js
+index 43d13a2..8cc2924 100644
+--- a/lib/split.js
++++ b/lib/split.js
+@@ -106,10 +106,11 @@ split = split || function (undef) {
+         return output.length > limit ? output.slice(0, limit) : output;
+     };
+ 
+-    // For convenience
+-    String.prototype.split = function (separator, limit) {
+-        return self(this, separator, limit);
+-    };
++    if ("\n".split(/\n/).length == 0) {
++        String.prototype.split = function (separator, limit) {
++            return self(this, separator, limit);
++        };
++    }
+ 
+     return self;
+ 
+-- 
+2.5.5
+
diff --git a/spec/source_map_spec.rb b/spec/source_map_spec.rb
new file mode 100644
index 0000000..47d60be
--- /dev/null
+++ b/spec/source_map_spec.rb
@@ -0,0 +1,226 @@
+# encoding: UTF-8
+require 'stringio'
+require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
+
+def expect_to_have_inline_source_map(minified, original)
+  options = { :source_map => { :sources_content => true } }
+  _, map = Uglifier.compile_with_map(minified, options)
+  expect(JSON.parse(map).fetch("sourcesContent", [])).to include(original)
+end
+
+describe "Uglifier" do
+  let(:source) do
+    <<-JS
+      function hello () {
+        function world () {
+          return 2;
+        };
+
+        return world() + world();
+      };
+    JS
+  end
+
+  it "generates source maps" do
+    source = File.open("lib/uglify.js", "r:UTF-8").read
+    minified, map = Uglifier.new.compile_with_map(source)
+    expect(minified.length).to be < source.length
+    expect(map.length).to be > 0
+    expect { JSON.parse(map) }.not_to raise_error
+  end
+
+  it "generates source maps with the correct meta-data" do
+    _, json = Uglifier.compile_with_map(
+      source,
+      :source_map => {
+        :filename => "ahoy.js",
+        :output_filename => "ahoy.min.js",
+        :root => "http://localhost/"
+      }
+    )
+
+    map = SourceMap::Map.from_json(json)
+    expect(map.filename).to eq("ahoy.min.js")
+    expect(map.sources).to eq(["ahoy.js"])
+    expect(map.names).to eq(%w(hello world))
+    expect(JSON.parse(json)["sourceRoot"]).to eq("http://localhost/")
+    expect(map[0].generated.line).to eq(1)
+  end
+
+  it "skips copyright lines in source maps" do
+    source = <<-JS
+      /* @copyright Conrad Irwin */
+      function hello () {
+        function world () {
+          return 2;
+        };
+
+        return world() + world();
+      };
+    JS
+
+    _, json = Uglifier.compile_with_map(
+      source,
+      :source_map => {
+        :filename => "ahoy.js",
+        :root => "http://localhost/"
+      }
+    )
+
+    map = SourceMap::Map.from_json(json)
+    expect(map[0].generated.line).to eq(2)
+  end
+
+  it "proceses an input source map" do
+    source = <<-JS
+      function hello () {
+        function world () {
+          return 2;
+        };
+
+        return world() + world();
+      };
+    JS
+
+    minified1, map1 = Uglifier.compile_with_map(
+      source,
+      :source_map => {
+        :filename => "ahoy.js",
+        :root => "http://localhost/"
+      },
+      :mangle => false
+    )
+
+    _, map2 = Uglifier.compile_with_map(
+      source,
+      :source_map => {
+        :input_source_map => map1
+      },
+      :mangle => true
+    )
+
+    expect(minified1.lines.to_a.length).to eq(1)
+
+    map = SourceMap::Map.from_json(map2)
+    expect(map.sources).to eq(["http://localhost/ahoy.js"])
+    expect(map[0].generated.line).to eq(1)
+    expect(map[-1].original.line).to eq(1)
+  end
+
+  it "handles empty string as input map sourceRoot" do
+    _, map1 = Uglifier.compile_with_map(
+      source,
+      :source_map => {
+        :filename => "ahoy.js",
+        :root => ""
+      },
+      :mangle => false
+    )
+
+    _, map = Uglifier.compile_with_map(
+      source,
+      :source_map => {
+        :input_source_map => map1
+      },
+      :mangle => true
+    )
+
+    expect(SourceMap::Map.from_json(map).sources).to eq(["ahoy.js"])
+  end
+
+  it "appends source map url to minified JS" do
+    minified, = Uglifier.compile_with_map(
+      source,
+      :source_map => {
+        :filename => "ahoy.js",
+        :output_filename => "ahoy.min.js",
+        :root => "http://localhost/",
+        :map_url => "http://example.com/map"
+      }
+    )
+    expect(minified).to include("\n//# sourceMappingURL=http://example.com/map")
+  end
+
+  it "appends source url to minified JS" do
+    minified, = Uglifier.compile_with_map(
+      source,
+      :source_map => {
+        :filename => "ahoy.js",
+        :output_filename => "ahoy.min.js",
+        :root => "http://localhost/",
+        :url => "http://example.com/source"
+      }
+    )
+    expect(minified).to include("\n//# sourceURL=http://example.com/source")
+  end
+
+  it "inlines source map" do
+    minified = Uglifier.compile(
+      source,
+      :source_map => {
+        :filename => "ahoy.js",
+        :output_filename => "ahoy.min.js",
+        :root => "http://localhost/",
+        :url => "http://example.com/source"
+      }
+    )
+    source_map_mime = "application/json;charset=utf-8;base64,"
+    expect(minified).to include("\n//# sourceMappingURL=data:#{source_map_mime}")
+  end
+
+  describe "inline source map parsing" do
+    let(:minified) do
+      Uglifier.compile(
+        source,
+        :source_map => {
+          :filename => "ahoy.js",
+          :sources_content => true
+        }
+      )
+    end
+
+    let(:code) { minified.split("\n")[0] }
+    let(:source_mapping_url) { minified.split("\n")[1][2..-1] }
+
+    it "parses inline source maps from line comments" do
+      minified = "#{code}\n//#{source_mapping_url}"
+      expect_to_have_inline_source_map(minified, source)
+    end
+
+    it "parses inline source maps with block comments" do
+      minified = "#{code}\n/*#{source_mapping_url}*/"
+      expect_to_have_inline_source_map(minified, source)
+    end
+
+    it "parses inline source maps with multi-line block comments" do
+      minified = "#{code}\n/*\n#{source_mapping_url}\n*/"
+      expect_to_have_inline_source_map(minified, source)
+    end
+
+    it "parses inline source maps from mixed comments" do
+      minified = "#{code}\n/*\n//#{source_mapping_url}\n*/"
+      expect_to_have_inline_source_map(minified, source)
+    end
+
+    it "only parses source maps at end of file" do
+      minified = "#{code}\n//#{source_mapping_url}\nhello();"
+      _, map = Uglifier.compile_with_map(minified)
+      expect(JSON.parse(map)["sourcesContent"]).to be_nil
+    end
+
+    it "handles other source map declarations at end of file" do
+      minified = "#{code}\n
+        //#{source_mapping_url}\n
+        //# sourceURL=http://example.com/source.js
+        //# sourceURL=http://example.com/source.js
+      "
+      expect_to_have_inline_source_map(minified, source)
+    end
+
+    it "does not explode when data URI is invalid" do
+      minified = "#{code}\n//# sourceMappingURL=data:application/javascript,foobar"
+      _, map = Uglifier.compile_with_map(minified)
+      expect(JSON.parse(map)["sourcesContent"]).to be_nil
+    end
+  end
+end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
new file mode 100644
index 0000000..e878a68
--- /dev/null
+++ b/spec/spec_helper.rb
@@ -0,0 +1,32 @@
+# encoding: UTF-8
+require 'uglifier'
+require 'rspec'
+require 'sourcemap'
+
+# Requires supporting files with custom matchers and macros, etc,
+# in ./support/ and its subdirectories.
+Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
+
+if ENV["ALASKA"]
+  require 'alaska/runtime'
+  require 'tempfile'
+  ExecJS.runtime = Alaska::Runtime.new
+end
+
+RSpec.configure do |config|
+  config.mock_with :rspec do |mock|
+    mock.syntax = :expect
+  end
+  config.expect_with :rspec do |expect|
+    expect.syntax = :expect
+  end
+
+  if ENV['CI']
+    config.before(:example, :focus) { raise "Do not commit focused specs" }
+  else
+    config.filter_run_including :focus => true
+    config.run_all_when_everything_filtered = true
+  end
+
+  config.warnings = true
+end
diff --git a/spec/uglifier_spec.rb b/spec/uglifier_spec.rb
new file mode 100644
index 0000000..efbd9a3
--- /dev/null
+++ b/spec/uglifier_spec.rb
@@ -0,0 +1,412 @@
+# encoding: UTF-8
+require 'stringio'
+require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
+
+describe "Uglifier" do
+  it "minifies JS" do
+    source = File.open("lib/uglify.js", "r:UTF-8").read
+    minified = Uglifier.new.compile(source)
+    expect(minified.length).to be < source.length
+    expect { Uglifier.new.compile(minified) }.not_to raise_error
+  end
+
+  it "throws an exception when compilation fails" do
+    expect { Uglifier.new.compile(")(") }.to raise_error(Uglifier::Error)
+  end
+
+  it "throws an exception on invalid option" do
+    expect { Uglifier.new(:foo => true) }.to raise_error(ArgumentError)
+  end
+
+  it "doesn't omit null character in strings" do
+    expect(Uglifier.new.compile('var foo="\0bar"')).to include("\\0bar")
+  end
+
+  it "adds trailing semicolon to minified source" do
+    source = "(function id(i) {return i;}());"
+    expect(Uglifier.new.compile(source)[-1]).to eql(";"[0])
+  end
+
+  describe "property name mangling" do
+    let(:source) do
+      <<-JS
+        var obj = {
+          _hidden: false,
+          "name": 'value'
+        };
+
+        alert(object.name);
+      JS
+    end
+
+    it "does not mangle property names by default" do
+      expect(Uglifier.compile(source)).to include("object.name")
+    end
+
+    it "can be configured to mangle properties" do
+      expect(Uglifier.compile(source, :mangle_properties => true))
+        .not_to include("object.name")
+    end
+
+    it "can configure a regex for mangling" do
+      expect(Uglifier.compile(source, :mangle_properties => { :regex => /^_/ }))
+        .to include("object.name")
+    end
+
+    it "can be configured to ignore quotes properties" do
+      expect(Uglifier.compile(source, :mangle_properties => { :ignore_quoted => true }))
+        .to include("object.name")
+    end
+
+    it "can be configured to include debug in mangled properties" do
+      expect(Uglifier.compile(source, :mangle_properties => { :debug => true }))
+        .to include("_$name$_")
+    end
+  end
+
+  describe "argument name mangling" do
+    it "doesn't try to mangle $super by default to avoid breaking PrototypeJS" do
+      expect(Uglifier.compile('function foo($super) {return $super}')).to include("$super")
+    end
+
+    it "allows variables to be excluded from mangling" do
+      code = "function bar(foo) {return foo + 'bar'};"
+      expect(Uglifier.compile(code, :mangle => { :except => ["foo"] }))
+        .to include("(foo)")
+    end
+
+    it "skips mangling when set to false" do
+      code = "function bar(foo) {return foo + 'bar'};"
+      expect(Uglifier.compile(code, :mangle => false)).to include("(foo)")
+    end
+
+    it "mangles argument names by default" do
+      code = "function bar(foo) {return foo + 'bar'};"
+      expect(Uglifier.compile(code)).not_to include("(foo)")
+    end
+
+    it "mangles top-level names when explicitly instructed" do
+      code = "function bar(foo) {return foo + 'bar'};"
+      expect(Uglifier.compile(code, :mangle => { :toplevel => false }))
+        .to include("bar(")
+      expect(Uglifier.compile(code, :mangle => { :toplevel => true }))
+        .not_to include("bar(")
+    end
+
+    it "can be controlled with mangle option" do
+      code = "function bar(foo) {return foo + 'bar'};"
+      expect(Uglifier.compile(code, :mangle => false)).to include("(foo)")
+    end
+  end
+
+  describe "comment preservation" do
+    let(:source) do
+      <<-JS
+        /* @preserve Copyright Notice */
+        /* (c) 2011 */
+        // INCLUDED
+        //! BANG
+        function identity(p) { return p; }
+        /* Another Copyright */
+        /*! Another Bang */
+        // A comment!
+        function add(a, b) { return a + b; }
+      JS
+    end
+
+    it "handles copyright option" do
+      compiled = Uglifier.compile(source, :copyright => false)
+      expect(compiled).not_to match(/Copyright/)
+    end
+
+    describe ":copyright" do
+      subject { Uglifier.compile(source, :comments => :copyright) }
+
+      it "preserves comments with string Copyright" do
+        expect(subject).to match(/Copyright Notice/)
+        expect(subject).to match(/Another Copyright/)
+      end
+
+      it "preserves comments that start with a bang (!)" do
+        expect(subject).to match(/! BANG/)
+        expect(subject).to match(/! Another Bang/)
+      end
+
+      it "ignores other comments" do
+        expect(subject).not_to match(/INCLUDED/)
+        expect(subject).not_to match(/A comment!/)
+      end
+    end
+
+    describe ":jsdoc" do
+      subject { Uglifier.compile(source, :output => { :comments => :jsdoc }) }
+
+      it "preserves jsdoc license/preserve blocks" do
+        expect(subject).to match(/Copyright Notice/)
+      end
+
+      it "ignores other comments" do
+        expect(subject).not_to match(/Another Copyright/)
+      end
+    end
+
+    describe ":all" do
+      subject { Uglifier.compile(source, :comments => :all) }
+
+      it "preserves all comments" do
+        expect(subject).to match(/INCLUDED/)
+        expect(subject).to match(/2011/)
+      end
+    end
+
+    describe ":none" do
+      subject { Uglifier.compile(source, :comments => :none) }
+
+      it "omits all comments" do
+        expect(subject).not_to match(%r{//})
+        expect(subject).not_to match(%r{/\*})
+      end
+    end
+
+    describe "regular expression" do
+      subject { Uglifier.compile(source, :comments => /included/i) }
+
+      it "matches comment blocks with regex" do
+        expect(subject).to match(/INCLUDED/)
+      end
+
+      it "omits other blocks" do
+        expect(subject).not_to match(/2011/)
+      end
+    end
+  end
+
+  it "squeezes code only if squeeze is set to true" do
+    code = "function a(a){if(a) { return 0; } else { return 1; }}"
+    minified = Uglifier.compile(code, :squeeze => false)
+    squeezed = Uglifier.compile(code, :squeeze => true)
+    expect(minified.length).to be > squeezed.length
+  end
+
+  it "honors max line length" do
+    code = "var foo = 123;function bar() { return foo; }"
+    uglifier = Uglifier.new(:output => { :max_line_len => 20 }, :compress => false)
+    expect(uglifier.compile(code).split("\n").map(&:length)).to all(be < 28)
+  end
+
+  it "hoists vars to top of the scope" do
+    code = "function something() { var a = 1; a = 2; var b = 3; return a + b;}"
+    minified = Uglifier.compile(code, :compress => { :hoist_vars => true })
+    expect(minified).to match(/var \w,\w/)
+  end
+
+  describe "screw_ie8 option" do
+    let(:code) { "function something() { return g['switch']; }" }
+
+    it "defaults to not screw IE8" do
+      expect(Uglifier.compile(code)).to match(".switch")
+    end
+
+    it "forwards screw_ie8 option to UglifyJS" do
+      expect(Uglifier.compile(code, :mangle => false, :screw_ie8 => true)).to match(/g\.switch/)
+      expect(Uglifier.compile(code, :compress => false, :screw_ie8 => true)).to match(/g\.switch/)
+    end
+
+    it "supports legacy ie_proof output option as opposite for screw_ie8" do
+      minified = Uglifier.compile(code, :output => { :ie_proof => true })
+      expect(minified).to include('["switch"]')
+    end
+  end
+
+  it "can be configured to output only ASCII" do
+    code = "function emoji() { return '\\ud83c\\ude01'; }"
+    minified = Uglifier.compile(code, :output => { :ascii_only => true })
+    expect(minified).to include("\\ud83c\\ude01")
+  end
+
+  it "escapes </script when asked to" do
+    code = "function test() { return '</script>';}"
+    minified = Uglifier.compile(code, :output => { :inline_script => true })
+    expect(minified).not_to include("</script>")
+  end
+
+  it "quotes keys" do
+    code = "var a = {foo: 1}"
+    minified = Uglifier.compile(code, :output => { :quote_keys => true })
+    expect(minified).to include('"foo"')
+  end
+
+  it "quotes unsafe keys by default" do
+    code = 'var code = {"class": "", "\u200c":"A"}'
+    expect(Uglifier.compile(code)).to include('"class"')
+    expect(Uglifier.compile(code)).to include('"\u200c"')
+
+    uglifier = Uglifier.new(:output => { :ascii_only => false, :quote_keys => false })
+    expect(uglifier.compile(code)).to include(["200c".to_i(16)].pack("U*"))
+  end
+
+  it "handles constant definitions" do
+    code = "if (BOOL) { var a = STR; var b = NULL; var c = NUM; }"
+    defines = { "NUM" => 1234, "BOOL" => true, "NULL" => nil, "STR" => "str" }
+    processed = Uglifier.compile(code, :define => defines)
+    expect(processed).to include("a=\"str\"")
+    expect(processed).not_to include("if")
+    expect(processed).to include("b=null")
+    expect(processed).to include("c=1234")
+  end
+
+  it "can disable IIFE negation" do
+    code = "(function() { console.log('test')})();"
+    disabled_negation = Uglifier.compile(code, :compress => { :negate_iife => false })
+    expect(disabled_negation).not_to include("!")
+    negation = Uglifier.compile(code, :compress => { :negate_iife => true })
+    expect(negation).to include("!")
+  end
+
+  it "can drop console logging" do
+    code = "(function() { console.log('test')})();"
+    compiled = Uglifier.compile(code, :compress => { :drop_console => true })
+    expect(compiled).not_to include("console")
+  end
+
+  describe "collapse_vars option" do
+    let(:code) do
+      <<-JS
+        function a() {
+          var win = window;
+          return win.Handlebars;
+        }
+      JS
+    end
+
+    it "collapses vars when collapse_vars is enabled" do
+      compiled = Uglifier.compile(code, :compress => { :collapse_vars => true })
+      expect(compiled).to include("return window.Handlebars")
+    end
+
+    it "defaults to not collapsing variables" do
+      expect(Uglifier.compile(code)).not_to include("return window.Handlebars")
+    end
+  end
+
+  it "processes @ngInject annotations" do
+    code = <<-JS
+    /**
+     * @ngInject
+     */
+    var f = function(foo, bar) { return foo + bar};
+    JS
+    with_angular = Uglifier.compile(code, :compress => { :angular => true })
+    without_angular = Uglifier.compile(code, :compress => { :angular => false })
+    expect(with_angular).to include("f.$inject")
+    expect(without_angular).not_to include("f.$inject")
+  end
+
+  it "keeps unused function arguments when keep_fargs option is set" do
+    code = <<-JS
+    function plus(a, b, c) { return a + b};
+    plus(1, 2);
+    JS
+
+    options = lambda do |keep_fargs|
+      {
+        :mangle => false,
+        :compress => {
+          :keep_fargs => keep_fargs,
+          :unsafe => true
+        }
+      }
+    end
+
+    expect(Uglifier.compile(code, options.call(false))).not_to include("c)")
+    expect(Uglifier.compile(code, options.call(true))).to include("c)")
+  end
+
+  it "keeps function names in output when compressor keep_fnames is set" do
+    code = <<-JS
+    (function plus(a, b) { return a + b})(1, 2);
+    JS
+    expect(Uglifier.compile(code, :compress => true)).not_to include("plus")
+
+    keep_fnames = Uglifier.compile(code, :mangle => false, :compress => { :keep_fnames => true })
+    expect(keep_fnames).to include("plus")
+  end
+
+  it "does not mangle function names in output when mangler keep_fnames is set" do
+    code = <<-JS
+    (function() {
+      function plus(a, b) { return a + b}
+      plus(1, 2);
+    })();
+    JS
+    expect(Uglifier.compile(code, :mangle => true)).not_to include("plus")
+
+    keep_fnames = Uglifier.compile(code, :mangle => { :keep_fnames => true })
+    expect(keep_fnames).to include("plus")
+  end
+
+  it "sets sets both compress and mangle keep_fnames when toplevel keep_fnames is true" do
+    code = <<-JS
+    (function plus(a, b) { return a + b})(1, 2);
+    JS
+    expect(Uglifier.compile(code)).not_to include("plus")
+
+    keep_fnames = Uglifier.compile(code, :keep_fnames => true)
+    expect(keep_fnames).to include("plus")
+  end
+
+  describe "Input Formats" do
+    let(:code) { "function hello() { return 'hello world'; }" }
+
+    it "handles strings" do
+      expect(Uglifier.new.compile(code)).not_to be_empty
+    end
+
+    it "handles IO objects" do
+      expect(Uglifier.new.compile(StringIO.new(code))).not_to be_empty
+    end
+  end
+
+  describe "enclose" do
+    let(:code) { "$.foo()" }
+
+    it "encloses code with given arguments" do
+      minified = Uglifier.compile(code, :enclose => { 'window.jQuery' => '$' })
+      expect(minified).to match(/window.jQuery/)
+    end
+
+    it "handles multiple definitions" do
+      definitions = [%w(lol lulz), %w(foo bar)]
+      minified = Uglifier.compile(code, :enclose => definitions)
+      expect(minified).to match(/lol,foo/)
+      expect(minified).to match(/lulz,bar/)
+    end
+
+    it "wraps with function when given empty object" do
+      minified = Uglifier.compile(code, :enclose => {})
+      expect(minified).to match(/function\(/)
+    end
+  end
+
+  describe "wrap_iife option" do
+    let(:code) do
+      <<-JS
+        (function() {
+          return function() {
+            console.log('test')
+          };
+        })()();
+      JS
+    end
+
+    it "defaults to not wrap IIFEs" do
+      expect(Uglifier.compile(code))
+        .to match("!function(){return function(){console.log(\"test\")}}()();")
+    end
+
+    it "wraps IIFEs" do
+      expect(Uglifier.compile(code, :output => { :wrap_iife => true }))
+        .to match("(function(){return function(){console.log(\"test\")}})()();")
+    end
+  end
+end

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ruby-extras/ruby-uglifier.git



More information about the Pkg-ruby-extras-commits mailing list