Skip to content

Commit

Permalink
Rewrite swift-docker on top of swift-argument-parse & swift-tools-sup…
Browse files Browse the repository at this point in the history
…port-core

Goals:

* Improve testability
* Windows support
* Better documentation
  • Loading branch information
iainsmith committed Apr 19, 2020
1 parent 819918c commit 78ace45
Show file tree
Hide file tree
Showing 42 changed files with 1,282 additions and 346 deletions.
5 changes: 5 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.DS_Store
/.build
/Packages
/*.xcodeproj
.git
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
/.build
/Packages
/*.xcodeproj
**/*/xcuserdata/*
2 changes: 1 addition & 1 deletion .swift-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4.0.3
5.2
16 changes: 16 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
language: generic
dist: bionic
sudo: required
osx_image: xcode11.4
os:
- linux
- osx
env:
- SWIFT_VERSION=5.1
- SWIFT_VERSION=5.2.1
install:
- if [ "$TRAVIS_OS_NAME" = "linux" ] || [ "$SWIFT_VERSION" = "5.1" ]; then eval "$(curl -sL https://swiftenv.fuller.li/en/latest/install.sh)"; fi;
script:
- set -o pipefail
- swift test --filter TravisClientTests.JSONTests

31 changes: 31 additions & 0 deletions Internals.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
## Docker Labels

[Docker Guide](https://docs.docker.com/config/labels-custom-metadata/)

our prefix is com.swiftdockercli

LABEL com.swiftdockercli.action="test"/"build"
LABEL com.swiftdockercli.folder="name-of-your-project"
* "com.swiftdockercli.action"= - images created from the test command
* "com.swiftdockercli.build" - images created from the build command

LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"

Identifying test images created with `swift-docker` = `docker images --filter "com.swiftdockercli.action=bar"`

## Docker Tags

https://docs.docker.com/engine/reference/commandline/tag/

## Ideas

* `swift docker test -s 4.1`
* `swift docker test -s 4.0`
* `swift docker test --configuration release`
* `swift docker test --swift 4.0 --configuration release`
* `swift docker test --image swiftdocker/swift:latest`
* `swift docker build --tag my-tag`
* `swift docker run ./build/hello --interactive`
* `swift docker run --daemon/--background`
* `swift docker test --log docker.log`
34 changes: 8 additions & 26 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,21 @@
"object": {
"pins": [
{
"package": "Commander",
"repositoryURL": "https://github.com/kylef/Commander",
"package": "swift-argument-parser",
"repositoryURL": "https://github.com/apple/swift-argument-parser",
"state": {
"branch": null,
"revision": "e5b50ad7b2e91eeb828393e89b03577b16be7db9",
"version": "0.8.0"
"revision": "9f04d1ff1afbccd02279338a2c91e5f27c45e93a",
"version": "0.0.5"
}
},
{
"package": "Rainbow",
"repositoryURL": "https://github.com/onevcat/Rainbow",
"package": "swift-tools-support-core",
"repositoryURL": "https://github.com/apple/swift-tools-support-core",
"state": {
"branch": null,
"revision": "f69961599ad524251d677fbec9e4bac57385d6fc",
"version": "3.1.1"
}
},
{
"package": "ShellOut",
"repositoryURL": "https://github.com/iainsmith/ShellOut",
"state": {
"branch": null,
"revision": "46c6382a0531a448841c0fa6fc58fcf75f216c56",
"version": "2.2.0"
}
},
{
"package": "Spectre",
"repositoryURL": "https://github.com/kylef/Spectre.git",
"state": {
"branch": null,
"revision": "e34d5687e1e9d865e3527dd58bc2f7464ef6d936",
"version": "0.8.0"
"revision": "ae8ccef3274e38eb5ae3189c357883510da74a01",
"version": "0.1.1"
}
}
]
Expand Down
56 changes: 34 additions & 22 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,28 +1,40 @@
// swift-tools-version:4.0
// swift-tools-version:5.1
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "SwiftDockerCLI",
products: [
.executable(name: "swift-docker", targets: ["SwiftDocker"]),
],
dependencies: [
.package(url: "https://github.com/iainsmith/ShellOut", from: "2.2.0"),
.package(url: "https://github.com/kylef/Commander", from: "0.8.0"),
.package(url: "https://github.com/onevcat/Rainbow", from: "3.1.1"),
],
targets: [
.target(
name: "SwiftDocker",
dependencies: ["SwiftDockerLib"]),
.target(
name: "SwiftDockerLib",
dependencies: ["ShellOut", "Commander", "Rainbow"]),
.testTarget(
name: "SwiftDockerLibTests",
dependencies: ["SwiftDockerLib"]
),
]
name: "swift-docker-cli",
platforms: [.macOS(.v10_14)],
products: [
.executable(name: "swift-docker", targets: ["SwiftDocker"]),
.library(name: "SwiftDocker", targets: ["SwiftDocker"]),
],
dependencies: [
.package(
url: "https://github.com/apple/swift-tools-support-core",
.upToNextMinor(from: "0.1.1")
),
.package(
url: "https://github.com/apple/swift-argument-parser",
.upToNextMinor(from: "0.0.5")
),
],
targets: [
.target(
name: "SwiftDocker",
dependencies: ["SwiftDockerLib"]
),
.target(
name: "SwiftDockerLib",
dependencies: [
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"),
.product(name: "ArgumentParser", package: "swift-argument-parser"),
]
),
.testTarget(
name: "SwiftDockerLibTests",
dependencies: ["SwiftDockerLib"]
),
]
)
109 changes: 76 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,56 @@
# swift-docker

Test your swift package is Linux compatible using one command. `swift docker test`
A command line tool for building & testing your swift package in a docker container.

<img src="https://s3.eu-west-2.amazonaws.com/iainpublicgifs/swift-docker-small.gif" width="500">

* [Quick start](#quick-start-for-macOS)
* [Features](#Features)
* [Installation](#Install-swift-docker)
* [Usage](#Usage)
* [Docker Labels](#docker-labels)

## Quick start for macOS

```sh
brew install iainsmith/formulae/swift-docker # Install swift docker
git clone https://github.com/jpsim/Yams.git # Clone an example package
cd Yams && swift test # Run the tests on your machine
swift docker test # Run the tests in a container
swift docker test --swift 5.1 # Check if the tests pass on swift 5.1
swift docker cleanup # Delete the docker image you just created
swift docker write-dockerfile # Write a ./Dockerfile to the repo
```

## Features

* [x] Test swift packages in one command `swift docker test`
* [x] Use custom images - `swift docker test --image vapor/swift:latest`
* [x] Build a docker image for your project - `swift docker build`
* [x] Quickly free up space - `swift docker cleanup`
* [x] Create a dockerfile for your project
* [ ] Prevent duplicate builds
* [ ] Automatically create a .dockerignore file
* [ ] Support multistage slim builds
* [ ] Log output to a file
* [ ] cmake build for running on Windows

## Install swift-docker

Install with Homebrew
```sh
brew tap iainsmith/formulae
brew install swift-docker
brew install iainsmith/formulae/swift-docker
```
<details>
<summary>
or from source
Install from source
</summary>
<pre>
> git clone https://github.com/iainsmith/swift-docker.git
> git clone https://github.com/iainsmith/swift-docker-cli.git
> cd swift-docker
> swift build -c release -Xswiftc -static-stdlib
# copy the binary to somewhere in your path.
> cp ./.build/x86_64-apple-macosx10.10/release/swift-docker ~/bin
> swift build -c release --disable-sandbox
# copy the binary to somewhere in your path.
> cp ./.build/release/swift-docker ~/bin
</pre>
</details>
</br>
Expand All @@ -29,50 +61,61 @@ And install docker if you don't have it already
</summary>

* Download the [Docker Mac App](https://www.docker.com/docker-mac).
* Alternatively install via homebrew `brew install docker`
* Or alternatively install via homebrew `brew cask install docker`
</details>

## Usage

Run the Tests
```bash
OVERVIEW: Build and test your swift packages in docker

```sh
# Against the latest version of swift
swift docker test
Simple commands for working with the official swift docker images
https://hub.docker.com/_/swift

# Against a swift version
swift docker test --swift 4.0
examples:

# Using a specific image
swift docker test --image ibmcom/swift-ubuntu:4.1
swift docker test #test the package in the current directory
swift docker test --swift 5.1 # test your package against swift:5.1
swift docker test --path ~/code/my-package # test a package in a directory
swift docker build --swift 5.2.2 --tag username/package:1.0
swift docker write-dockerfile --swift 5.2.2-slim
swift docker cleanup # Remove all images created with swift docker test

# Run tests and save dockerfile
swift docker test --image ibmcom/swift-ubuntu:4.1 --write-dockerfile
```
USAGE: swift-docker <subcommand>

Save the default dockerfile to ./Dockerfile
OPTIONS:
-h, --help Show help information.

```sh
swift docker write-dockerfile
SUBCOMMANDS:
test Test your swift package in a docker container.
build Build you swift package in a docker container.
cleanup Remove temporary docker images.
write-dockerfile Write a dockerfile to disk.
```

Cleanup docker images generated by swift-docker
## Docker labels

Each docker image created by `swift-docker` is tagged with two labels.

```
swift docker cleanup
LABEL com.swiftdockercli.action="test/build"
LABEL com.swiftdockercli.folder="your-project-name"
```

## Credits

swift-docker is built on top of
Running `docker ps -a --filter label=com.swiftdockercli.action=test` will list all containers created by swift-docker test
Running `docker images --filter label=com.swiftdockercli.action=test` will list all images created by swift-docker test

* [ShellOut](https://github.com/JohnSundell/ShellOut) (from John Sundell)
* [Commander](https://github.com/kylef/commander) (from Kyle Fuller)
* [Rainbow](https://github.com/onevcat/Rainbow) (from 王巍 Wei Wang)
This is how `swift docker cleanup` looks up images to delete.

## Contributing

If you have suggestions for new commands, features or bug fixes. Please raise an issue or open a PR.
If you have suggestions for new commands, features or bug fixes. Please raise an issue or open a PR.

If you find this tool useful in your workflow let me know on twitter [@_iains]()
If you find this tool useful in your workflow let me know on twitter [@_iains](https://twitter.com/_iains)

## Credits

swift-docker is built on top of

* [swift-tools-support-core](https://github.com/apple/swift-tools-support-core)
* [swift-argument-parser](https://github.com/apple/swift-argument-parser)
39 changes: 1 addition & 38 deletions Sources/SwiftDocker/main.swift
Original file line number Diff line number Diff line change
@@ -1,40 +1,3 @@
import Commander
import Foundation
import SwiftDockerLib

Group() {
let version = Option("swift",
default: "4.1",
flag: "s",
description: "The swift version to test against. e.g 4.0")
// Ideally we could represent this as an optional.
let image = Option("image",
default: "",
flag: "i",
description: "(Optional) The docker image to test against. e.g swiftdocker/swift:4.0")

let writeDockerfile = Flag("write-dockerfile",
default: false,
flag: "w",
description: "Write the dockerfile to the current directory")

/// swift docker test -s 4.1
/// swift docker test -s 4.0
/// swift docker test -s 4.0 -w
/// swift docker test --swift 4.0 --write-dockerfile
/// swift docker test --image swiftdocker/swift:latest
$0.command("test",
version, image, writeDockerfile,
description: "Build and test the SPM package") { version, image, shouldWriteToLocalDir in
try runDockerTests(version: version, image: image, writeDockerFile: shouldWriteToLocalDir)
}
/// swift docker test cleanup
$0.command("cleanup", description: "Remove docker images created with swift docker") {
try runDockerRemoveImages()
}

/// swift docker test write-dockerfile
$0.command("write-dockerfile", version, description: "Write the default dockerfile to ./Dockerfile") { version in
try writeDefaultDockerFile(version: version)
}
}.run()
SwiftDockerCLI.main()
14 changes: 14 additions & 0 deletions Sources/SwiftDockerLib/ArgumentParserExtensions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import protocol ArgumentParser.ExpressibleByArgument
import class Foundation.NSString
import struct Foundation.URL

extension URL: ExpressibleByArgument {
public init?(argument: String) {
let expanded = NSString(string: argument).expandingTildeInPath
self = URL(fileURLWithPath: expanded)
}

public var defaultValueDescription: String {
self.relativeString
}
}
Loading

0 comments on commit 78ace45

Please sign in to comment.