Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/build-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ jobs:
mkdir -p jb_updater-bundle
cp jb_updater/jb_updater jb_updater-bundle/
cp jb_updater/jb_updater_gui jb_updater-bundle/
cp jb_updater/assets/jb_updater.svg jb_updater-bundle/
tar -czf jb_updater-bundle-linux-x86_64.tar.gz -C jb_updater-bundle .
- uses: actions/upload-artifact@v4
with:
Expand Down Expand Up @@ -146,13 +147,14 @@ jobs:
cd ..
zip -ry jb_updater-bundle-macos-${ARCH}.zip jb_updater-bundle

# .app bundle with dylibs inside
# .app bundle with dylibs + icon inside
APP_ROOT="JBUpdater.app/Contents"
mkdir -p "$APP_ROOT/MacOS" "$APP_ROOT/Resources"
cp jb_updater/jb_updater_gui "$APP_ROOT/MacOS/"
cp jb_updater/jb_updater "$APP_ROOT/MacOS/"
cp jb_updater/libcrypto.3.dylib "$APP_ROOT/MacOS/"
cp jb_updater/libssl.3.dylib "$APP_ROOT/MacOS/"
cp jb_updater/assets/jb_updater.icns "$APP_ROOT/Resources/"

cat > "$APP_ROOT/Info.plist" <<'PLIST'
<?xml version="1.0" encoding="UTF-8"?>
Expand All @@ -162,6 +164,7 @@ jobs:
<key>CFBundleIdentifier</key><string>com.example.jb-updater</string>
<key>CFBundleVersion</key><string>1.0</string>
<key>CFBundleExecutable</key><string>jb_updater_gui</string>
<key>CFBundleIconFile</key><string>jb_updater</string>
<key>LSMinimumSystemVersion</key><string>11.0</string>
<key>NSHighResolutionCapable</key><true/>
</dict></plist>
Expand Down
Binary file added jb_updater/assets/jb_updater.icns
Binary file not shown.
Binary file added jb_updater/assets/jb_updater.ico
Binary file not shown.
5 changes: 5 additions & 0 deletions jb_updater/assets/jb_updater.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added jb_updater/assets/jb_updater_128x128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added jb_updater/assets/jb_updater_16x16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added jb_updater/assets/jb_updater_256x256.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added jb_updater/assets/jb_updater_32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added jb_updater/assets/jb_updater_48x48.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added jb_updater/assets/jb_updater_512x512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
59 changes: 59 additions & 0 deletions jb_updater/spec/cli_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
require "./spec_helper"
include JBUpdater

describe Options do
describe "#initialize" do
it "defaults all fields to nil/false/empty" do
o = Options.new
o.plugins_dir.should be_nil
o.build.should be_nil
o.only.should be_empty
o.only_incompatible?.should be_false
o.dry_run?.should be_false
o.downloads_host.should eq "downloads.marketplace.jetbrains.com"
o.pin_versions.should be_empty
o.direct_urls.should be_empty
o.list?.should be_false
o.bin_path.should be_nil
o.include_bundled?.should be_false
o.install_ids.should be_empty
o.product.should be_nil
o.ide_path.should be_nil
o.brew_patch.should be_false
o.upgrade_ide?.should be_false
o.ide_downloads_host.should eq "download-cdn.jetbrains.com"
o.arch.should be_nil
o.list_ide_releases?.should be_false
o.no_tty_progress_bar?.should be_false
end
end
end

describe JBUpdater do
describe ".parse_cli" do
it "parses --help and sets list flag" do
opts = JBUpdater.parse_cli(["-l"])
opts.list?.should be_true
end

it "parses --build" do
opts = JBUpdater.parse_cli(["-b", "RM-252"])
opts.build.should eq "RM-252"
end

it "parses --dry-run" do
opts = JBUpdater.parse_cli(["--dry-run"])
opts.dry_run?.should be_true
end

it "parses --plugins-dir" do
opts = JBUpdater.parse_cli(["--plugins-dir", "/custom/path"])
opts.plugins_dir.should eq "/custom/path"
end

it "parses --install-plugin" do
opts = JBUpdater.parse_cli(["-i", "com.example.plugin,org.test"])
opts.install_ids.should eq ["com.example.plugin", "org.test"]
end
end
end
31 changes: 31 additions & 0 deletions jb_updater/spec/http_client_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,35 @@ describe HTTPClient do
new_uri.host.should eq "cdn.jetbrains.io"
new_uri.path.should eq "/files/1234/yaml.zip"
end

it "overrides IDE host correctly" do
uri = URI.parse("https://download.jetbrains.com/ruby/RM-252.0.dmg")
new_uri = HTTPClient.override_ide_repo_host(uri, "custom-cdn.example.com")
new_uri.host.should eq "custom-cdn.example.com"
end

describe ".no_tty_progress_bar" do
it "defaults to false" do
HTTPClient.no_tty_progress_bar?.should be_false
end

it "can be set and read back" do
HTTPClient.no_tty_progress_bar = true
HTTPClient.no_tty_progress_bar?.should be_true
HTTPClient.no_tty_progress_bar = false
end
end

