-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
374 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{ | ||
"name": "@rn-buildhub/gcp-storage", | ||
"version": "0.0.1", | ||
"description": "", | ||
"main": "dist/index.js", | ||
"module": "dist/index.js", | ||
"types": "dist/index.d.ts", | ||
"typings": "dist/index.d.ts", | ||
"scripts": { | ||
"build": "tsc" | ||
}, | ||
"author": "", | ||
"license": "ISC", | ||
"dependencies": { | ||
"@google-cloud/storage": "^7.3.0", | ||
"@rn-buildhub/storage-interface": "workspace:^", | ||
"@types/node": "^18.18.4", | ||
"dotenv": "^16.3.1", | ||
"typescript": "^4.9.5" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
import {Storage, Bucket} from "@google-cloud/storage"; | ||
|
||
import process from "node:process"; | ||
import path from "node:path"; | ||
import fs from "node:fs"; | ||
import { Build, HubAdapter, ProjectBuildInfo } from "@rn-buildhub/storage-interface"; | ||
|
||
export interface GCPStorageOptions { | ||
gcpBucket?: string; | ||
gcpApplicationCredentials?: string; | ||
} | ||
|
||
export function getProjectRootDir() { | ||
// todo improve this | ||
return process.cwd(); | ||
} | ||
|
||
function getOptions(options: GCPStorageOptions) { | ||
return { | ||
gcpBucket: process.env.RNBH_GCP_BUCKET ?? options.gcpBucket, | ||
gcpApplicationCredentials: process.env.RNBH_GOOGLE_APPLICATION_CREDENTIALS ?? options.gcpApplicationCredentials, | ||
}; | ||
} | ||
|
||
|
||
// todo rename hub adapter to stare and then create a hub that extends the storage? | ||
class GCPStorage extends HubAdapter { | ||
private bucket: Bucket; | ||
|
||
// todo validate config | ||
|
||
public constructor(fileOptions?: GCPStorageOptions) { | ||
super(); | ||
require("dotenv").config({ path: path.join(getProjectRootDir(), ".env") }); | ||
const options = getOptions(fileOptions || {}); | ||
if(!options.gcpApplicationCredentials){ | ||
throw new Error("Missing RNBH_GOOGLE_APPLICATION_CREDENTIALS env variable"); | ||
} | ||
const jsonFileContent = fs.readFileSync( | ||
path.join(getProjectRootDir(), options.gcpApplicationCredentials), | ||
"utf8" | ||
); | ||
const credentials = JSON.parse(jsonFileContent.toString()); | ||
console.log("credentials", credentials) | ||
console.log("options", options); | ||
const storage = new Storage({ | ||
credentials | ||
}) | ||
if (!options.gcpBucket) { | ||
throw new Error("Missing RNBH_GCP_BUCKET env variable"); | ||
} | ||
|
||
this.bucket = storage.bucket(options.gcpBucket); | ||
} | ||
|
||
private async uploadFileToGcp( | ||
path: string, | ||
buffer: Buffer, | ||
metadata?: { [key: string]: string } | ||
) { | ||
await this.bucket.file(path).save(buffer, { | ||
metadata: metadata | ||
}); | ||
} | ||
|
||
async upload(buildId: string, buffer: Buffer, fileName: string): Promise<string> { | ||
const buildpath = this.getBuildPath(buildId); | ||
|
||
await this.uploadFileToGcp(`${buildpath}/${fileName}`, buffer, { | ||
createdAt: new Date().toISOString() | ||
}); | ||
return `${buildpath}/${fileName}`; | ||
} | ||
|
||
async downloadFileFromGcp(path: string): Promise<Buffer> { | ||
const [buffer] = await this.bucket.file(path).download(); | ||
return buffer; | ||
} | ||
|
||
async setLastBuild(buildId: string): Promise<void> { | ||
const fileContent = JSON.stringify({ lastBuild: buildId }); | ||
await this.uploadFileToGcp(`config.json`, Buffer.from(fileContent, "utf-8")); | ||
} | ||
|
||
async getLastBuild(): Promise<string> { | ||
const fileContent = await this.downloadFileFromGcp(`config.json`); | ||
return JSON.parse(fileContent.toString()).lastBuild; | ||
} | ||
|
||
private getBuildPath(buildId: string) { | ||
return `builds/${buildId}`; | ||
} | ||
|
||
async saveBuildInfo(buildId: string, info: { | ||
androidBuilds: Build[]; | ||
iosBuilds: Build[]; | ||
}): Promise<void> { | ||
const buildpath = this.getBuildPath(buildId); | ||
const infoToSave: ProjectBuildInfo = { | ||
...info, | ||
createdAt: new Date().toISOString(), | ||
version: 1, | ||
id: buildId | ||
}; | ||
await this.uploadFileToGcp(`${buildpath}/info.json`, Buffer.from(JSON.stringify(infoToSave), "utf-8")); | ||
} | ||
|
||
async getBuildInfo(buildId: string): Promise<ProjectBuildInfo> { | ||
const buildpath = this.getBuildPath(buildId); | ||
const fileContent = await this.downloadFileFromGcp(`${buildpath}/info.json`); | ||
return JSON.parse(fileContent.toString()); | ||
} | ||
|
||
download(path: string): Promise<Buffer> { | ||
return this.downloadFileFromGcp(path); | ||
} | ||
} | ||
|
||
export default GCPStorage; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{ | ||
"compilerOptions": { | ||
"declaration": true, | ||
"importHelpers": false, | ||
"module": "commonjs", | ||
"outDir": "dist", | ||
"rootDir": "src", | ||
"strict": true, | ||
"noImplicitAny": true, | ||
"noEmitOnError": true, | ||
"target": "es2019", | ||
"esModuleInterop": true, | ||
"skipLibCheck": true, | ||
}, | ||
"include": [ | ||
"src/**/*" | ||
], | ||
"ts-node": { | ||
"esm": true | ||
} | ||
} |
Oops, something went wrong.