Skip to content

Commit

Permalink
Merge pull request #323 from garden-io/remote-sources-tags
Browse files Browse the repository at this point in the history
docs(examples): use version tags in remote-sources repo urls
  • Loading branch information
eysi09 committed Oct 16, 2018
2 parents 53fefa6 + 7c48383 commit 0b2d703
Show file tree
Hide file tree
Showing 9 changed files with 223 additions and 261 deletions.
6 changes: 6 additions & 0 deletions docs/reference/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,12 @@ module:
# Optional.
image:

# POSIX-style name of Dockerfile, relative to project root. Defaults to
# $PROJECT_ROOT/Dockerfile.
#
# Optional.
dockerfile:

# List of services to deploy from this container module.
#
# Optional.
Expand Down
8 changes: 4 additions & 4 deletions examples/remote-sources/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,12 @@ project:
name: remote-sources
sources:
- name: web-services
repositoryUrl: https://github.com/garden-io/garden-example-remote-sources-web-services.git#master
repositoryUrl: https://github.com/garden-io/garden-example-remote-sources-web-services.git#v0.1.0
- name: db-services
repositoryUrl: https://github.com/garden-io/garden-example-remote-sources-db-services.git#master
repositoryUrl: https://github.com/garden-io/garden-example-remote-sources-db-services.git#v0.1.0
```
> Remote repository URLs must contain a hash part that references a specific branch or tag, e.g. `https://github.com/org/repo.git/#v1.0`.
> Remote repository URLs must contain a hash part that references a specific branch or tag, e.g. `https://github.com/org/repo.git/#my-tag-or-branch`. The remote repositories used in this example all contain the tag `v0.1.0`. Read more about Git tagging [here](https://git-scm.com/book/en/v2/Git-Basics-Tagging).

### Configuring remote modules

Expand All @@ -94,7 +94,7 @@ module:
description: worker
type: container
name: jworker
repositoryUrl: https://github.com/garden-io/garden-example-remote-module-jworker.git#master
repositoryUrl: https://github.com/garden-io/garden-example-remote-module-jworker.git#v0.1.0
services:
- name: javaworker
dependencies:
Expand Down
4 changes: 2 additions & 2 deletions examples/remote-sources/garden.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ project:
name: remote-sources
sources:
- name: web-services
repositoryUrl: https://github.com/garden-io/garden-example-remote-sources-web-services.git#master
repositoryUrl: https://github.com/garden-io/garden-example-remote-sources-web-services.git#v0.1.0
- name: db-services
repositoryUrl: https://github.com/garden-io/garden-example-remote-sources-db-services.git#master
repositoryUrl: https://github.com/garden-io/garden-example-remote-sources-db-services.git#v0.1.0
2 changes: 1 addition & 1 deletion examples/remote-sources/services/jworker/garden.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module:
description: worker
type: container
name: jworker
repositoryUrl: https://github.com/garden-io/garden-example-remote-module-jworker.git#master
repositoryUrl: https://github.com/garden-io/garden-example-remote-module-jworker.git#v0.1.0
services:
- name: javaworker
dependencies:
Expand Down
58 changes: 47 additions & 11 deletions garden-service/src/plugins/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
*/

import * as Joi from "joi"
import * as childProcess from "child-process-promise"
import { Module } from "../types/module"
import {
joiEnvVars,
Expand Down Expand Up @@ -37,6 +36,7 @@ import { keyBy } from "lodash"
import { genericTestSchema, GenericTestSpec } from "./generic"
import { ModuleSpec, ModuleConfig } from "../config/module"
import { BaseServiceSpec, ServiceConfig, baseServiceSchema } from "../config/service"
import execa = require("execa")

export interface ContainerIngressSpec {
hostname?: string
Expand Down Expand Up @@ -207,6 +207,7 @@ export const containerTestSchema = genericTestSchema
export interface ContainerModuleSpec extends ModuleSpec {
buildArgs: PrimitiveMap,
image?: string,
dockerfile?: string,
services: ContainerServiceSpec[],
tests: ContainerTestSpec[],
}
Expand All @@ -229,6 +230,8 @@ export const containerModuleSpecSchema = Joi.object()
"the module does not contain a Dockerfile, this image will be used to deploy the container services. " +
"If specified and the module does contain a Dockerfile, this identifier is used when pushing the built image.",
),
dockerfile: Joi.string().uri(<any>{ relativeOnly: true })
.description("POSIX-style name of Dockerfile, relative to project root. Defaults to $PROJECT_ROOT/Dockerfile."),
services: joiArray(serviceSchema)
.unique("name")
.description("List of services to deploy from this container module."),
Expand All @@ -250,6 +253,13 @@ interface ParsedImageId {
tag: string
}

function getDockerfilePath(basePath: string, dockerfile?: string) {
if (dockerfile) {
return join(basePath, dockerfile)
}
return join(basePath, "Dockerfile")
}

export const helpers = {
/**
* Returns the image ID used locally, when building and deploying to local environments
Expand Down Expand Up @@ -355,24 +365,32 @@ export const helpers = {

async pullImage(module: ContainerModule) {
const identifier = await helpers.getPublicImageId(module)
await helpers.dockerCli(module, `pull ${identifier}`)
await helpers.dockerCli(module, ["pull", identifier])
},

async imageExistsLocally(module: ContainerModule) {
const identifier = await helpers.getLocalImageId(module)
const exists = (await helpers.dockerCli(module, `images ${identifier} -q`)).stdout.trim().length > 0
const exists = (await helpers.dockerCli(module, ["images", identifier, "-q"])).length > 0
return exists ? identifier : null
},

async dockerCli(module: ContainerModule, args) {
async dockerCli(module: ContainerModule, args: string[]) {
// TODO: use dockerode instead of CLI
return childProcess.exec("docker " + args, { cwd: module.buildPath, maxBuffer: 1024 * 1024 })
return execa.stdout("docker", args, { cwd: module.buildPath, maxBuffer: 1024 * 1024 })
},

async hasDockerfile(module: ContainerModule) {
const buildPath = module.buildPath
return pathExists(join(buildPath, "Dockerfile"))
return pathExists(helpers.getDockerfilePathFromModule(module))
},

getDockerfilePathFromModule(module: ContainerModule) {
return getDockerfilePath(module.buildPath, module.spec.dockerfile)
},

getDockerfilePathFromConfig(config: ModuleConfig) {
return getDockerfilePath(config.path, config.spec.dockerfile)
},

}

export async function validateContainerModule({ moduleConfig }: ValidateModuleParams<ContainerModule>) {
Expand Down Expand Up @@ -433,8 +451,17 @@ export async function validateContainerModule({ moduleConfig }: ValidateModulePa
timeout: t.timeout,
}))

const hasDockerfile = await pathExists(helpers.getDockerfilePathFromConfig(moduleConfig))

if (moduleConfig.spec.dockerfile && !hasDockerfile) {
throw new ConfigurationError(
`Dockerfile not found at specififed path ${moduleConfig.spec.dockerfile} for module ${moduleConfig.name}`,
{},
)
}

// make sure we can build the thing
if (!moduleConfig.spec.image && !(await pathExists(join(moduleConfig.path, "Dockerfile")))) {
if (!moduleConfig.spec.image && !hasDockerfile) {
throw new ConfigurationError(
`Module ${moduleConfig.name} neither specifies image nor provides Dockerfile`,
{},
Expand Down Expand Up @@ -482,14 +509,23 @@ export const gardenPlugin = (): GardenPlugin => ({
// build doesn't exist, so we create it
logEntry && logEntry.setState(`Building ${identifier}...`)

const cmdOpts = ["build", "-t", identifier]
const buildArgs = Object.entries(module.spec.buildArgs).map(([key, value]) => {
// TODO: may need to escape this
return `--build-arg ${key}=${value}`
}).join(" ")

if (buildArgs) {
cmdOpts.push(buildArgs)
}

if (module.spec.dockerfile) {
cmdOpts.push("--file", helpers.getDockerfilePathFromModule(module))
}

// TODO: log error if it occurs
// TODO: stream output to log if at debug log level
await helpers.dockerCli(module, `build ${buildArgs} -t ${identifier} ${buildPath}`)
await helpers.dockerCli(module, [...cmdOpts, buildPath])

return { fresh: true, details: { identifier } }
},
Expand All @@ -506,13 +542,13 @@ export const gardenPlugin = (): GardenPlugin => ({
logEntry && logEntry.setState({ msg: `Publishing image ${remoteId}...` })

if (localId !== remoteId) {
await helpers.dockerCli(module, `tag ${localId} ${remoteId}`)
await helpers.dockerCli(module, ["tag", localId, remoteId])
}

// TODO: log error if it occurs
// TODO: stream output to log if at debug log level
// TODO: check if module already exists remotely?
await helpers.dockerCli(module, `push ${remoteId}`)
await helpers.dockerCli(module, ["push", remoteId])

return { published: true, message: `Published ${remoteId}` }
},
Expand Down
4 changes: 2 additions & 2 deletions garden-service/src/plugins/kubernetes/deployment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -368,8 +368,8 @@ export async function pushModule({ ctx, module, logEntry }: PushModuleParams<Con

logEntry && logEntry.setState({ msg: `Pushing image ${remoteId}...` })

await helpers.dockerCli(module, `tag ${localId} ${remoteId}`)
await helpers.dockerCli(module, `push ${remoteId}`)
await helpers.dockerCli(module, ["tag", localId, remoteId])
await helpers.dockerCli(module, ["push", remoteId])

return { pushed: true, message: `Pushed ${localId}` }
}
24 changes: 20 additions & 4 deletions garden-service/src/vcs/git.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { ensureDir, pathExists, stat } from "fs-extra"
import Bluebird = require("bluebird")

import { NEW_MODULE_VERSION, VcsHandler, RemoteSourceParams } from "./base"
import { ConfigurationError } from "../exceptions"
import { ConfigurationError, RuntimeError } from "../exceptions"

export const helpers = {
gitCli: (cwd: string): (cmd: string, args: string[]) => Promise<string> => {
Expand Down Expand Up @@ -105,7 +105,15 @@ export class GitHandler extends VcsHandler {
const entry = logEntry.info({ section: name, msg: `Fetching from ${url}`, status: "active" })
const { repositoryUrl, hash } = parseGitUrl(url)

await git("clone", ["--depth=1", `--branch=${hash}`, repositoryUrl, absPath])
try {
await git("clone", ["--depth=1", `--branch=${hash}`, repositoryUrl, absPath])
} catch (err) {
entry.setError()
throw new RuntimeError(`Downloading remote ${sourceType} failed with error: \n\n${err}`, {
repositoryUrl: url,
message: err.message,
})
}

entry.setSuccess()
}
Expand All @@ -129,8 +137,16 @@ export class GitHandler extends VcsHandler {
if (localCommitId !== remoteCommitId) {
entry.setState(`Fetching from ${url}`)

await git("fetch", ["--depth=1", "origin", hash])
await git("reset", ["--hard", `origin/${hash}`])
try {
await git("fetch", ["--depth=1", "origin", hash])
await git("reset", ["--hard", `origin/${hash}`])
} catch (err) {
entry.setError()
throw new RuntimeError(`Updating remote ${sourceType} failed with error: \n\n${err}`, {
repositoryUrl: url,
message: err.message,
})
}

entry.setSuccess("Source updated")
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
FROM scratch
Loading

0 comments on commit 0b2d703

Please sign in to comment.