Module: ManifestParser

Defined in:
lib/spm_version_updates/manifest_parser.rb

Overview

Parses Swift Package Manager manifests (‘Package.swift`) and their adjacent `Package.resolved` files.

This supports the “SwiftPM-native” repo layout, where dependencies are declared directly in one or more ‘Package.swift` manifests rather than as `XCRemoteSwiftPackageReference` objects inside an `.xcodeproj`.

Manifests are parsed with a lightweight, dependency-free scanner so the action runs on any runner (e.g. ‘ubuntu-latest`) without requiring Swift or a macOS/Xcode toolchain to be installed.

The requirement hashes returned by ManifestParser.get_packages intentionally mirror the shape produced by ‘Xcodeproj` for `XCRemoteSwiftPackageReference#requirement` (`“kind”`, `“minimumVersion”`, `“maximumVersion”`, `“version”`, `“branch”`, `“revision”`) so the same comparison logic can be reused for both modes.

Defined Under Namespace

Classes: CouldNotFindManifest, CouldNotFindResolvedFile, ManifestPathMustBeSet

Constant Summary collapse

PACKAGE_CALL =
".package("

Class Method Summary collapse

Class Method Details

.default_resolved_path(manifest_path) ⇒ String

Infer the ‘Package.resolved` path that sits next to a manifest.

Parameters:

  • manifest_path (String)

    The path to a ‘Package.swift` file

Returns:

  • (String)


65
66
67
# File 'lib/spm_version_updates/manifest_parser.rb', line 65

def self.default_resolved_path(manifest_path)
  File.join(File.dirname(manifest_path), "Package.resolved")
end

.get_packages(manifest_path) ⇒ Hash<String, Hash>

Find the direct SPM dependencies declared in a ‘Package.swift` manifest.

Local packages (declared with ‘path:`) and packages without a recognizable version requirement are skipped.

Keyed by the normalized repository URL (used to match against ‘Package.resolved` pins and `ignore-repos`), while the original, scheme-bearing `repository_url` is retained for git operations.

Parameters:

  • manifest_path (String)

    The path to a ‘Package.swift` file

Returns:

  • (Hash<String, Hash>)

    normalized URL => { “repository_url”, “requirement” }

Raises:



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/spm_version_updates/manifest_parser.rb', line 37

def self.get_packages(manifest_path)
  raise(ManifestPathMustBeSet) if manifest_path.nil? || manifest_path.empty?
  raise(CouldNotFindManifest, manifest_path) unless File.exist?(manifest_path)

  content = strip_comments(File.read(manifest_path))
  package_calls(content).each_with_object({}) { |call, packages|
    url = call[/\burl\s*:\s*"([^"]+)"/, 1]
    next if url.nil? # local package (path:) or otherwise unrecognized

    requirement = requirement_for(call)
    next if requirement.nil?

    packages[GitOperations.trim_repo_url(url)] = { "repository_url" => url, "requirement" => requirement }
  }
end

.get_resolved_versions(resolved_path) ⇒ Hash<String, String>

Extract the resolved versions from a ‘Package.resolved` file.

Parameters:

  • resolved_path (String)

    The path to a ‘Package.resolved` file

Returns:

  • (Hash<String, String>)

    normalized repository URL => version or revision



57
58
59
# File 'lib/spm_version_updates/manifest_parser.rb', line 57

def self.get_resolved_versions(resolved_path)
  PackageResolved.versions_from(resolved_path)
end