Skip to content

Commit 4a489fb

Browse files
macOS: move from homebrew to github.com/vtjnash/coveralls-macos-binaries
1 parent eb14afc commit 4a489fb

File tree

2 files changed

+83
-242
lines changed

2 files changed

+83
-242
lines changed

src/coveralls_functions.jl

Lines changed: 75 additions & 227 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@ function get_coveralls_info(platform)
1111
method = :download
1212
)
1313
elseif platform == :macos
14+
# Get the latest version dynamically
15+
arch = Sys.ARCH == :aarch64 ? "aarch64" : "x86_64"
16+
version = get_latest_coveralls_macos_version()
1417
return (
15-
url = nothing, # Use Homebrew instead
18+
url = "https://github.com/vtjnash/coveralls-macos-binaries/releases/latest/download/coveralls-macos-$version-$arch.tar.gz",
1619
filename = "coveralls",
17-
method = :homebrew,
18-
tap = "coverallsapp/coveralls",
19-
package = "coveralls"
20+
method = :download,
21+
is_archive = true
2022
)
2123
elseif platform == :windows
2224
return (
@@ -29,6 +31,30 @@ function get_coveralls_info(platform)
2931
end
3032
end
3133

34+
"""
35+
get_latest_coveralls_macos_version()
36+
37+
Get the latest version tag for coveralls-macos-binaries from GitHub API.
38+
"""
39+
function get_latest_coveralls_macos_version()
40+
try
41+
response = HTTP.get("https://api.github.com/repos/vtjnash/coveralls-macos-binaries/releases/latest")
42+
release_data = JSON.parse(String(response.body))
43+
tag_name = release_data["tag_name"]
44+
45+
# Extract version from tag name (e.g., "v0.6.15-build.20250827235919" -> "v0.6.15")
46+
version_match = match(r"^(v\d+\.\d+\.\d+)", tag_name)
47+
if version_match !== nothing
48+
return version_match.captures[1]
49+
else
50+
error("Could not parse version from tag: $tag_name")
51+
end
52+
catch e
53+
@warn "Failed to fetch latest version, falling back to known version: $e"
54+
return "v0.6.15" # Fallback to a known working version
55+
end
56+
end
57+
3258
"""
3359
to_coveralls_json(fcs::Vector{FileCoverage})
3460
@@ -110,207 +136,16 @@ function download_coveralls_reporter(; force=false, install_dir=nothing)
110136
platform = CoverageUtils.detect_platform()
111137
reporter_info = get_coveralls_info(platform)
112138

113-
if reporter_info.method == :homebrew
114-
return install_via_homebrew(reporter_info; force=force)
115-
elseif reporter_info.method == :download
139+
if reporter_info.method == :download
116140
return install_via_download(reporter_info, platform; force=force, install_dir=install_dir)
117141
else
118142
error("Unsupported installation method: $(reporter_info.method)")
119143
end
120144
end
121-
122-
"""
123-
detect_homebrew_status()
124-
125-
Detect available Homebrew installations and return status information.
126-
Returns (brew_cmd, use_local, local_homebrew_dir, local_brew_path).
127-
"""
128-
function detect_homebrew_status()
129-
local_homebrew_dir = @get_scratch!("local_homebrew")
130-
local_brew_path = joinpath(local_homebrew_dir, "bin", "brew")
131-
132-
# Try system Homebrew first
133-
system_brew_cmd = Sys.which("brew")
134-
if system_brew_cmd !== nothing
135-
try
136-
# Simple writability test: check if we can write to the brew prefix
137-
brew_prefix = chomp(read(`$system_brew_cmd --prefix`, String))
138-
if isdir(brew_prefix) && iswritable(brew_prefix)
139-
@info "System Homebrew is available and writable"
140-
return (system_brew_cmd, false, local_homebrew_dir, local_brew_path)
141-
end
142-
catch e
143-
@debug "System Homebrew check failed: $e"
144-
end
145-
end
146-
147-
@info "Using local Homebrew installation"
148-
return (local_brew_path, true, local_homebrew_dir, local_brew_path)
149-
end
150-
151-
"""
152-
install_via_homebrew(reporter_info; force=false)
153-
154-
Install Coveralls reporter via Homebrew (macOS).
155-
First tries system Homebrew, then falls back to local Homebrew if system is locked down.
156-
"""
157-
function install_via_homebrew(reporter_info; force=false)
158-
brew_cmd, use_local_homebrew, local_homebrew_dir, local_brew_path = detect_homebrew_status()
159-
160-
# Install local Homebrew if needed
161-
if use_local_homebrew && !isfile(local_brew_path)
162-
install_local_homebrew(local_homebrew_dir, local_brew_path)
163-
end
164-
165-
# Determine coveralls installation path
166-
coveralls_path = if use_local_homebrew
167-
joinpath(local_homebrew_dir, "bin", "coveralls")
168-
else
169-
brew_prefix = chomp(read(`$brew_cmd --prefix`, String))
170-
joinpath(brew_prefix, "bin", "coveralls")
171-
end
172-
173-
# Check if already installed
174-
if !force && isfile(coveralls_path)
175-
@info "Coveralls reporter already installed at: $coveralls_path"
176-
return coveralls_path
177-
end
178-
179-
# Install coveralls
180-
return install_coveralls_with_homebrew(brew_cmd, reporter_info, coveralls_path, use_local_homebrew, force)
181-
end
182-
183-
"""
184-
install_local_homebrew(local_homebrew_dir, local_brew_path)
185-
186-
Install a local Homebrew instance.
187-
"""
188-
function install_local_homebrew(local_homebrew_dir, local_brew_path)
189-
@info "Installing local Homebrew to: $local_homebrew_dir"
190-
191-
mkpath(local_homebrew_dir)
192-
193-
# Download and extract Homebrew
194-
latest_release_url = "https://api.github.com/repos/Homebrew/brew/releases/latest"
195-
response = HTTP.get(latest_release_url)
196-
release_data = JSON.parse(String(response.body))
197-
tarball_url = release_data["tarball_url"]
198-
199-
tarball_path = joinpath(local_homebrew_dir, "homebrew-latest.tar.gz")
200-
Downloads.download(tarball_url, tarball_path)
201-
202-
run(`tar -xzf $tarball_path -C $local_homebrew_dir --strip-components=1`)
203-
rm(tarball_path)
204-
205-
if !isfile(local_brew_path)
206-
error("Homebrew extraction failed - brew executable not found")
207-
end
208-
209-
# Post-install setup with better error handling
210-
try
211-
# Create cache and temp directories
212-
cache_dir = joinpath(local_homebrew_dir, "cache")
213-
temp_dir = joinpath(local_homebrew_dir, "temp")
214-
mkpath(cache_dir)
215-
mkpath(temp_dir)
216-
217-
withenv("HOMEBREW_NO_AUTO_UPDATE" => "1",
218-
"HOMEBREW_NO_INSTALL_CLEANUP" => "1",
219-
"HOMEBREW_NO_ANALYTICS" => "1",
220-
"HOMEBREW_CACHE" => cache_dir,
221-
"HOMEBREW_TEMP" => temp_dir,
222-
"TMPDIR" => temp_dir) do
223-
run(`$local_brew_path update --force --quiet`)
224-
end
225-
catch e
226-
@warn "Homebrew post-install setup failed, but continuing: $e"
227-
end
228-
229-
@info "Local Homebrew installed successfully"
230-
end
231-
232-
"""
233-
install_coveralls_with_homebrew(brew_cmd, reporter_info, coveralls_path, use_local_homebrew, force=false)
234-
235-
Install coveralls using the specified brew command.
236-
"""
237-
function install_coveralls_with_homebrew(brew_cmd, reporter_info, coveralls_path, use_local_homebrew, force=false)
238-
homebrew_type = use_local_homebrew ? "local Homebrew" : "system Homebrew"
239-
@info "Installing Coveralls reporter via $homebrew_type..."
240-
241-
# Set up environment variables for local Homebrew
242-
local_env_vars = if use_local_homebrew
243-
local_homebrew_dir = dirname(dirname(brew_cmd)) # Get parent of bin directory
244-
cache_dir = joinpath(local_homebrew_dir, "cache")
245-
temp_dir = joinpath(local_homebrew_dir, "temp")
246-
247-
# Ensure directories exist
248-
mkpath(cache_dir)
249-
mkpath(temp_dir)
250-
251-
# Set additional permissions to handle CI environments
252-
try
253-
chmod(cache_dir, 0o755)
254-
chmod(temp_dir, 0o755)
255-
catch e
256-
@debug "Could not set directory permissions: $e"
257-
end
258-
259-
[
260-
"HOMEBREW_NO_AUTO_UPDATE" => "1",
261-
"HOMEBREW_NO_INSTALL_CLEANUP" => "1",
262-
"HOMEBREW_NO_ANALYTICS" => "1",
263-
"HOMEBREW_CACHE" => cache_dir,
264-
"HOMEBREW_TEMP" => temp_dir,
265-
"TMPDIR" => temp_dir,
266-
"HOMEBREW_NO_BOTTLE_SOURCE_FALLBACK" => "1",
267-
"HOMEBREW_FORCE_BREWED_CURL" => "1",
268-
"HOMEBREW_NO_ENV_HINTS" => "1",
269-
"HOMEBREW_QUIET" => "1"
270-
]
271-
else
272-
[]
273-
end
274-
275-
# Add tap (ignore failures)
276-
try
277-
withenv(local_env_vars...) do
278-
run(`$brew_cmd tap $(reporter_info.tap)`)
279-
end
280-
catch e
281-
@debug "Tap command failed (possibly already exists): $e"
282-
end
283-
284-
# Install coveralls
285-
install_cmd = force ? "reinstall" : "install"
286-
try
287-
withenv(local_env_vars...) do
288-
# For local Homebrew, try to install with more permissive settings
289-
if use_local_homebrew
290-
run(`$brew_cmd $install_cmd $(reporter_info.package) --force-bottle`)
291-
else
292-
run(`$brew_cmd $install_cmd $(reporter_info.package)`)
293-
end
294-
end
295-
catch e
296-
@error "Install command failed: $e"
297-
# Re-throw to let caller handle the error
298-
rethrow(e)
299-
end
300-
301-
# Verify installation
302-
if !isfile(coveralls_path)
303-
error("Coveralls installation failed - not found at: $coveralls_path")
304-
end
305-
306-
@info "Coveralls reporter installed at: $coveralls_path"
307-
return coveralls_path
308-
end
309-
310145
"""
311146
install_via_download(reporter_info, platform; force=false, install_dir=nothing)
312147
313-
Install Coveralls reporter via direct download (Linux/Windows).
148+
Install Coveralls reporter via direct download.
314149
"""
315150
function install_via_download(reporter_info, platform; force=false, install_dir=nothing)
316151
# Determine installation directory
@@ -336,7 +171,41 @@ function install_via_download(reporter_info, platform; force=false, install_dir=
336171

337172
@info "Downloading Coveralls Universal Coverage Reporter for $platform..."
338173

339-
return CoverageUtils.download_binary(reporter_info.url, install_dir, reporter_info.filename)
174+
# Handle tar.gz archives (for macOS binaries)
175+
if haskey(reporter_info, :is_archive) && reporter_info.is_archive
176+
# Download archive to temporary location
177+
archive_name = basename(reporter_info.url)
178+
archive_path = joinpath(install_dir, archive_name)
179+
180+
try
181+
Downloads.download(reporter_info.url, archive_path)
182+
183+
# Extract directly to the install directory
184+
run(`tar -xzf $archive_path -C $install_dir`)
185+
186+
# The executable should now be in the install directory
187+
extracted_exec = joinpath(install_dir, reporter_info.filename)
188+
if isfile(extracted_exec)
189+
chmod(extracted_exec, 0o755) # Make executable
190+
@info "Coveralls reporter installed at: $extracted_exec"
191+
192+
# Clean up the archive
193+
rm(archive_path)
194+
195+
return extracted_exec
196+
else
197+
error("Extracted executable not found at: $extracted_exec")
198+
end
199+
200+
catch e
201+
# Clean up on error
202+
isfile(archive_path) && rm(archive_path)
203+
rethrow(e)
204+
end
205+
else
206+
# Direct binary download (Linux/Windows)
207+
return CoverageUtils.download_binary(reporter_info.url, install_dir, reporter_info.filename)
208+
end
340209
end
341210

342211
"""
@@ -357,35 +226,6 @@ function get_coveralls_executable(; auto_download=true, install_dir=nothing)
357226
end
358227
end
359228

360-
# For macOS, check Homebrew installations
361-
if platform == :macos
362-
_, use_local_homebrew, local_homebrew_dir, _ = detect_homebrew_status()
363-
364-
# Check system Homebrew if available
365-
if !use_local_homebrew
366-
system_brew_cmd = Sys.which("brew")
367-
if system_brew_cmd !== nothing
368-
try
369-
brew_prefix = chomp(read(`$system_brew_cmd --prefix`, String))
370-
system_coveralls_path = joinpath(brew_prefix, "bin", "coveralls")
371-
if isfile(system_coveralls_path)
372-
@info "Found Coveralls reporter in system Homebrew: $system_coveralls_path"
373-
return system_coveralls_path
374-
end
375-
catch e
376-
@debug "Could not check system Homebrew installation: $e"
377-
end
378-
end
379-
end
380-
381-
# Check local Homebrew installation
382-
local_coveralls_path = joinpath(local_homebrew_dir, "bin", "coveralls")
383-
if isfile(local_coveralls_path)
384-
@info "Found Coveralls reporter in local Homebrew: $local_coveralls_path"
385-
return local_coveralls_path
386-
end
387-
end
388-
389229
# Check in specified install directory
390230
if install_dir !== nothing
391231
local_path = joinpath(install_dir, reporter_info.filename)
@@ -395,6 +235,14 @@ function get_coveralls_executable(; auto_download=true, install_dir=nothing)
395235
end
396236
end
397237

238+
# Check default install directory (scratch space)
239+
default_install_dir = @get_scratch!("coveralls_reporter")
240+
default_path = joinpath(default_install_dir, reporter_info.filename)
241+
if isfile(default_path)
242+
@info "Found Coveralls reporter at: $default_path"
243+
return default_path
244+
end
245+
398246
# Auto-download if enabled
399247
if auto_download
400248
@info "Coveralls reporter not found, downloading..."

test/runtests.jl

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -815,25 +815,18 @@ withenv(
815815
# Download/install the coveralls reporter and test basic functionality
816816
mktempdir() do tmpdir
817817
try
818-
# Download/install the reporter (uses Homebrew on macOS, direct download elsewhere)
818+
# Download/install the reporter (direct download for all platforms)
819819
exe_path = Coverage.download_coveralls_reporter(; install_dir=tmpdir)
820820
@test !isempty(exe_path) # Should get a valid path
821821

822-
# For Homebrew installations, exe_path is the full path to coveralls
823-
# For direct downloads, exe_path is the full path to the binary
824-
if Coverage.detect_platform() == :macos
825-
# On macOS with Homebrew, test the command is available
826-
@test (exe_path == "coveralls" || endswith(exe_path, "/coveralls"))
822+
# Test the downloaded file exists and is executable
823+
@test isfile(exe_path)
824+
if Sys.iswindows()
825+
# On Windows, just check that the file exists and has .exe extension
826+
@test endswith(exe_path, ".exe")
827827
else
828-
# On other platforms, test the downloaded file exists and is executable
829-
@test isfile(exe_path)
830-
if Sys.iswindows()
831-
# On Windows, just check that the file exists and has .exe extension
832-
@test endswith(exe_path, ".exe")
833-
else
834-
# On Unix systems, check execute permissions
835-
@test stat(exe_path).mode & 0o111 != 0 # Check execute permissions
836-
end
828+
# On Unix systems (including macOS), check execute permissions
829+
@test stat(exe_path).mode & 0o111 != 0 # Check execute permissions
837830
end
838831

839832
# Test basic command execution (--help should work)

0 commit comments

Comments
 (0)