Skip to content

Commit 53457c3

Browse files
authored
Allow for .package(url: , branch:) syntax (#3292)
motivation: simpler/nicer syntax changes: Permit .package(url: String, branch: String) syntax
1 parent cf0eb29 commit 53457c3

File tree

11 files changed

+122
-22
lines changed

11 files changed

+122
-22
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
Note: This is in reverse chronological order, so newer entries are added to the top.
22

3+
Swift v.Next
4+
-----------
5+
* [#3292]
6+
* Improvements
7+
8+
Adding a dependency requirement can now be done with the convenience initializer `.package(url: String, branch: String)`.
9+
10+
311
Swift 5.4
412
-----------
513
* [#2937]
@@ -21,6 +29,8 @@ Swift 5.4
2129
* Source Breakages for Swift Packages
2230

2331
The package manager now throws an error if a manifest file contains invalid UTF-8 byte sequences.
32+
33+
2434

2535
Swift 4.2
2636
---------

Documentation/PackageDescription.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,16 @@ static func package(url: String, from version: Version) -> Package.Dependency
296296
/// - requirement: A dependency requirement. See static methods on `Package.Dependency.Requirement` for available options.
297297
static func package(url: String, _ requirement: Package.Dependency.Requirement) -> Package.Dependency
298298

299+
/// Adds a remote package dependency given a branch requirement.
300+
///
301+
/// .package(url: "https://example.com/example-package.git", branch: "main"),
302+
///
303+
/// - Parameters:
304+
/// - name: The name of the package, or nil to deduce it from the URL.
305+
/// - url: The valid Git URL of the package.
306+
/// - branch: A dependency requirement. See static methods on `Package.Dependency.Requirement` for available options.
307+
static func package(name: String? = nil, url: String, branch: String) -> Package.Dependency
308+
299309
/// Add a package dependency starting with a specific minimum version, up to
300310
/// but not including a specified maximum version.
301311
///
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// swift-tools-version:999.0
2+
// The swift-tools-version declares the minimum version of Swift required to build this package.
3+
4+
import PackageDescription
5+
6+
let package = Package(
7+
name: "Bar",
8+
products: [
9+
// Products define the executables and libraries a package produces, and make them visible to other packages.
10+
.library(
11+
name: "Bar",
12+
targets: ["Bar"]),
13+
],
14+
dependencies: [
15+
// Dependencies declare other packages that this package depends on.
16+
// .package(url: /* package url */, from: "1.0.0"),
17+
.package(url: "../Foo", branch: "main")
18+
],
19+
targets: [
20+
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
21+
// Targets can depend on other targets in this package, and on products in packages this package depends on.
22+
.target(
23+
name: "Bar",
24+
dependencies: ["Foo"]),
25+
]
26+
)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import Foo
2+
3+
struct Bar {
4+
var text = "Hello, World!"
5+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// swift-tools-version:999.0
2+
// The swift-tools-version declares the minimum version of Swift required to build this package.
3+
4+
import PackageDescription
5+
6+
let package = Package(
7+
name: "Foo",
8+
products: [
9+
// Products define the executables and libraries a package produces, and make them visible to other packages.
10+
.library(
11+
name: "Foo",
12+
targets: ["Foo"]),
13+
],
14+
dependencies: [
15+
// Dependencies declare other packages that this package depends on.
16+
// .package(url: /* package url */, from: "1.0.0"),
17+
],
18+
targets: [
19+
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
20+
// Targets can depend on other targets in this package, and on products in packages this package depends on.
21+
.target(
22+
name: "Foo",
23+
dependencies: []),
24+
]
25+
)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
struct Foo {
2+
var text = "Hello, World!"
3+
}

Sources/PackageDescription/PackageDependency.swift

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,23 @@ extension Package.Dependency {
6464
) -> Package.Dependency {
6565
return .init(name: name, url: url, requirement: .upToNextMajor(from: version))
6666
}
67+
68+
/// Adds a remote package dependency given a branch requirement.
69+
///
70+
/// .package(url: "https://example.com/example-package.git", branch: "main"),
71+
///
72+
/// - Parameters:
73+
/// - name: The name of the package, or nil to deduce it from the URL.
74+
/// - url: The valid Git URL of the package.
75+
/// - branch: A dependency requirement. See static methods on `Package.Dependency.Requirement` for available options.
76+
@available(_PackageDescription, introduced: 999.0)
77+
public static func package(
78+
name: String? = nil,
79+
url: String,
80+
branch: String
81+
) -> Package.Dependency {
82+
return .init(name: name, url: url, requirement: .branch(branch))
83+
}
6784

6885
/// Adds a remote package dependency given a version requirement.
6986
///
@@ -249,11 +266,6 @@ extension Package.Dependency {
249266
fatalError()
250267
}
251268

252-
@available(*, unavailable, message: "use package(url:_:) with the .branch(String) initializer instead")
253-
public static func package(url: String, branch: String) -> Package.Dependency {
254-
fatalError()
255-
}
256-
257269
@available(*, unavailable, message: "use package(url:_:) with the .revision(String) initializer instead")
258270
public static func package(url: String, revision: String) -> Package.Dependency {
259271
fatalError()

Sources/SPMTestSupport/misc.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ public func initGitRepo(
132132
for tag in tags {
133133
try repo.tag(name: tag)
134134
}
135+
try systemQuietly([Git.tool, "-C", dir.pathString, "branch", "-m", "main"])
135136
} catch {
136137
XCTFail("\(error)", file: file, line: line)
137138
}

Tests/FunctionalTests/DependencyResolutionTests.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,15 @@ class DependencyResolutionTests: XCTestCase {
6565
XCTAssertEqual(output, "♣︎K\n♣︎Q\n♣︎J\n♣︎10\n♣︎9\n♣︎8\n♣︎7\n♣︎6\n♣︎5\n♣︎4\n")
6666
}
6767
}
68+
69+
func testConvenienceBranchInit() throws {
70+
fixture(name: "DependencyResolution/External/Branch") { prefix in
71+
// Tests the convenience init .package(url: , branch: )
72+
let app = prefix.appending(component: "Bar")
73+
let result = try SwiftPMProduct.SwiftBuild.executeProcess([], packagePath: app)
74+
XCTAssert(result.exitStatus == .terminated(code: 0))
75+
}
76+
}
6877

6978
func testMirrors() {
7079
fixture(name: "DependencyResolution/External/Mirror") { prefix in
@@ -76,7 +85,7 @@ class DependencyResolutionTests: XCTestCase {
7685
try ["Foo", "Bar", "BarMirror"].forEach { directory in
7786
let path = prefix.appending(component: directory)
7887
_ = try Process.checkNonZeroExit(args: "git", "-C", path.pathString, "init")
79-
_ = try Process.checkNonZeroExit(args: "git", "-C", path.pathString, "checkout", "-b", "main")
88+
_ = try Process.checkNonZeroExit(args: "git", "-C", path.pathString, "checkout", "-b", "newMain")
8089
}
8190

8291
// run with no mirror

Tests/PackageLoadingTests/PD4_0LoadingTests.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,6 @@ class PackageDescription4_0LoadingTests: PackageDescriptionLoadingTests {
299299
XCTFail("this package should not load succesfully")
300300
} catch ManifestParseError.invalidManifestFormat(let error, _) {
301301
XCTAssert(error.contains("error: 'package(url:version:)' is unavailable: use package(url:_:) with the .exact(Version) initializer instead\n"), "\(error)")
302-
XCTAssert(error.contains("error: 'package(url:branch:)' is unavailable: use package(url:_:) with the .branch(String) initializer instead\n"), "\(error)")
303302
XCTAssert(error.contains("error: 'package(url:revision:)' is unavailable: use package(url:_:) with the .revision(String) initializer instead\n"), "\(error)")
304303
XCTAssert(error.contains("error: 'package(url:range:)' is unavailable: use package(url:_:) without the range label instead\n"), "\(error)")
305304
}

Tests/SourceControlTests/GitRepositoryTests.swift

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -59,15 +59,15 @@ class GitRepositoryTests: XCTestCase {
5959
XCTFail("unexpected resolution of invalid tag to \(revision)")
6060
}
6161

62-
let master = try repository.resolveRevision(identifier: "master")
62+
let main = try repository.resolveRevision(identifier: "main")
6363

64-
XCTAssertEqual(master.identifier,
64+
XCTAssertEqual(main.identifier,
6565
try Process.checkNonZeroExit(
66-
args: Git.tool, "-C", testRepoPath.pathString, "rev-parse", "--verify", "master").spm_chomp())
66+
args: Git.tool, "-C", testRepoPath.pathString, "rev-parse", "--verify", "main").spm_chomp())
6767

6868
// Check that git hashes resolve to themselves.
69-
let masterIdentifier = try repository.resolveRevision(identifier: master.identifier)
70-
XCTAssertEqual(master.identifier, masterIdentifier.identifier)
69+
let mainIdentifier = try repository.resolveRevision(identifier: main.identifier)
70+
XCTAssertEqual(main.identifier, mainIdentifier.identifier)
7171

7272
// Check that invalid identifier doesn't resolve.
7373
if let revision = try? repository.resolveRevision(identifier: "invalid") {
@@ -157,7 +157,7 @@ class GitRepositoryTests: XCTestCase {
157157
try repo.stageEverything()
158158
try repo.commit()
159159
// We should be able to read a repo which as a submdoule.
160-
_ = try repo.read(tree: try repo.resolveHash(treeish: "master"))
160+
_ = try repo.read(tree: try repo.resolveHash(treeish: "main"))
161161
}
162162
}
163163

@@ -365,7 +365,7 @@ class GitRepositoryTests: XCTestCase {
365365
// We should have commits which are not pushed.
366366
XCTAssert(try checkoutRepo.hasUnpushedCommits())
367367
// Push the changes and check again.
368-
try checkoutTestRepo.push(remote: "origin", branch: "master")
368+
try checkoutTestRepo.push(remote: "origin", branch: "main")
369369
XCTAssertFalse(try checkoutRepo.hasUnpushedCommits())
370370
}
371371
}
@@ -437,7 +437,7 @@ class GitRepositoryTests: XCTestCase {
437437
let repo = GitRepository(path: testRepoPath)
438438
var currentRevision = try repo.getCurrentRevision()
439439
// This is the default branch of a new repo.
440-
XCTAssert(repo.exists(revision: Revision(identifier: "master")))
440+
XCTAssert(repo.exists(revision: Revision(identifier: "main")))
441441
// Check a non existent revision.
442442
XCTAssertFalse(repo.exists(revision: Revision(identifier: "nonExistent")))
443443
// Checkout a new branch using command line.
@@ -470,9 +470,9 @@ class GitRepositoryTests: XCTestCase {
470470
try repo.stage(file: "test.txt")
471471
}
472472

473-
try repo.checkout(revision: Revision(identifier: "master"))
474-
// Current branch must be master.
475-
XCTAssertEqual(try repo.currentBranch(), "master")
473+
try repo.checkout(revision: Revision(identifier: "main"))
474+
// Current branch must be main.
475+
XCTAssertEqual(try repo.currentBranch(), "main")
476476
// Create a new branch.
477477
try repo.checkout(newBranch: "TestBranch")
478478
XCTAssertEqual(try repo.currentBranch(), "TestBranch")
@@ -657,9 +657,9 @@ class GitRepositoryTests: XCTestCase {
657657
initGitRepo(testRepoPath)
658658
let repo = GitRepository(path: testRepoPath)
659659

660-
// Create a `main` branch and remove `master`.
661-
try repo.checkout(newBranch: "main")
662-
try systemQuietly([Git.tool, "-C", testRepoPath.pathString, "branch", "-D", "master"])
660+
// Create a `newMain` branch and remove `main`.
661+
try repo.checkout(newBranch: "newMain")
662+
try systemQuietly([Git.tool, "-C", testRepoPath.pathString, "branch", "-D", "main"])
663663

664664
// Change the branch name to something non-existent.
665665
try systemQuietly([Git.tool, "-C", testRepoPath.pathString, "symbolic-ref", "HEAD", "refs/heads/_non_existent_branch_"])
@@ -679,7 +679,7 @@ class GitRepositoryTests: XCTestCase {
679679
let checkoutRepo = try provider.openCheckout(at: checkoutPath)
680680

681681
// Try to check out the `main` branch.
682-
try checkoutRepo.checkout(revision: Revision(identifier: "main"))
682+
try checkoutRepo.checkout(revision: Revision(identifier: "newMain"))
683683
XCTAssertTrue(localFileSystem.exists(checkoutPath.appending(component: "file.swift")))
684684

685685
// The following will throw if HEAD was set incorrectly and we didn't do a no-checkout clone.

0 commit comments

Comments
 (0)