
- There's a TODO on the "someday" list [1] to ensure that `head` Git URLs always specify a branch. - So I thought I'd automate this worry by adding an audit. - Since `resource` block URLs tend to be pinned to SHAs, if indeed they are Git URLs, this audit only applies to `head` URLs. [1]: https://github.com/orgs/Homebrew/projects/5?pane=issue&itemId=98789749
509 lines
14 KiB
Ruby
509 lines
14 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require "utils/ast"
|
|
|
|
RSpec.describe Utils::AST::FormulaAST do
|
|
subject(:formula_ast) do
|
|
described_class.new <<~RUBY
|
|
class Foo < Formula
|
|
url "https://brew.sh/foo-1.0.tar.gz"
|
|
license all_of: [
|
|
:public_domain,
|
|
"MIT",
|
|
"GPL-3.0-or-later" => { with: "Autoconf-exception-3.0" },
|
|
]
|
|
end
|
|
RUBY
|
|
end
|
|
|
|
describe "#replace_stanza" do
|
|
it "replaces the specified stanza in a formula" do
|
|
formula_ast.replace_stanza(:license, :public_domain)
|
|
expect(formula_ast.process).to eq <<~RUBY
|
|
class Foo < Formula
|
|
url "https://brew.sh/foo-1.0.tar.gz"
|
|
license :public_domain
|
|
end
|
|
RUBY
|
|
end
|
|
end
|
|
|
|
describe "#add_stanza" do
|
|
it "adds the specified stanza to a formula" do
|
|
formula_ast.add_stanza(:revision, 1)
|
|
expect(formula_ast.process).to eq <<~RUBY
|
|
class Foo < Formula
|
|
url "https://brew.sh/foo-1.0.tar.gz"
|
|
license all_of: [
|
|
:public_domain,
|
|
"MIT",
|
|
"GPL-3.0-or-later" => { with: "Autoconf-exception-3.0" },
|
|
]
|
|
revision 1
|
|
end
|
|
RUBY
|
|
end
|
|
end
|
|
|
|
describe "#remove_stanza" do
|
|
context "when stanza to be removed is a single line followed by a blank line" do
|
|
subject(:formula_ast) do
|
|
described_class.new <<~RUBY.chomp
|
|
class Foo < Formula
|
|
url "https://brew.sh/foo-1.0.tar.gz"
|
|
license :cannot_represent
|
|
|
|
bottle do
|
|
sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra
|
|
end
|
|
end
|
|
RUBY
|
|
end
|
|
|
|
let(:new_contents) do
|
|
<<~RUBY.chomp
|
|
class Foo < Formula
|
|
url "https://brew.sh/foo-1.0.tar.gz"
|
|
|
|
bottle do
|
|
sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra
|
|
end
|
|
end
|
|
RUBY
|
|
end
|
|
|
|
it "removes the line containing the stanza" do
|
|
formula_ast.remove_stanza(:license)
|
|
expect(formula_ast.process).to eq(new_contents)
|
|
end
|
|
end
|
|
|
|
context "when stanza to be removed is a multiline block followed by a blank line" do
|
|
subject(:formula_ast) do
|
|
described_class.new <<~RUBY.chomp
|
|
class Foo < Formula
|
|
url "https://brew.sh/foo-1.0.tar.gz"
|
|
license all_of: [
|
|
:public_domain,
|
|
"MIT",
|
|
"GPL-3.0-or-later" => { with: "Autoconf-exception-3.0" },
|
|
]
|
|
|
|
bottle do
|
|
sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra
|
|
end
|
|
end
|
|
RUBY
|
|
end
|
|
|
|
let(:new_contents) do
|
|
<<~RUBY.chomp
|
|
class Foo < Formula
|
|
url "https://brew.sh/foo-1.0.tar.gz"
|
|
|
|
bottle do
|
|
sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra
|
|
end
|
|
end
|
|
RUBY
|
|
end
|
|
|
|
it "removes the lines containing the stanza" do
|
|
formula_ast.remove_stanza(:license)
|
|
expect(formula_ast.process).to eq(new_contents)
|
|
end
|
|
end
|
|
|
|
context "when stanza to be removed has a comment on the same line" do
|
|
subject(:formula_ast) do
|
|
described_class.new <<~RUBY.chomp
|
|
class Foo < Formula
|
|
url "https://brew.sh/foo-1.0.tar.gz"
|
|
license :cannot_represent # comment
|
|
|
|
bottle do
|
|
sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra
|
|
end
|
|
end
|
|
RUBY
|
|
end
|
|
|
|
let(:new_contents) do
|
|
<<~RUBY.chomp
|
|
class Foo < Formula
|
|
url "https://brew.sh/foo-1.0.tar.gz"
|
|
# comment
|
|
|
|
bottle do
|
|
sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra
|
|
end
|
|
end
|
|
RUBY
|
|
end
|
|
|
|
it "removes the stanza but keeps the comment and its whitespace" do
|
|
formula_ast.remove_stanza(:license)
|
|
expect(formula_ast.process).to eq(new_contents)
|
|
end
|
|
end
|
|
|
|
context "when stanza to be removed has a comment on the next line" do
|
|
subject(:formula_ast) do
|
|
described_class.new <<~RUBY.chomp
|
|
class Foo < Formula
|
|
url "https://brew.sh/foo-1.0.tar.gz"
|
|
license :cannot_represent
|
|
# comment
|
|
|
|
bottle do
|
|
sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra
|
|
end
|
|
end
|
|
RUBY
|
|
end
|
|
|
|
let(:new_contents) do
|
|
<<~RUBY.chomp
|
|
class Foo < Formula
|
|
url "https://brew.sh/foo-1.0.tar.gz"
|
|
# comment
|
|
|
|
bottle do
|
|
sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra
|
|
end
|
|
end
|
|
RUBY
|
|
end
|
|
|
|
it "removes the stanza but keeps the comment" do
|
|
formula_ast.remove_stanza(:license)
|
|
expect(formula_ast.process).to eq(new_contents)
|
|
end
|
|
end
|
|
|
|
context "when stanza to be removed has newlines before and after" do
|
|
subject(:formula_ast) do
|
|
described_class.new <<~RUBY.chomp
|
|
class Foo < Formula
|
|
url "https://brew.sh/foo-1.0.tar.gz"
|
|
|
|
bottle do
|
|
sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra
|
|
end
|
|
|
|
head do
|
|
url "https://brew.sh/foo.git"
|
|
branch "develop"
|
|
end
|
|
end
|
|
RUBY
|
|
end
|
|
|
|
let(:new_contents) do
|
|
<<~RUBY.chomp
|
|
class Foo < Formula
|
|
url "https://brew.sh/foo-1.0.tar.gz"
|
|
|
|
head do
|
|
url "https://brew.sh/foo.git"
|
|
branch "develop"
|
|
end
|
|
end
|
|
RUBY
|
|
end
|
|
|
|
it "removes the stanza and preceding newline" do
|
|
formula_ast.remove_stanza(:bottle)
|
|
expect(formula_ast.process).to eq(new_contents)
|
|
end
|
|
end
|
|
|
|
context "when stanza to be removed is at the end of the formula" do
|
|
subject(:formula_ast) do
|
|
described_class.new <<~RUBY.chomp
|
|
class Foo < Formula
|
|
url "https://brew.sh/foo-1.0.tar.gz"
|
|
license :cannot_represent
|
|
|
|
bottle do
|
|
sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra
|
|
end
|
|
end
|
|
RUBY
|
|
end
|
|
|
|
let(:new_contents) do
|
|
<<~RUBY.chomp
|
|
class Foo < Formula
|
|
url "https://brew.sh/foo-1.0.tar.gz"
|
|
license :cannot_represent
|
|
end
|
|
RUBY
|
|
end
|
|
|
|
it "removes the stanza and preceding newline" do
|
|
formula_ast.remove_stanza(:bottle)
|
|
expect(formula_ast.process).to eq(new_contents)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#add_bottle_block" do
|
|
let(:bottle_output) do
|
|
<<-RUBY
|
|
bottle do
|
|
sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra
|
|
end
|
|
RUBY
|
|
end
|
|
|
|
context "when `license` is a string" do
|
|
subject(:formula_ast) do
|
|
described_class.new <<~RUBY.chomp
|
|
class Foo < Formula
|
|
url "https://brew.sh/foo-1.0.tar.gz"
|
|
license "MIT"
|
|
end
|
|
RUBY
|
|
end
|
|
|
|
let(:new_contents) do
|
|
<<~RUBY.chomp
|
|
class Foo < Formula
|
|
url "https://brew.sh/foo-1.0.tar.gz"
|
|
license "MIT"
|
|
|
|
bottle do
|
|
sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra
|
|
end
|
|
end
|
|
RUBY
|
|
end
|
|
|
|
it "adds `bottle` after `license`" do
|
|
formula_ast.add_bottle_block(bottle_output)
|
|
expect(formula_ast.process).to eq(new_contents)
|
|
end
|
|
end
|
|
|
|
context "when `license` is a symbol" do
|
|
subject(:formula_ast) do
|
|
described_class.new <<~RUBY.chomp
|
|
class Foo < Formula
|
|
url "https://brew.sh/foo-1.0.tar.gz"
|
|
license :cannot_represent
|
|
end
|
|
RUBY
|
|
end
|
|
|
|
let(:new_contents) do
|
|
<<~RUBY.chomp
|
|
class Foo < Formula
|
|
url "https://brew.sh/foo-1.0.tar.gz"
|
|
license :cannot_represent
|
|
|
|
bottle do
|
|
sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra
|
|
end
|
|
end
|
|
RUBY
|
|
end
|
|
|
|
it "adds `bottle` after `license`" do
|
|
formula_ast.add_bottle_block(bottle_output)
|
|
expect(formula_ast.process).to eq(new_contents)
|
|
end
|
|
end
|
|
|
|
context "when `license` is multiline" do
|
|
subject(:formula_ast) do
|
|
described_class.new <<~RUBY.chomp
|
|
class Foo < Formula
|
|
url "https://brew.sh/foo-1.0.tar.gz"
|
|
license all_of: [
|
|
:public_domain,
|
|
"MIT",
|
|
"GPL-3.0-or-later" => { with: "Autoconf-exception-3.0" },
|
|
]
|
|
end
|
|
RUBY
|
|
end
|
|
|
|
let(:new_contents) do
|
|
<<~RUBY.chomp
|
|
class Foo < Formula
|
|
url "https://brew.sh/foo-1.0.tar.gz"
|
|
license all_of: [
|
|
:public_domain,
|
|
"MIT",
|
|
"GPL-3.0-or-later" => { with: "Autoconf-exception-3.0" },
|
|
]
|
|
|
|
bottle do
|
|
sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra
|
|
end
|
|
end
|
|
RUBY
|
|
end
|
|
|
|
it "adds `bottle` after `license`" do
|
|
formula_ast.add_bottle_block(bottle_output)
|
|
expect(formula_ast.process).to eq(new_contents)
|
|
end
|
|
end
|
|
|
|
context "when `head` is a string" do
|
|
subject(:formula_ast) do
|
|
described_class.new <<~RUBY.chomp
|
|
class Foo < Formula
|
|
url "https://brew.sh/foo-1.0.tar.gz"
|
|
head "https://brew.sh/foo.git", branch: "develop"
|
|
end
|
|
RUBY
|
|
end
|
|
|
|
let(:new_contents) do
|
|
<<~RUBY.chomp
|
|
class Foo < Formula
|
|
url "https://brew.sh/foo-1.0.tar.gz"
|
|
head "https://brew.sh/foo.git", branch: "develop"
|
|
|
|
bottle do
|
|
sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra
|
|
end
|
|
end
|
|
RUBY
|
|
end
|
|
|
|
it "adds `bottle` after `head`" do
|
|
formula_ast.add_bottle_block(bottle_output)
|
|
expect(formula_ast.process).to eq(new_contents)
|
|
end
|
|
end
|
|
|
|
context "when `head` is a block" do
|
|
subject(:formula_ast) do
|
|
described_class.new <<~RUBY.chomp
|
|
class Foo < Formula
|
|
url "https://brew.sh/foo-1.0.tar.gz"
|
|
|
|
head do
|
|
url "https://brew.sh/foo.git"
|
|
branch "develop"
|
|
end
|
|
end
|
|
RUBY
|
|
end
|
|
|
|
let(:new_contents) do
|
|
<<~RUBY.chomp
|
|
class Foo < Formula
|
|
url "https://brew.sh/foo-1.0.tar.gz"
|
|
|
|
bottle do
|
|
sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra
|
|
end
|
|
|
|
head do
|
|
url "https://brew.sh/foo.git"
|
|
branch "develop"
|
|
end
|
|
end
|
|
RUBY
|
|
end
|
|
|
|
it "adds `bottle` before `head`" do
|
|
formula_ast.add_bottle_block(bottle_output)
|
|
expect(formula_ast.process).to eq(new_contents)
|
|
end
|
|
end
|
|
|
|
context "when there is a comment on the same line" do
|
|
subject(:formula_ast) do
|
|
described_class.new <<~RUBY.chomp
|
|
class Foo < Formula
|
|
url "https://brew.sh/foo-1.0.tar.gz" # comment
|
|
end
|
|
RUBY
|
|
end
|
|
|
|
let(:new_contents) do
|
|
<<~RUBY.chomp
|
|
class Foo < Formula
|
|
url "https://brew.sh/foo-1.0.tar.gz" # comment
|
|
|
|
bottle do
|
|
sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra
|
|
end
|
|
end
|
|
RUBY
|
|
end
|
|
|
|
it "adds `bottle` after the comment" do
|
|
formula_ast.add_bottle_block(bottle_output)
|
|
expect(formula_ast.process).to eq(new_contents)
|
|
end
|
|
end
|
|
|
|
context "when the next line is a comment" do
|
|
subject(:formula_ast) do
|
|
described_class.new <<~RUBY.chomp
|
|
class Foo < Formula
|
|
url "https://brew.sh/foo-1.0.tar.gz"
|
|
# comment
|
|
end
|
|
RUBY
|
|
end
|
|
|
|
let(:new_contents) do
|
|
<<~RUBY.chomp
|
|
class Foo < Formula
|
|
url "https://brew.sh/foo-1.0.tar.gz"
|
|
# comment
|
|
|
|
bottle do
|
|
sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra
|
|
end
|
|
end
|
|
RUBY
|
|
end
|
|
|
|
it "adds `bottle` after the comment" do
|
|
formula_ast.add_bottle_block(bottle_output)
|
|
expect(formula_ast.process).to eq(new_contents)
|
|
end
|
|
end
|
|
|
|
context "when the next line is blank and the one after it is a comment" do
|
|
subject(:formula_ast) do
|
|
described_class.new <<~RUBY.chomp
|
|
class Foo < Formula
|
|
url "https://brew.sh/foo-1.0.tar.gz"
|
|
|
|
# comment
|
|
end
|
|
RUBY
|
|
end
|
|
|
|
let(:new_contents) do
|
|
<<~RUBY.chomp
|
|
class Foo < Formula
|
|
url "https://brew.sh/foo-1.0.tar.gz"
|
|
|
|
bottle do
|
|
sha256 "f7b1fc772c79c20fddf621ccc791090bc1085fcef4da6cca03399424c66e06ca" => :sierra
|
|
end
|
|
|
|
# comment
|
|
end
|
|
RUBY
|
|
end
|
|
|
|
it "adds `bottle` before the comment" do
|
|
formula_ast.add_bottle_block(bottle_output)
|
|
expect(formula_ast.process).to eq(new_contents)
|
|
end
|
|
end
|
|
end
|
|
end
|