Skip to content

Commit

Permalink
chore: decoupling
Browse files Browse the repository at this point in the history
  • Loading branch information
cybersokari committed Dec 6, 2024
1 parent 5c00492 commit 76aa222
Show file tree
Hide file tree
Showing 11 changed files with 57 additions and 33 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/deploy.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Docker hub
name: Build & deploy
on:
push:
tags:
Expand Down
18 changes: 16 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
<a href="https://allurereport.org/docs/">
<img id="allure" src="assets/allure-logo.png" alt="Allure Logo" height="150">
</a>
<a href="https://docs.docker.com/">
<img id="docker" src="assets/docker-logo.png" alt="Docker Logo" height="150">
</a>
<a href="https://firebase.google.com/docs">
<img id="firebase" src="assets/firebase-logo.png" alt="Firebase Logo" height="150">
</a>

# Allure Docker Deploy

---

![Deployment](https://github.com/cybersokari/allure-docker-deploy/actions/workflows/deploy.yaml/badge.svg?branch=main)
![](https://img.shields.io/docker/pulls/sokari/allure-docker-deploy)
# Allure Docker Deploy
_An easy-to-use Docker solution for sharing and backing up Allure test reports_

_An easy-to-use serverless Docker solution for sharing and backing up Allure test reports_

This [Docker image](https://hub.docker.com/r/sokari/allure-docker-deploy) lets you share [Allure test reports](https://allurereport.org/) seamlessly via an ephemeral URL. It also backs up all report history and retries to Firebase Cloud Storage, enabling unique URLs for each test run and previewing previous reports.

Expand Down
Binary file added assets/allure-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/docker-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/firebase-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion worker/app/cloud-storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export class CloudStorage {
validation: process.env.DEBUG !== 'true',
destination: `${storageHomeDir}/${destinationFilePath}`,
});
counter.incrementFilesUploaded()
await counter.incrementFilesUploaded()
} catch (error) {
console.error(`Failed to upload ${filePath}:`, error);
}
Expand Down
18 changes: 14 additions & 4 deletions worker/app/counter.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
import { Mutex } from 'async-mutex';
class Counter {
private startTime: number | null = null;
private processed = 0
private uploaded = 0

incrementFilesProcessed() {
this.processed ++
// Mutex for protecting critical sections
private mutex = new Mutex();

async incrementFilesProcessed(): Promise<void> {
await this.mutex.runExclusive(() => {
this.processed++;
});
}
incrementFilesUploaded() {
this.uploaded++

async incrementFilesUploaded(): Promise<void> {
await this.mutex.runExclusive(() => {
this.uploaded++;
});
}

get filesUploaded(){
return this.uploaded
}
Expand Down
28 changes: 15 additions & 13 deletions worker/app/report-builder.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {REPORTS_DIR, STAGING_PATH} from "../index";

const allure = require('allure-commandline')
import {deploy} from "./site-builder";
import {changePermissionsRecursively, createFirebaseJson, publishToFireBaseHosting} from "./site-builder";
import * as path from "node:path";
import * as fs from 'fs/promises'
import counter from "./counter";
Expand All @@ -17,10 +17,13 @@ class ReportBuilder {

public setTtl() {
clearTimeout(this.timeOut)
this.timeOut = setTimeout(this.generateAndHost, this.ttl * 1000)
this.timeOut = setTimeout(async () => {
await this.generate()
return await this.host()
}, this.ttl * 1000)
}

public async generateAndHost() {
public async generate() {

// History files can exist in reports directory in WATCH_MODE
// due to multiple call to generateAndHost, so we try to move
Expand Down Expand Up @@ -53,7 +56,7 @@ class ReportBuilder {
let success = false
await new Promise((resolve, reject) => {
generation.on('exit', async function (exitCode: number) {
success = exitCode == 0
success = exitCode === 0
if (success) {
resolve('success')
} else {
Expand All @@ -62,14 +65,6 @@ class ReportBuilder {
}
})
})
if (success){
try {
return await deploy()
} catch (e) {
console.log(`Hosting deployment failed: ${e}`)
}
}
return null
}

// Move from '/allure-results' mount to staging
Expand All @@ -79,7 +74,7 @@ class ReportBuilder {
const destinationFilePath = path.join(STAGING_PATH, path.basename(file));
await fs.mkdir(path.dirname(destinationFilePath), {recursive: true});// recursive, don't throw
await fs.copyFile(file, destinationFilePath);
counter.incrementFilesProcessed()
await counter.incrementFilesProcessed()
} catch (e) {
console.warn(`Failed to move ${path.basename(file)} to staging area: ${e}`)
}
Expand All @@ -88,6 +83,13 @@ class ReportBuilder {
return this
}

public async host() {
await createFirebaseJson()
// Grant execution permission to website files
await changePermissionsRecursively(REPORTS_DIR, 0o755)
return await publishToFireBaseHosting()
}

}

export default new ReportBuilder()
12 changes: 3 additions & 9 deletions worker/app/site-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import counter from "./counter";

const exec = util.promisify(require('child_process').exec)

async function createFirebaseJson() {
export async function createFirebaseJson() {
const hosting = {
"hosting": {
"public": ".",
Expand All @@ -30,7 +30,7 @@ async function createFirebaseJson() {
}
}

async function changePermissionsRecursively(dirPath: string, mode: fsSync.Mode) {
export async function changePermissionsRecursively(dirPath: string, mode: fsSync.Mode) {
await fs.chmod(dirPath, mode);

const files = await fs.readdir(dirPath);
Expand All @@ -47,7 +47,7 @@ async function changePermissionsRecursively(dirPath: string, mode: fsSync.Mode)
}
}

async function publishToFireBaseHosting() {
export async function publishToFireBaseHosting() {
if (process.env.DEBUG === 'true') {
console.warn('DEBUG=true: Skipping live deployment')
return
Expand Down Expand Up @@ -118,12 +118,6 @@ export function writeGitHubSummary({summaryPath = '', url = ''}) {
}
}

export async function deploy() {
await createFirebaseJson()
// Grant execution permission to website files
await changePermissionsRecursively(REPORTS_DIR, 0o755)
return await publishToFireBaseHosting()
}



7 changes: 5 additions & 2 deletions worker/app/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,19 @@ export async function getAllFiles(dirPath: string): Promise<string[]> {
export function validateWebsiteExpires(expires: string): boolean {
// Check if input is empty
if (!expires) {
console.error('Error: WEBSITE_EXPIRES cannot be empty');
return false;
}

if(expires.trim().length > 3){
return false;
}


// Regex to validate format: number followed by h/d/w
const validFormatRegex = /^(\d+)([hdw])$/;
const match = expires.match(validFormatRegex);

if (!match) {
console.error('Error: Invalid WEBSITE_EXPIRES format. Use format like 12h, 7d, or 2w');
return false;
}

Expand Down
3 changes: 2 additions & 1 deletion worker/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ function main(): void {
ReportBuilder.stageFiles(await getAllFiles(MOUNTED_PATH)),
cloudStorage?.stageRemoteFiles()
])
const url = await ReportBuilder.generateAndHost()
await ReportBuilder.generate()
const url = await ReportBuilder.host()
if(keepHistory){
await cloudStorage?.uploadHistory()
}
Expand Down

0 comments on commit 76aa222

Please sign in to comment.