Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

git action cicd 구축 #37

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: froxy Continuous Delivery

on:
push:
branches:
- release # release 브랜치에 푸시될 때 실행
pull_request:
branches:
- main

jobs:
build_and_deploy:
runs-on: ubuntu-20.04 # 빌드가 진행될 환경 설정

steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v2

- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }} # DockerHub 사용자 이름
password: ${{ secrets.DOCKER_PASSWORD }} # DockerHub 비밀번호

#이미지 이름 저장
- name: Set Docker image tag as a variable
run: echo "DOCKER_TAG=${{ secrets.DOCKER_USERNAME }}/froxy-server:latest" >> $GITHUB_ENV

- name: Create .env file
run: |
echo "${{ secrets.BE_ENV }}" > .env
- name: Build Docker image
run: |
docker build -t $DOCKER_TAG .

- name: Push Docker image to Docker Hub
run: |
docker push $DOCKER_TAG

- name: Setup SSH
uses: webfactory/[email protected]
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}

- name: Deploy
run: |
ssh -o StrictHostKeyChecking=no [email protected] "
if [ \$(docker ps -a -q -f name=froxy-container) ]; then
docker stop froxy-container
docker rm froxy-container
fi
docker pull $DOCKER_TAG && \
docker run -d --name froxy-container -p 3000:3000 ${{ secrets.DOCKER_USERNAME }}/froxy-server:latest"
docker image prune -f
48 changes: 48 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Froxy Continuous Integration

on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
ci:
runs-on: ubuntu-20.04

steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 9

- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '20' # 적절한 Node.js 버전으로 설정
cache: 'pnpm' # pnpm 캐싱 활성화

- name: Create .env file
run: |
echo "${{ secrets.BE_ENV }}" > ./apps/backend/.env

- name: Install dependencies #라이브러리설치
run: |
pnpm install

- name: Run lint & Turbo build
run: |
pnpm lint --filter=backend
pnpm turbo run build --filter=backend
#FE CI : pnpm turbo run build --filter=frontend
#전역 CI : pnpm turbo run build

#테스트코드 빌드는 테스트코드를 추가할때 사용
#- name: Run Turbo tests
# run: |
# pnpm turbo run test --filter=be
19 changes: 19 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
FROM node:20

WORKDIR /app


COPY package*.json ./
RUN npm install -g pnpm

COPY . .

RUN pnpm install

RUN pnpm lint --filter=backend && pnpm turbo run build --filter=backend

WORKDIR /app/apps/backend
CMD ["pnpm", "run", "start:prod"]

# 외부에서 접근할 수 있도록 포트 노출
EXPOSE 3000
3 changes: 0 additions & 3 deletions apps/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,10 @@
"@nestjs/common": "^10.0.0",
"@nestjs/core": "^10.0.0",
"@nestjs/platform-express": "^10.0.0",
"ansi-regex": "^6.1.0",
"dockerode": "^4.0.2",
"dotenv": "^16.4.5",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.8.1",
"strip-ansi": "^7.1.0",
"strip-ansi-cjs": "^8.0.0",
"tar-stream": "^3.1.7"
},
"devDependencies": {
Expand Down
7 changes: 4 additions & 3 deletions apps/backend/src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { DockerModule } from './docker/docker.module';
import { ConfigModule } from "@nestjs/config"

@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
envFilePath: '.env',
envFilePath: '.env'
}),
DockerModule],
DockerModule
],
controllers: [AppController],
providers: [AppService]
})
Expand Down
10 changes: 5 additions & 5 deletions apps/backend/src/docker/docker.controller.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { Controller, Get, Param } from '@nestjs/common';

Check warning on line 1 in apps/backend/src/docker/docker.controller.ts

View workflow job for this annotation

GitHub Actions / ci

'Param' is defined but never used

Check warning on line 1 in apps/backend/src/docker/docker.controller.ts

View workflow job for this annotation

GitHub Actions / ci

'Param' is defined but never used
import { DockerService } from './docker.service.js';
import { ConfigService } from '@nestjs/config';
import { DockerService } from './docker.service.js';