describe ".override_plugin_repo_host" do
it "returns original URI when downloads_host is nil" do
uri = URI.parse("https://plugins.jetbrains.com/files/test.zip")
HTTPClient.override_plugin_repo_host(uri, nil).should be uri
end

it "returns original URI when host doesn't match" do
uri = URI.parse("https://other.host.com/files/test.zip")
new_uri = HTTPClient.override_plugin_repo_host(uri, "cdn.example.com")
new_uri.should be uri
end
end
end
146 changes: 146 additions & 0 deletions jb_updater/spec/plugin_marketplace_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
require "./spec_helper"
include JBUpdater

describe JBUpdater do
describe ".html_strip" do
it "removes basic HTML tags" do
JBUpdater.html_strip("<p>hello</p>").should eq "hello"
end

it "decodes HTML entities" do
JBUpdater.html_strip("&amp;lt;test&amp;gt;").should eq "<test>"
end

it "decodes numeric entities" do
JBUpdater.html_strip("&#65;&#66;&#67;").should eq "ABC"
end

it "collapses whitespace" do
JBUpdater.html_strip("a b\n\nc").should eq "a b c"
end

it "handles empty string" do
JBUpdater.html_strip("").should eq ""
end

it "handles string with no HTML" do
JBUpdater.html_strip("plain text").should eq "plain text"
end
end
end

describe PluginInfo do
describe ".parse" do
it "parses valid XML with one plugin" do
xml = <<-XML
<?xml version="1.0"?>
<plugin-list>
<idea-plugin downloads="12345">
<id>com.example.plugin</id>
<name>Example Plugin</name>
<description>Cool plugin</description>
<vendor>Example Inc</vendor>
<tags>web, integration,</tags>
</idea-plugin>
</plugin-list>
XML
plugins = PluginInfo.parse(xml)
plugins.size.should eq 1
plugins[0].xml_id.should eq "com.example.plugin"
plugins[0].name.should eq "Example Plugin"
plugins[0].description.should eq "Cool plugin"
plugins[0].downloads.should eq 12_345
plugins[0].vendor.should eq "Example Inc"
plugins[0].categories.should contain("web")
plugins[0].categories.should contain("integration")
end

it "strips HTML from description inside XML entities" do
xml = <<-XML
<?xml version="1.0"?>
<plugin-list>
<idea-plugin>
<id>test.html</id>
<name>Test</name>
<description>&lt;b&gt;Bold text&lt;/b&gt; description</description>
</idea-plugin>
</plugin-list>
XML
plugins = PluginInfo.parse(xml)
plugins.size.should eq 1
# The Crystal XML parser may or may not decode entities before passing
# to html_strip. Accept both outcomes: either fully stripped or partially.
desc = plugins[0].description
desc.should_not contain(">")
desc.should_not contain("<")
end

it "returns empty array for empty XML" do
PluginInfo.parse("<plugin-list></plugin-list>").should be_empty
end

it "returns empty array for malformed XML" do
PluginInfo.parse("not xml").should be_empty
end

it "strips malformed <ff> tags" do
xml = <<-XML
<plugin-list>
<idea-plugin>
<id>test</id>
<name>Test</name>
<description><ff>bad</ff>desc</description>
</idea-plugin>
</plugin-list>
XML
PluginInfo.parse(xml).size.should eq 1
end
end

describe "#download_url" do
it "builds URL with xml_id and numeric id" do
p = PluginInfo.new(id: 999_i64, xml_id: "test.plugin", name: "T", description: "")
p.download_url.should eq "https://plugins.jetbrains.com/files/test.plugin/999"
end
end

describe "#download_install_url" do
it "builds install URL with xml_id" do
p = PluginInfo.new(id: 0_i64, xml_id: "test.plugin", name: "T", description: "")
p.download_install_url.should eq "https://plugins.jetbrains.com/plugin/download?pluginId=test.plugin"
end
end

describe "#download_for_build_url" do
it "includes build parameter" do
p = PluginInfo.new(id: 0_i64, xml_id: "test.plugin", name: "T", description: "")
url = p.download_for_build_url("RM-252")
url.should contain("build=RM-252")
url.should contain("id=test.plugin")
end
end

describe "#formatted_downloads" do
it "formats millions" do
p = PluginInfo.new(id: 1_i64, xml_id: "x", name: "x", description: "", downloads: 2_500_000_i64)
p.formatted_downloads.should eq "2.5M"
end

it "formats thousands" do
p = PluginInfo.new(id: 1_i64, xml_id: "x", name: "x", description: "", downloads: 450_000_i64)
p.formatted_downloads.should eq "450.0K"
end

it "formats small numbers" do
p = PluginInfo.new(id: 1_i64, xml_id: "x", name: "x", description: "", downloads: 123_i64)
p.formatted_downloads.should eq "123"
end
end

describe "#star_rating" do
it "returns five stars" do
p = PluginInfo.new(id: 1_i64, xml_id: "x", name: "x", description: "")
p.star_rating.should eq "⭐⭐⭐⭐⭐"
end
end
end
Loading
Loading