Merge remote-tracking branch 'origin/main' into feat/agent

This commit is contained in:
Nevo David 2025-10-16 22:29:58 +07:00
commit c75df52bd0
10 changed files with 346 additions and 74 deletions

View File

@ -3,7 +3,6 @@ name: Build
on:
push:
pull_request:
jobs:
build:
@ -17,6 +16,9 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
@ -48,3 +50,20 @@ jobs:
- name: Build
run: pnpm run build
- name: Get Commit SHA (short)
id: get_version
run: |
# Get the short 8-character commit SHA
VERSION=$(git rev-parse --short=8 HEAD)
echo "Commit SHA is $VERSION"
echo "tag=$VERSION" >> $GITHUB_OUTPUT
- name: SonarQube Analysis (Branch)
uses: SonarSource/sonarqube-scan-action@v6
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
with:
args: >
-Dsonar.projectVersion=${{ steps.get_version.outputs.tag }}

71
.github/workflows/build-pr vendored Normal file
View File

@ -0,0 +1,71 @@
---
name: Build
on:
pull_request:
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: ['20.17.0']
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
environment:
name: build-pr
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: 8
run_install: false
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- name: Setup pnpm cache
uses: actions/cache@v4
with:
path: |
${{ env.STORE_PATH }}
${{ github.workspace }}/.next/cache
key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ hashFiles('**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx') }}
restore-keys: |
${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}-
- name: Install dependencies
run: pnpm install
- name: Build
run: pnpm run build
- name: Get Commit SHA (short)
id: get_version
run: |
# Get the short 8-character commit SHA
VERSION=$(git rev-parse --short=8 HEAD)
echo "Commit SHA is $VERSION"
echo "tag=$VERSION" >> $GITHUB_OUTPUT
- name: SonarQube Analysis (Pull Request)
uses: SonarSource/sonarqube-scan-action@v6
with:
args: >
-Dsonar.projectVersion=${{ steps.get_version.outputs.tag }}
-Dsonar.pullrequest.key=${{ github.event.pull_request.number }}
-Dsonar.pullrequest.branch=${{ github.event.pull_request.head.ref }}
-Dsonar.pullrequest.base=${{ github.event.pull_request.base.ref }}

View File

@ -9,10 +9,16 @@ permissions: write-all
jobs:
build-and-publish:
runs-on: ubuntu-latest
environment:
name: build-pr
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3

96
Jenkins/Build.Jenkinsfile Normal file
View File

@ -0,0 +1,96 @@
// Declarative Pipeline for building Node.js application and running SonarQube analysis triggered by a push event.
pipeline {
// Defines the execution environment. Using 'agent any' to ensure an agent is available.
agent any
// Global environment block removed to prevent Groovy scoping issues with manual path calculation.
stages {
// Stage 1: Checkout the code (Relies on the initial SCM checkout done by Jenkins)
stage('Source Checkout') {
steps {
echo "Workspace already populated by the initial SCM checkout. Proceeding."
}
}
// Stage 2: Setup Node.js v20 and install pnpm
stage('Setup Environment and Tools') {
steps {
sh '''
echo "Ensuring required utilities and Node.js are installed..."
sudo apt-get update
sudo apt-get install -y curl unzip nodejs
# 1. Install Node.js v20
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs
echo "Node.js version: \$(node -v)"
# 2. Install pnpm globally (version 8)
npm install -g pnpm@8
echo "pnpm version: \$(pnpm -v)"
'''
}
}
// Stage 3: Install dependencies and build the application
stage('Install and Build') {
steps {
sh 'pnpm install'
sh 'pnpm run build'
}
}
// Stage 4: Run SonarQube analysis: Install scanner, get version, and execute.
stage('SonarQube Analysis') {
steps {
script {
// 1. Get the short 8-character commit SHA for project versioning
def commitShaShort = sh(returnStdout: true, script: 'git rev-parse --short=8 HEAD').trim()
echo "Commit SHA (short) is: ${commitShaShort}"
// --- 2. MANUALLY INSTALL THE SONAR SCANNER CLI LOCALLY IN THIS STAGE ---
sh """
echo "Manually downloading and installing Sonar Scanner CLI..."
# Download the stable scanner CLI package
curl -sS -o sonar-scanner.zip \
"https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.7.0.2747.zip"
# Added -o flag to force overwrite and prevent interactive prompt failure
unzip -o -q sonar-scanner.zip -d .
"""
// 3. Find the extracted directory name and capture the full absolute bin path in Groovy
// This is defined locally and used directly, avoiding environment variable issues.
def scannerBinPath = sh(
returnStdout: true,
script: '''
SCANNER_DIR=$(find . -maxdepth 1 -type d -name "sonar-scanner*" | head -n 1)
# Get the full absolute path to the executable file
echo \$(pwd)/\${SCANNER_DIR}/bin/sonar-scanner
'''
).trim()
echo "Scanner executable path captured: ${scannerBinPath}"
// 4. Use withSonarQubeEnv to set up the secure variables (HOST and TOKEN)
withSonarQubeEnv(installationName: 'SonarQube-Server') {
// 5. Execute the scanner using the Groovy variable directly.
sh """
echo "Starting SonarQube Analysis for project version: ${commitShaShort}"
# Execute the full, absolute path captured in the Groovy variable.
'${scannerBinPath}' \\
-Dsonar.projectVersion=${commitShaShort} \\
-Dsonar.sources=.
# SONAR_HOST_URL and SONAR_TOKEN are automatically passed as environment variables
# by the withSonarQubeEnv block.
"""
}
}
}
}
}
}

