Skip to content

Commit

Permalink
Extract container service and helpers from updater
Browse files Browse the repository at this point in the history
Moving some shared bits out of the updater class to reduce bloat.
  • Loading branch information
Philip Harrison committed Jul 28, 2021
1 parent c2aca79 commit 3ed9753
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 71 deletions.
24 changes: 24 additions & 0 deletions __tests__/container-service.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import Docker from 'dockerode'

import {ContainerService} from '../src/container-service'
import {ImageService} from '../src/image-service'

describe('ContainerService', () => {
const docker = new Docker()
let container: any

beforeAll(async () => {
await ImageService.pull('alpine')
container = await docker.createContainer({
Image: 'alpine',
AttachStdout: true,
AttachStderr: true,
Cmd: ['/bin/sh', '-c', 'echo $VAR'],
Env: ['VAR=env-var']
})
})

test('runs containers', async () => {
await ContainerService.run(container)
})
})
20 changes: 20 additions & 0 deletions __tests__/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import {base64DecodeDependencyFile} from '../src/utils'

describe('base64DecodeDependencyFile', () => {
test('clones the dependency file', () => {
const dependencyFile = {
name: 'package.json',
content: 'dGVzdCBzdHJpbmc=',
directory: '/',
type: 'file',
support_file: false,
content_encoding: 'utf-8',
deleted: false,
operation: 'add'
}

const decoded = base64DecodeDependencyFile(dependencyFile)
expect(decoded.content).toEqual('test string')
expect(dependencyFile.content).toEqual('dGVzdCBzdHJpbmc=')
})
})
35 changes: 35 additions & 0 deletions src/container-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import * as core from '@actions/core'
import {Container} from 'dockerode'
import {pack} from 'tar-stream'
import {FileFetcherInput, FileUpdaterInput} from './file-types'

export const ContainerService = {
async storeInput(
name: string,
path: string,
container: Container,
input: FileFetcherInput | FileUpdaterInput
): Promise<void> {
const tar = pack()
tar.entry({name}, JSON.stringify(input))
tar.finalize()
await container.putArchive(tar, {path})
},

async run(container: Container): Promise<void> {
try {
const stream = await container.attach({
stream: true,
stdout: true,
stderr: true
})
container.modem.demuxStream(stream, process.stdout, process.stderr)

await container.start()
await container.wait()
} finally {
await container.remove()
core.info(`Cleaned up container ${container.id}`)
}
}
}
27 changes: 27 additions & 0 deletions src/file-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import {Credential, JobDetails} from './api-client'

export type FetchedFiles = {
base_commit_sha: string
dependency_files: any[]
base64_dependency_files: any[]
}

export type FileFetcherInput = {
job: JobDetails
credentials: Credential[]
}

export type DependencyFile = {
name: string
content: any
directory: string
type: string
support_file: boolean
content_encoding: string
deleted: boolean
operation: string
}

export type FileUpdaterInput = FetchedFiles & {
job: JobDetails
}
92 changes: 21 additions & 71 deletions src/updater.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,16 @@ import Docker, {Container} from 'dockerode'
import path from 'path'
import fs from 'fs'
import {Credential, JobDetails, APIClient} from './api-client'
import {pack} from 'tar-stream'
import {ContainerService} from './container-service'
import {base64DecodeDependencyFile} from './utils'
import {DependencyFile, FetchedFiles, FileUpdaterInput} from './file-types'

const JOB_INPUT_FILENAME = 'job.json'
const JOB_INPUT_PATH = `/home/dependabot/dependabot-updater`
const JOB_OUTPUT_FILENAME = 'output.json'
const JOB_OUTPUT_PATH = '/home/dependabot/dependabot-updater/output'
const REPO_CONTENTS_PATH = '/home/dependabot/dependabot-updater/repo'

const decode = (str: string): string =>
Buffer.from(str, 'base64').toString('binary')

export class Updater {
docker: Docker
constructor(
Expand Down Expand Up @@ -47,22 +46,21 @@ export class Updater {
}
}

private decodeBase64Content(file: DependencyFile): string {
const fileCopy = JSON.parse(JSON.stringify(file))
fileCopy.content = decode(fileCopy.content)
return fileCopy
}

private async runFileFetcher(
details: JobDetails,
credentials: Credential[]
): Promise<void | FetchedFiles> {
const container = await this.createContainer('fetch_files')
await this.storeContainerInput(container, {
job: details,
credentials
})
await this.runContainer(container)
await ContainerService.storeInput(
JOB_INPUT_FILENAME,
JOB_INPUT_PATH,
container,
{
job: details,
credentials
}
)
await ContainerService.run(container)

const outputPath = path.join(__dirname, '../output/output.json')
if (!fs.existsSync(outputPath)) {
Expand All @@ -76,7 +74,7 @@ export class Updater {
base_commit_sha: fileFetcherOutput.base_commit_sha,
base64_dependency_files: fileFetcherOutput.base64_dependency_files,
dependency_files: fileFetcherOutput.base64_dependency_files.map(
(file: DependencyFile) => this.decodeBase64Content(file)
(file: DependencyFile) => base64DecodeDependencyFile(file)
)
}

Expand All @@ -95,8 +93,13 @@ export class Updater {
dependency_files: files.dependency_files,
job: details
}
await this.storeContainerInput(container, containerInput)
await this.runContainer(container)
await ContainerService.storeInput(
JOB_INPUT_FILENAME,
JOB_INPUT_PATH,
container,
containerInput
)
await ContainerService.run(container)
}

private async createContainer(updaterCommand: string): Promise<Container> {
Expand Down Expand Up @@ -125,57 +128,4 @@ export class Updater {
core.info(`Created ${updaterCommand} container: ${container.id}`)
return container
}

private async storeContainerInput(
container: Container,
input: FileFetcherInput | FileUpdaterInput
): Promise<void> {
const tar = pack()
tar.entry({name: JOB_INPUT_FILENAME}, JSON.stringify(input))
tar.finalize()
await container.putArchive(tar, {path: JOB_INPUT_PATH})
}

private async runContainer(container: Container): Promise<void> {
try {
await container.start()
const stream = await container.attach({
stream: true,
stdout: true,
stderr: true
})
container.modem.demuxStream(stream, process.stdout, process.stderr)

await container.wait()
} finally {
await container.remove()
core.info(`Cleaned up container ${container.id}`)
}
}
}

type FileFetcherInput = {
job: JobDetails
credentials: Credential[]
}

type FetchedFiles = {
base_commit_sha: string
dependency_files: any[]
base64_dependency_files: any[]
}

type DependencyFile = {
name: string
content: any
directory: string
type: string
support_file: boolean
content_encoding: string
deleted: boolean
operation: string
}

type FileUpdaterInput = FetchedFiles & {
job: JobDetails
}
12 changes: 12 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {DependencyFile} from './file-types'

const base64Decode = (str: string): string =>
Buffer.from(str, 'base64').toString('binary')

export const base64DecodeDependencyFile = (
file: DependencyFile
): DependencyFile => {
const fileCopy = JSON.parse(JSON.stringify(file))
fileCopy.content = base64Decode(fileCopy.content)
return fileCopy
}

0 comments on commit 3ed9753

Please sign in to comment.