@Controller('docker')
export class DockerController {
constructor(private readonly dockerService: DockerService, private configService: ConfigService) {}

@Get('get')
async getDockersTest(): Promise<string>{
async getDockersTest(): Promise<string> {
const mainFileName = 'FunctionDivide.js';
// const gitToken = this.configService.get<string>('STATIC_GIST_ID');
const gistId = this.configService.get<string>('DYNAMIC_GIST_ID');
const gitToken = this.configService.get<string>('GIT_TOKEN');
console.log(gitToken);
const inputs = ["1 1 1 1","1 1 1 1","1 1 1 1","1 1 1 1"];
const value = await this.dockerService.getDocker(gitToken, gistId, mainFileName,inputs);
return value
const inputs = ['1 1 1 1', '1 1 1 1', '1 1 1 1', '1 1 1 1'];
const value = await this.dockerService.getDocker(gitToken, gistId, mainFileName, inputs);
return value;
}
}
4 changes: 2 additions & 2 deletions apps/backend/src/docker/docker.service.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Injectable } from '@nestjs/common';
import * as Docker from 'dockerode';
import { Container } from 'dockerode';
import * as tar from 'tar-stream';
import * as path from 'path';
import { promises as fs } from 'fs';

Check warning on line 4 in apps/backend/src/docker/docker.service.ts

View workflow job for this annotation

GitHub Actions / ci

'fs' is defined but never used

Check warning on line 4 in apps/backend/src/docker/docker.service.ts

View workflow job for this annotation

GitHub Actions / ci

'fs' is defined but never used
import * as path from 'path';

Check warning on line 5 in apps/backend/src/docker/docker.service.ts

View workflow job for this annotation

GitHub Actions / ci

'path' is defined but never used

Check warning on line 5 in apps/backend/src/docker/docker.service.ts

View workflow job for this annotation

GitHub Actions / ci

'path' is defined but never used
import * as tar from 'tar-stream';