100
Jenkins/BuildPR.Jenkinsfile Normal file
View File

@ -0,0 +1,100 @@
// Declarative Pipeline for building Node.js application and running SonarQube analysis for a Pull Request.
pipeline {
// Defines the execution environment. Using 'agent any' to ensure an agent is available.
agent any
// Environment variables that hold PR details, provided by Jenkins Multibranch setup.
environment {
// FIX: Environment variables must be quoted or wrapped in a function call.
// We quote the 'env.CHANGE_ID' reference to fix the compilation error.
PR_KEY = "${env.CHANGE_ID}"
PR_BRANCH = "${env.CHANGE_BRANCH}"
PR_BASE = "${env.CHANGE_TARGET}"
}
stages {
// Stage 1: Checkout the code (Relies on the initial SCM checkout done by Jenkins)
stage('Source Checkout') {
steps {
echo "Workspace already populated by the initial SCM checkout. Proceeding."
}
}
// Stage 2: Setup Node.js v20, install pnpm, and install required tools (curl, unzip)
stage('Setup Environment and Tools') {
steps {
sh '''
echo "Ensuring required utilities and Node.js are installed..."
sudo apt-get update
sudo apt-get install -y curl unzip nodejs
# 1. Install Node.js v20 (closest matching the specified version '20.17.0')
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs
echo "Node.js version: \$(node -v)"
# 2. Install pnpm globally (version 8)
npm install -g pnpm@8
echo "pnpm version: \$(pnpm -v)"
'''
}
}
// Stage 3: Install dependencies and build the application
stage('Install and Build') {
steps {
sh 'pnpm install'
sh 'pnpm run build'
}
}
// Stage 4: Run SonarQube PR analysis: Install scanner locally, get version, and execute.
stage('SonarQube Pull Request Analysis') {
steps {
script {
// 1. Get the short 8-character commit SHA for project versioning
def commitShaShort = sh(returnStdout: true, script: 'git rev-parse --short=8 HEAD').trim()
echo "Commit SHA (short) is: ${commitShaShort}"
// --- 2. MANUALLY INSTALL THE SONAR SCANNER CLI LOCALLY ---
sh """
echo "Manually downloading and installing Sonar Scanner CLI..."
curl -sS -o sonar-scanner.zip \
"https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.7.0.2747.zip"
unzip -o -q sonar-scanner.zip -d .
"""
// 3. Find the extracted directory name and capture the full absolute executable path.
def scannerBinPath = sh(
returnStdout: true,
script: '''
SCANNER_DIR=$(find . -maxdepth 1 -type d -name "sonar-scanner*" | head -n 1)
# Get the full absolute path to the executable file
echo \$(pwd)/\${SCANNER_DIR}/bin/sonar-scanner
'''
).trim()
echo "Scanner executable path captured: ${scannerBinPath}"
// 4. Use withSonarQubeEnv to set up the secure variables (HOST and TOKEN)
withSonarQubeEnv(installationName: 'SonarQube-Server') {
// 5. Execute the scanner using the Groovy variable directly with PR parameters.
sh """
echo "Starting SonarQube Pull Request Analysis for PR #${PR_KEY}"
'${scannerBinPath}' \\
-Dsonar.projectVersion=${commitShaShort} \\
-Dsonar.sources=. \\
-Dsonar.pullrequest.key=${PR_KEY} \\
-Dsonar.pullrequest.branch=${PR_BRANCH} \\
-Dsonar.pullrequest.base=${PR_BASE}
# SONAR_HOST_URL and SONAR_TOKEN are automatically passed as environment variables
# by the withSonarQubeEnv block.
"""
}
}
}
}
}
}

