All files / owid-grapher/baker DeployQueueServer.ts

85.38% Statements 111/130
91.67% Branches 11/12
45.45% Functions 5/11
85.38% Lines 111/130

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 1001x 1x 1x 1x 1x 1x 1x 1x 1x 2x 2x 2x 2x 2x 2x 1x 1x 1x 1x 1x 1x 1x 3x 3x 1x 1x 3x 3x 2x 2x 1x 1x                 1x 1x     1x 1x     1x 1x     1x 1x     1x 1x 1x       1x 1x 1x 4x 4x 4x 11x 11x 11x 2x 2x 11x 4x 4x 1x 1x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 1x 1x
import { Deploy, DeployChange, DeployStatus } from "../clientUtils/owidTypes"
import * as fs from "fs-extra"
import {
    DEPLOY_QUEUE_FILE_PATH,
    DEPLOY_PENDING_FILE_PATH,
} from "../settings/serverSettings"
 
export class DeployQueueServer {
    constructor(
        queueFilePath = DEPLOY_QUEUE_FILE_PATH,
        pendingFilePath = DEPLOY_PENDING_FILE_PATH
    ) {
        this.queueFilePath = queueFilePath
        this.pendingFilePath = pendingFilePath
    }
 
    private queueFilePath: string
    private pendingFilePath: string
 
    // File manipulation
 
    private async readQueuedFile() {
        return await fs.readFile(this.queueFilePath, "utf8")
    }
 
    private async readPendingFile() {
        if (await fs.pathExists(this.pendingFilePath))
            return await fs.readFile(this.pendingFilePath, "utf8")
        return undefined
    }
 
    async readQueuedAndPendingFiles() {
        const queueContent = await this.readQueuedFile()
        const pendingContent = await this.readPendingFile()
        // If any deploys didn't exit cleanly, this.pendingFilePath would exist.
        // Prepend that message to the current deploy.
        return pendingContent
            ? pendingContent + "\n" + queueContent
            : queueContent
    }
 
    async enqueueChange(item: DeployChange) {
        await fs.appendFile(this.queueFilePath, JSON.stringify(item) + "\n")
    }
 
    async clearQueueFile() {
        await fs.truncate(this.queueFilePath, 0)
    }
 
    async writePendingFile(content: string) {
        await fs.writeFile(this.pendingFilePath, content)
    }
 
    async deletePendingFile() {
        await fs.unlink(this.pendingFilePath)
    }
 
    // Parsing queue content
    async queueIsEmpty() {
        const res = await this.readQueuedAndPendingFiles()
        return !res
    }
 
    // Parse all lines in file as JSON
    parseQueueContent(content: string): DeployChange[] {
        return content
            .split("\n")
            .map((line) => {
                try {
                    return JSON.parse(line)
                } catch (err) {
                    return null
                }
            })
            .filter((x) => x)
    }
 
    async getDeploys() {
        const [queueContent, pendingContent] = await Promise.all([
            this.readQueuedFile(),
            this.readPendingFile(),
        ])
        const deploys: Deploy[] = []
        if (queueContent)
            deploys.push({
                status: DeployStatus.queued,
                // Changes are always appended. Reversing them means the latest changes are first
                // (which is what we want in the UI).
                // We can't sort by time because the presence of "time" is not guaranteed.
                changes: this.parseQueueContent(queueContent).reverse(),
            })
        if (pendingContent)
            deploys.push({
                status: DeployStatus.pending,
                changes: this.parseQueueContent(pendingContent).reverse(),
            })
        return deploys
    }
}