interface GistFileAttributes {
filename: string;
Expand All @@ -25,7 +25,7 @@
docker = new Docker();

async getDocker(gitToken: string, gistId: string, mainFileName: string, inputs: any[]): Promise<string> {
const gistUrl = 'https://gist.github.com/username/gistid';

Check warning on line 28 in apps/backend/src/docker/docker.service.ts

View workflow job for this annotation

GitHub Actions / ci

'gistUrl' is assigned a value but never used

Check warning on line 28 in apps/backend/src/docker/docker.service.ts

View workflow job for this annotation

GitHub Actions / ci

'gistUrl' is assigned a value but never used

return this.runGistFiles(gitToken, gistId, mainFileName, inputs)
.then((result) => {
Expand Down
9 changes: 3 additions & 6 deletions apps/backend/test/app.e2e-spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import * as request from 'supertest';
import { AppModule } from './../src/app.module';

Expand All @@ -8,17 +8,14 @@ describe('AppController (e2e)', () => {

beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
imports: [AppModule]
}).compile();

app = moduleFixture.createNestApplication();
await app.init();
});

it('/ (GET)', () => {
return request(app.getHttpServer())
.get('/')
.expect(200)
.expect('Hello World!');
return request(app.getHttpServer()).get('/').expect(200).expect('Hello World!');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// vite.config.ts
import react from "file:///Users/munjunho/Desktop/BC-project/web38-Froxy/node_modules/.pnpm/@[email protected][email protected]_@[email protected][email protected]_/node_modules/@vitejs/plugin-react-swc/index.mjs";
import { resolve } from "path";
import { defineConfig } from "file:///Users/munjunho/Desktop/BC-project/web38-Froxy/node_modules/.pnpm/[email protected]_@[email protected][email protected]/node_modules/vite/dist/node/index.js";
import dts from "file:///Users/munjunho/Desktop/BC-project/web38-Froxy/node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected][email protected]_@[email protected][email protected]_/node_modules/vite-plugin-dts/dist/index.mjs";
import tsconfigPaths from "file:///Users/munjunho/Desktop/BC-project/web38-Froxy/node_modules/.pnpm/[email protected][email protected][email protected]_@[email protected][email protected]_/node_modules/vite-tsconfig-paths/dist/index.js";
var __vite_injected_original_dirname = "/Users/munjunho/Desktop/BC-project/web38-Froxy/packages/react-markdown";
var vite_config_default = defineConfig({
base: "./",
test: {
globals: true,
environment: "jsdom",
setupFiles: ["./src/test/setupTests.ts"]
},
resolve: {
alias: {
"@": resolve(__vite_injected_original_dirname, "./src")
}
},
build: {
lib: {
entry: resolve(__vite_injected_original_dirname, "src/index.ts"),
name: "@froxy/react-markdown",
formats: ["es"],
// 포맷 추가
fileName: (format) => `index.${format}.js`
// 포맷별 파일명
},
rollupOptions: {
external: ["react", "react-dom"],
output: {
globals: {
react: "React",
"react-dom": "ReactDOM"
},
exports: "named",
// named exports 설정
chunkFileNames: "chunks/[name].js",
assetFileNames: "assets/[name].[ext]",
entryFileNames: "[name].js",
manualChunks: void 0,
inlineDynamicImports: false
}
}
},
plugins: [
react(),
tsconfigPaths(),
dts({
tsconfigPath: "./tsconfig.app.json",
include: ["src"],
rollupTypes: true
// 타입 번들링
})
]
});
export {
vite_config_default as default
};
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCIvVXNlcnMvbXVuanVuaG8vRGVza3RvcC9CQy1wcm9qZWN0L3dlYjM4LUZyb3h5L3BhY2thZ2VzL3JlYWN0LW1hcmtkb3duXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ZpbGVuYW1lID0gXCIvVXNlcnMvbXVuanVuaG8vRGVza3RvcC9CQy1wcm9qZWN0L3dlYjM4LUZyb3h5L3BhY2thZ2VzL3JlYWN0LW1hcmtkb3duL3ZpdGUuY29uZmlnLnRzXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ltcG9ydF9tZXRhX3VybCA9IFwiZmlsZTovLy9Vc2Vycy9tdW5qdW5oby9EZXNrdG9wL0JDLXByb2plY3Qvd2ViMzgtRnJveHkvcGFja2FnZXMvcmVhY3QtbWFya2Rvd24vdml0ZS5jb25maWcudHNcIjsvLy8gPHJlZmVyZW5jZSB0eXBlcz1cInZpdGVzdFwiIC8+XG5cbmltcG9ydCByZWFjdCBmcm9tICdAdml0ZWpzL3BsdWdpbi1yZWFjdC1zd2MnO1xuaW1wb3J0IHsgcmVzb2x2ZSB9IGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSAndml0ZSc7XG5pbXBvcnQgZHRzIGZyb20gJ3ZpdGUtcGx1Z2luLWR0cyc7XG5pbXBvcnQgdHNjb25maWdQYXRocyBmcm9tICd2aXRlLXRzY29uZmlnLXBhdGhzJztcblxuLy8gaHR0cHM6Ly92aXRlLmRldi9jb25maWcvXG5leHBvcnQgZGVmYXVsdCBkZWZpbmVDb25maWcoe1xuICBiYXNlOiAnLi8nLFxuICB0ZXN0OiB7XG4gICAgZ2xvYmFsczogdHJ1ZSxcbiAgICBlbnZpcm9ubWVudDogJ2pzZG9tJyxcbiAgICBzZXR1cEZpbGVzOiBbJy4vc3JjL3Rlc3Qvc2V0dXBUZXN0cy50cyddXG4gIH0sXG4gIHJlc29sdmU6IHtcbiAgICBhbGlhczoge1xuICAgICAgJ0AnOiByZXNvbHZlKF9fZGlybmFtZSwgJy4vc3JjJylcbiAgICB9XG4gIH0sXG4gIGJ1aWxkOiB7XG4gICAgbGliOiB7XG4gICAgICBlbnRyeTogcmVzb2x2ZShfX2Rpcm5hbWUsICdzcmMvaW5kZXgudHMnKSxcbiAgICAgIG5hbWU6ICdAZnJveHkvcmVhY3QtbWFya2Rvd24nLFxuICAgICAgZm9ybWF0czogWydlcyddLCAvLyBcdUQzRUNcdUI5RjcgXHVDRDk0XHVBQzAwXG4gICAgICBmaWxlTmFtZTogKGZvcm1hdCkgPT4gYGluZGV4LiR7Zm9ybWF0fS5qc2AgLy8gXHVEM0VDXHVCOUY3XHVCQ0M0IFx1RDMwQ1x1Qzc3Q1x1QkE4NVxuICAgIH0sXG4gICAgcm9sbHVwT3B0aW9uczoge1xuICAgICAgZXh0ZXJuYWw6IFsncmVhY3QnLCAncmVhY3QtZG9tJ10sXG4gICAgICBvdXRwdXQ6IHtcbiAgICAgICAgZ2xvYmFsczoge1xuICAgICAgICAgIHJlYWN0OiAnUmVhY3QnLFxuICAgICAgICAgICdyZWFjdC1kb20nOiAnUmVhY3RET00nXG4gICAgICAgIH0sXG4gICAgICAgIGV4cG9ydHM6ICduYW1lZCcsIC8vIG5hbWVkIGV4cG9ydHMgXHVDMTI0XHVDODE1XG4gICAgICAgIGNodW5rRmlsZU5hbWVzOiAnY2h1bmtzL1tuYW1lXS5qcycsXG4gICAgICAgIGFzc2V0RmlsZU5hbWVzOiAnYXNzZXRzL1tuYW1lXS5bZXh0XScsXG4gICAgICAgIGVudHJ5RmlsZU5hbWVzOiAnW25hbWVdLmpzJyxcbiAgICAgICAgbWFudWFsQ2h1bmtzOiB1bmRlZmluZWQsXG4gICAgICAgIGlubGluZUR5bmFtaWNJbXBvcnRzOiBmYWxzZVxuICAgICAgfVxuICAgIH1cbiAgfSxcblxuICBwbHVnaW5zOiBbXG4gICAgcmVhY3QoKSxcbiAgICB0c2NvbmZpZ1BhdGhzKCksXG4gICAgZHRzKHtcbiAgICAgIHRzY29uZmlnUGF0aDogJy4vdHNjb25maWcuYXBwLmpzb24nLFxuICAgICAgaW5jbHVkZTogWydzcmMnXSxcbiAgICAgIHJvbGx1cFR5cGVzOiB0cnVlIC8vIFx1RDBDMFx1Qzc4NSBcdUJDODhcdUI0RTRcdUI5QzFcbiAgICB9KVxuICBdXG59KTtcbiJdLAogICJtYXBwaW5ncyI6ICI7QUFFQSxPQUFPLFdBQVc7QUFDbEIsU0FBUyxlQUFlO0FBQ3hCLFNBQVMsb0JBQW9CO0FBQzdCLE9BQU8sU0FBUztBQUNoQixPQUFPLG1CQUFtQjtBQU4xQixJQUFNLG1DQUFtQztBQVN6QyxJQUFPLHNCQUFRLGFBQWE7QUFBQSxFQUMxQixNQUFNO0FBQUEsRUFDTixNQUFNO0FBQUEsSUFDSixTQUFTO0FBQUEsSUFDVCxhQUFhO0FBQUEsSUFDYixZQUFZLENBQUMsMEJBQTBCO0FBQUEsRUFDekM7QUFBQSxFQUNBLFNBQVM7QUFBQSxJQUNQLE9BQU87QUFBQSxNQUNMLEtBQUssUUFBUSxrQ0FBVyxPQUFPO0FBQUEsSUFDakM7QUFBQSxFQUNGO0FBQUEsRUFDQSxPQUFPO0FBQUEsSUFDTCxLQUFLO0FBQUEsTUFDSCxPQUFPLFFBQVEsa0NBQVcsY0FBYztBQUFBLE1BQ3hDLE1BQU07QUFBQSxNQUNOLFNBQVMsQ0FBQyxJQUFJO0FBQUE7QUFBQSxNQUNkLFVBQVUsQ0FBQyxXQUFXLFNBQVMsTUFBTTtBQUFBO0FBQUEsSUFDdkM7QUFBQSxJQUNBLGVBQWU7QUFBQSxNQUNiLFVBQVUsQ0FBQyxTQUFTLFdBQVc7QUFBQSxNQUMvQixRQUFRO0FBQUEsUUFDTixTQUFTO0FBQUEsVUFDUCxPQUFPO0FBQUEsVUFDUCxhQUFhO0FBQUEsUUFDZjtBQUFBLFFBQ0EsU0FBUztBQUFBO0FBQUEsUUFDVCxnQkFBZ0I7QUFBQSxRQUNoQixnQkFBZ0I7QUFBQSxRQUNoQixnQkFBZ0I7QUFBQSxRQUNoQixjQUFjO0FBQUEsUUFDZCxzQkFBc0I7QUFBQSxNQUN4QjtBQUFBLElBQ0Y7QUFBQSxFQUNGO0FBQUEsRUFFQSxTQUFTO0FBQUEsSUFDUCxNQUFNO0FBQUEsSUFDTixjQUFjO0FBQUEsSUFDZCxJQUFJO0FBQUEsTUFDRixjQUFjO0FBQUEsTUFDZCxTQUFTLENBQUMsS0FBSztBQUFBLE1BQ2YsYUFBYTtBQUFBO0FBQUEsSUFDZixDQUFDO0FBQUEsRUFDSDtBQUNGLENBQUM7IiwKICAibmFtZXMiOiBbXQp9Cg==
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// vite.config.ts
import react from "file:///Users/munjunho/Desktop/BC-project/web38-Froxy/node_modules/.pnpm/@[email protected][email protected]_@[email protected][email protected]_/node_modules/@vitejs/plugin-react-swc/index.mjs";
import { resolve } from "path";
import { defineConfig } from "file:///Users/munjunho/Desktop/BC-project/web38-Froxy/node_modules/.pnpm/[email protected]_@[email protected][email protected]/node_modules/vite/dist/node/index.js";
import dts from "file:///Users/munjunho/Desktop/BC-project/web38-Froxy/node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected][email protected]_@[email protected][email protected]_/node_modules/vite-plugin-dts/dist/index.mjs";
import tsconfigPaths from "file:///Users/munjunho/Desktop/BC-project/web38-Froxy/node_modules/.pnpm/[email protected][email protected][email protected]_@[email protected][email protected]_/node_modules/vite-tsconfig-paths/dist/index.js";
var __vite_injected_original_dirname = "/Users/munjunho/Desktop/BC-project/web38-Froxy/packages/react-markdown";
var vite_config_default = defineConfig({
base: "./",
test: {
globals: true,
environment: "jsdom",
setupFiles: ["./src/test/setupTests.ts"]
},
resolve: {
alias: {
"@": resolve(__vite_injected_original_dirname, "./src")
}
},
build: {
lib: {
entry: resolve(__vite_injected_original_dirname, "src/index.ts"),
name: "@froxy/react-markdown",
formats: ["es"],
// 포맷 추가
fileName: (format) => `index.${format}.js`
// 포맷별 파일명
},
rollupOptions: {
external: ["react", "react-dom"],
output: {
globals: {
react: "React",
"react-dom": "ReactDOM"
},
exports: "named",
// named exports 설정
chunkFileNames: "chunks/[name].js",
assetFileNames: "assets/[name].[ext]",
entryFileNames: "[name].js",
manualChunks: void 0,
inlineDynamicImports: false
}
}
},
plugins: [
react(),
tsconfigPaths(),
dts({
tsconfigPath: "./tsconfig.app.json",
include: ["src"],
rollupTypes: true
// 타입 번들링
})
]
});
export {
vite_config_default as default
};
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCIvVXNlcnMvbXVuanVuaG8vRGVza3RvcC9CQy1wcm9qZWN0L3dlYjM4LUZyb3h5L3BhY2thZ2VzL3JlYWN0LW1hcmtkb3duXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ZpbGVuYW1lID0gXCIvVXNlcnMvbXVuanVuaG8vRGVza3RvcC9CQy1wcm9qZWN0L3dlYjM4LUZyb3h5L3BhY2thZ2VzL3JlYWN0LW1hcmtkb3duL3ZpdGUuY29uZmlnLnRzXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ltcG9ydF9tZXRhX3VybCA9IFwiZmlsZTovLy9Vc2Vycy9tdW5qdW5oby9EZXNrdG9wL0JDLXByb2plY3Qvd2ViMzgtRnJveHkvcGFja2FnZXMvcmVhY3QtbWFya2Rvd24vdml0ZS5jb25maWcudHNcIjsvLy8gPHJlZmVyZW5jZSB0eXBlcz1cInZpdGVzdFwiIC8+XG5cbmltcG9ydCByZWFjdCBmcm9tICdAdml0ZWpzL3BsdWdpbi1yZWFjdC1zd2MnO1xuaW1wb3J0IHsgcmVzb2x2ZSB9IGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSAndml0ZSc7XG5pbXBvcnQgZHRzIGZyb20gJ3ZpdGUtcGx1Z2luLWR0cyc7XG5pbXBvcnQgdHNjb25maWdQYXRocyBmcm9tICd2aXRlLXRzY29uZmlnLXBhdGhzJztcblxuLy8gaHR0cHM6Ly92aXRlLmRldi9jb25maWcvXG5leHBvcnQgZGVmYXVsdCBkZWZpbmVDb25maWcoe1xuICBiYXNlOiAnLi8nLFxuICB0ZXN0OiB7XG4gICAgZ2xvYmFsczogdHJ1ZSxcbiAgICBlbnZpcm9ubWVudDogJ2pzZG9tJyxcbiAgICBzZXR1cEZpbGVzOiBbJy4vc3JjL3Rlc3Qvc2V0dXBUZXN0cy50cyddXG4gIH0sXG4gIHJlc29sdmU6IHtcbiAgICBhbGlhczoge1xuICAgICAgJ0AnOiByZXNvbHZlKF9fZGlybmFtZSwgJy4vc3JjJylcbiAgICB9XG4gIH0sXG4gIGJ1aWxkOiB7XG4gICAgbGliOiB7XG4gICAgICBlbnRyeTogcmVzb2x2ZShfX2Rpcm5hbWUsICdzcmMvaW5kZXgudHMnKSxcbiAgICAgIG5hbWU6ICdAZnJveHkvcmVhY3QtbWFya2Rvd24nLFxuICAgICAgZm9ybWF0czogWydlcyddLCAvLyBcdUQzRUNcdUI5RjcgXHVDRDk0XHVBQzAwXG4gICAgICBmaWxlTmFtZTogKGZvcm1hdCkgPT4gYGluZGV4LiR7Zm9ybWF0fS5qc2AgLy8gXHVEM0VDXHVCOUY3XHVCQ0M0IFx1RDMwQ1x1Qzc3Q1x1QkE4NVxuICAgIH0sXG4gICAgcm9sbHVwT3B0aW9uczoge1xuICAgICAgZXh0ZXJuYWw6IFsncmVhY3QnLCAncmVhY3QtZG9tJ10sXG4gICAgICBvdXRwdXQ6IHtcbiAgICAgICAgZ2xvYmFsczoge1xuICAgICAgICAgIHJlYWN0OiAnUmVhY3QnLFxuICAgICAgICAgICdyZWFjdC1kb20nOiAnUmVhY3RET00nXG4gICAgICAgIH0sXG4gICAgICAgIGV4cG9ydHM6ICduYW1lZCcsIC8vIG5hbWVkIGV4cG9ydHMgXHVDMTI0XHVDODE1XG4gICAgICAgIGNodW5rRmlsZU5hbWVzOiAnY2h1bmtzL1tuYW1lXS5qcycsXG4gICAgICAgIGFzc2V0RmlsZU5hbWVzOiAnYXNzZXRzL1tuYW1lXS5bZXh0XScsXG4gICAgICAgIGVudHJ5RmlsZU5hbWVzOiAnW25hbWVdLmpzJyxcbiAgICAgICAgbWFudWFsQ2h1bmtzOiB1bmRlZmluZWQsXG4gICAgICAgIGlubGluZUR5bmFtaWNJbXBvcnRzOiBmYWxzZVxuICAgICAgfVxuICAgIH1cbiAgfSxcblxuICBwbHVnaW5zOiBbXG4gICAgcmVhY3QoKSxcbiAgICB0c2NvbmZpZ1BhdGhzKCksXG4gICAgZHRzKHtcbiAgICAgIHRzY29uZmlnUGF0aDogJy4vdHNjb25maWcuYXBwLmpzb24nLFxuICAgICAgaW5jbHVkZTogWydzcmMnXSxcbiAgICAgIHJvbGx1cFR5cGVzOiB0cnVlIC8vIFx1RDBDMFx1Qzc4NSBcdUJDODhcdUI0RTRcdUI5QzFcbiAgICB9KVxuICBdXG59KTtcbiJdLAogICJtYXBwaW5ncyI6ICI7QUFFQSxPQUFPLFdBQVc7QUFDbEIsU0FBUyxlQUFlO0FBQ3hCLFNBQVMsb0JBQW9CO0FBQzdCLE9BQU8sU0FBUztBQUNoQixPQUFPLG1CQUFtQjtBQU4xQixJQUFNLG1DQUFtQztBQVN6QyxJQUFPLHNCQUFRLGFBQWE7QUFBQSxFQUMxQixNQUFNO0FBQUEsRUFDTixNQUFNO0FBQUEsSUFDSixTQUFTO0FBQUEsSUFDVCxhQUFhO0FBQUEsSUFDYixZQUFZLENBQUMsMEJBQTBCO0FBQUEsRUFDekM7QUFBQSxFQUNBLFNBQVM7QUFBQSxJQUNQLE9BQU87QUFBQSxNQUNMLEtBQUssUUFBUSxrQ0FBVyxPQUFPO0FBQUEsSUFDakM7QUFBQSxFQUNGO0FBQUEsRUFDQSxPQUFPO0FBQUEsSUFDTCxLQUFLO0FBQUEsTUFDSCxPQUFPLFFBQVEsa0NBQVcsY0FBYztBQUFBLE1BQ3hDLE1BQU07QUFBQSxNQUNOLFNBQVMsQ0FBQyxJQUFJO0FBQUE7QUFBQSxNQUNkLFVBQVUsQ0FBQyxXQUFXLFNBQVMsTUFBTTtBQUFBO0FBQUEsSUFDdkM7QUFBQSxJQUNBLGVBQWU7QUFBQSxNQUNiLFVBQVUsQ0FBQyxTQUFTLFdBQVc7QUFBQSxNQUMvQixRQUFRO0FBQUEsUUFDTixTQUFTO0FBQUEsVUFDUCxPQUFPO0FBQUEsVUFDUCxhQUFhO0FBQUEsUUFDZjtBQUFBLFFBQ0EsU0FBUztBQUFBO0FBQUEsUUFDVCxnQkFBZ0I7QUFBQSxRQUNoQixnQkFBZ0I7QUFBQSxRQUNoQixnQkFBZ0I7QUFBQSxRQUNoQixjQUFjO0FBQUEsUUFDZCxzQkFBc0I7QUFBQSxNQUN4QjtBQUFBLElBQ0Y7QUFBQSxFQUNGO0FBQUEsRUFFQSxTQUFTO0FBQUEsSUFDUCxNQUFNO0FBQUEsSUFDTixjQUFjO0FBQUEsSUFDZCxJQUFJO0FBQUEsTUFDRixjQUFjO0FBQUEsTUFDZCxTQUFTLENBQUMsS0FBSztBQUFBLE1BQ2YsYUFBYTtBQUFBO0FBQUEsSUFDZixDQUFDO0FBQUEsRUFDSDtBQUNGLENBQUM7IiwKICAibmFtZXMiOiBbXQp9Cg==
Loading
Loading