70
Jenkinsfile vendored
View File

@ -1,70 +0,0 @@
pipeline {
agent any
environment {
NODE_VERSION = '20.17.0'
PR_NUMBER = "${env.CHANGE_ID}" // PR number comes from webhook payload
IMAGE_TAG="ghcr.io/gitroomhq/postiz-app-pr:${env.CHANGE_ID}"
}
stages {
stage('Checkout Repository') {
steps {
checkout scm
}
}
stage('Check Node.js and npm') {
steps {
script {
sh "node -v"
sh "npm -v"
}
}
}
stage('Install Dependencies') {
steps {
sh 'npm ci'
}
}
stage('Build Project') {
steps {
sh 'npm run build'
}
}
stage('Build and Push Docker Image') {
when {
expression { return env.CHANGE_ID != null } // Only run if it's a PR
}
steps {
withCredentials([string(credentialsId: 'gh-pat', variable: 'GITHUB_PASS')]) {
// Docker login step
sh '''
echo "$GITHUB_PASS" | docker login ghcr.io -u "egelhaus" --password-stdin
'''
// Build Docker image
sh '''
docker build -f Dockerfile.dev -t $IMAGE_TAG .
'''
// Push Docker image to GitHub Container Registry
sh '''
docker push $IMAGE_TAG
'''
}
}
}
}
post {
success {
echo 'Build completed successfully!'
}
failure {
echo 'Build failed!'
}
}
}

View File

@ -26,6 +26,9 @@ import {
} from '@gitroom/backend/services/auth/permissions/permission.exception.class';
import { VideoDto } from '@gitroom/nestjs-libraries/dtos/videos/video.dto';
import { VideoFunctionDto } from '@gitroom/nestjs-libraries/dtos/videos/video.function.dto';
import { UploadDto } from '@gitroom/nestjs-libraries/dtos/media/upload.dto';
import axios from 'axios';
import { Readable } from 'stream';
@ApiTags('Public API')
@Controller('/public/v1')
@ -56,6 +59,37 @@ export class PublicIntegrationsController {
);
}
@Post('/upload-from-url')
async uploadFromUrl(
@GetOrgFromRequest() org: Organization,
@Body() body: UploadDto
) {
const response = await axios.get(body.url, {
responseType: 'arraybuffer',
});
const buffer = Buffer.from(response.data);
const getFile = await this.storage.uploadFile({
buffer,
mimetype: 'image/jpeg',
size: buffer.length,
path: '',
fieldname: '',
destination: '',
stream: new Readable(),
filename: '',
originalname: '',
encoding: '',
});
return this._mediaService.saveFile(
org.id,
getFile.originalname,
getFile.path
);
}
@Get('/find-slot/:id')
async findSlotIntegration(
@GetOrgFromRequest() org: Organization,

View File

@ -0,0 +1,9 @@
import { IsDefined, IsString, Validate } from 'class-validator';
import { ValidUrlExtension } from '@gitroom/helpers/utils/valid.url.path';
export class UploadDto {
@IsString()
@IsDefined()
@Validate(ValidUrlExtension)
url: string;
}

View File

@ -16,8 +16,8 @@ export const initializeSentryClient = (environment: string, dsn: string) =>
autoInject: false,
}),
],
replaysSessionSampleRate: environment === 'development' ? 1.0 : 0.5,
replaysSessionSampleRate: 1.0,
replaysOnErrorSampleRate: 1.0,
profilesSampleRate: environment === 'development' ? 1.0 : 0.45,
profilesSampleRate: environment === 'development' ? 1.0 : 0.75,
});

7
sonar-project.properties Normal file
View File

@ -0,0 +1,7 @@
sonar.projectKey=gitroomhq_postiz-app_bd4cd369-af44-4d19-903b-c4bdb0b66022
sonar.projectName=Postiz App
sonar.projectDescription=An Open-Source Social Media Scheduler
# Scan Performace
sonar.javascript.node.maxspace=24576
sonar.exclusions=**/node_modules/**,**/dist/**,**/build/**,**/coverage/**,**/*.spec.ts,**/*.test.ts,*.png