Last active
October 21, 2023 13:22
-
-
Save yus-ham/625bca92e4a5e3dd236dedae6b2df362 to your computer and use it in GitHub Desktop.
Auto pull by webhooks
This file contains hidden or 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
<?php | |
$CI_SECRET = 'xxxxx'; | |
$BASE_DIR = '/var/www/html/'; | |
$_SERVER['REQUEST_METHOD'] === 'POST' OR die(header('HTTP/1.1 405').'#METHOD_NOT_ALLOWED'); | |
$data = file_get_contents('php://input'); | |
$sign = substr($_SERVER['HTTP_X_HUB_SIGNATURE_256'] ??null, 7) OR die(header('HTTP/1.1 400').'#SIGNATURE'); | |
$host_sign = hash_hmac('sha256', $data, $CI_SECRET); | |
hash_equals($host_sign, $sign) OR die(header('HTTP/1.1 401 #INVALID_SIGNATURE')); | |
$data = json_decode($data); | |
header('Content-Type: text/plain'); | |
$branch = trim(explode('/', $data->ref)[2]); | |
$project = preg_replace('/\'"|\.\./', '', $branch ?: $data->repository->name); | |
chdir($BASE_DIR.$project); | |
$host_branch = trim(explode('/', file_get_contents("$BASE_DIR$project/.git/HEAD"))[2]); | |
$remote = parse_ini_file("$BASE_DIR$project/.git/config", $section=true)["branch $host_branch"]["remote"]; | |
if ($host_branch !== $branch) { | |
echo 'Branch not matched, Skip!'; | |
} else { | |
foreach ([ | |
"git fetch $remote $branch", | |
"git merge $remote/$branch --no-edit", | |
"composer --no-interaction --prefer-dist -o i", | |
"php yii migrate --interactive=0", | |
] as $cmd) { | |
$result = null; | |
print "\n$cmd\n"; | |
passthru($cmd, $result); | |
$result and print "Exit code: $result\n"; | |
} | |
} | |
echo "\n\ngit status\n"; | |
system("git status"); | |
echo "git log\n"; | |
exec("git log -n 5", $output); | |
$commit = null; | |
foreach ((array)$output as $line) { | |
if (trim($line)) { | |
if (strpos($line, 'commit ') === 0) { | |
$commit and print_r($commit); | |
$commit = [$line]; | |
} | |
else $commit[] = $line; | |
} | |
} | |
$commit and print_r($commit); |
This file contains hidden or 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
import { appendFileSync } from 'fs' | |
import { basename } from 'path' | |
const VALIDATE = true | |
const TEST_PROJECT = 'press' | |
const BASE_DIR = '/var/www/html/' | |
const TOKEN = '!Xxx123' | |
const REMOTE = 'origin' | |
const projects = { | |
'press': { | |
branch: 'main', | |
logFile: `/var/www/html/press-git/frontpage/ci/status.html`, | |
directory: 'press-git', | |
env: { | |
//BUILD_OUTDIR: 'dist/portal', | |
API_URL: '/press-dev/app-api/web', | |
BASE_URL: '/press-dev/adminpanel', | |
}, | |
extra_commands: [ | |
`bun install`, | |
(p) => { | |
const out = `[${date()}] Build started ...\n\n` | |
appendFileSync(p.logFileTxt, out) | |
appendFileSync(p.logFile, `${nl2br(out)}\n`) | |
}, | |
{ cmd: `bun vite build -l error`, isSuccess: o => !o.match(/Found \d+ errors? in/) }, | |
(p) => { | |
const out = `[${date()}] CI finished with status: Success\n` | |
appendFileSync(p.logFileTxt, out) | |
appendFileSync(p.logFile, out) | |
console.info(out) | |
}, | |
] | |
}, | |
/*'portal-be': { | |
env: {}, | |
branch: 'develop', | |
pm2_proc_name: 'portal-be.3001', | |
logFile: `/var/www/html/portal/ci-status-be.html`, | |
extra_commands: [ | |
(p, out) => { | |
spawnProcess(`pm2 restart 12 --update-env`, p) | |
const proc = spawnProcess(`pm2 jlist`, p) | |
for (const pm2_proc of JSON.parse(proc.stdout.toString())) { | |
if (pm2_proc.name === p.pm2_proc_name && pm2_proc.pid) { | |
out = `[${date()}] CI finished with status: Success\n` | |
appendFileSync(p.logFileTxt, out) | |
appendFileSync(p.logFile, out) | |
console.info(out) | |
return | |
} | |
} | |
out = `[${date()}] CI finished with status: Failed\n` | |
appendFileSync(p.logFileTxt, out) | |
appendFileSync(p.logFile, out) | |
console.error(out) | |
}, | |
] | |
},*/ | |
} | |
// start ci-gitlab with pm2 id for portal-be | |
// pm2 start <ci-gitlab> -f --interpreter-args -- pm2-id <portal-be>=<0> | |
let isPm2Id | |
for (let item of (process.argv || [])) { | |
if (isPm2Id) { | |
item = item.split('=').map(x => x.trim()) | |
if (item[0] && projects[item[0]]) { | |
projects[item[0]].pm2_id = item[1] | |
} | |
isPm2Id = false | |
continue | |
} | |
if (item.startsWith('pm2-id')) { | |
isPm2Id = true | |
} | |
} | |
const server = Bun.serve({ | |
port: 9000, | |
async fetch(req, p) { | |
//console.info({req}) | |
try { | |
p = await getProject(req) | |
Bun.sleep(1).then(_ => startCI(p)) | |
} catch (e) { | |
console.error(e) | |
return new Response(e.message, e) | |
} | |
return new Response('OK\n\nCheck CI logs at: https://localhost/ci/' + basename(p.logFile)) | |
} | |
}) | |
console.info(`Webhook server started on http://${server.hostname}:${server.port}`) | |
async function getProject(req) { | |
const config = new URLSearchParams(req.headers.get('x-gitlab-token')) | |
if (VALIDATE && !config.get('token')) | |
throw { message: 'No Token', status: 401 } | |
if (VALIDATE && config.get('token') !== TOKEN) | |
throw { message: 'Invalid Token', status: 422 } | |
const params = VALIDATE ? await req.json() : {} | |
const push_branch = params.ref?.split('/')[2] | |
const project_name = params.project?.path_with_namespace.split('/')[1] || TEST_PROJECT | |
const project = projects[project_name] || {} | |
if (VALIDATE && project.is_running) | |
throw {message: 'Already running', status: 419 } | |
if (VALIDATE && push_branch !== project.branch) | |
throw { message: 'Invalid branch', status: 422 } | |
project.name = project_name | |
project.is_running = true | |
project.logFileTxt = project.logFile.replace(/\.html$/, '.txt') | |
return project | |
} | |
async function startCI(project, log) { | |
await Bun.write(project.logFileTxt, (log = `[${date()}] CI started ...`) + `\n\n`) | |
await Bun.write(project.logFile, `<!doctype html><body style="font-family:monospace">\n${log}<br><br>\n`) | |
const opts = { | |
stdout: 'pipe', | |
stderr: 'pipe', | |
env: { ...Bun.env, ...project.env }, | |
cwd: BASE_DIR + (project.directory || project.name) | |
} | |
//console.info({opts}) | |
new Array( | |
(p) => console.info(`Project: ${p.name}`), | |
`git status`, | |
`git fetch ${REMOTE} ${project.branch}`, | |
`git merge ${REMOTE}/${project.branch} --no-edit`, | |
`git log -5`, | |
...project.extra_commands, | |
(p) => { | |
console.info(`---- END ------------------------------`) | |
p.is_running = false | |
}, | |
) | |
.reduceRight((_onExit, cmd) => { | |
const onExit = () => console.info(`---------------------------------------`) || _onExit() | |
return async () => { | |
if (typeof cmd === 'function') | |
return Promise.resolve().then(_ => cmd(project)).then(onExit) | |
if (!cmd.cmd) { | |
cmd = { cmd } | |
} | |
cmd.isSuccess = () => true | |
console.info(`CWD: ${opts.cwd}\nCMD: ${cmd.cmd}`) | |
const proc = spawnProcess(cmd.cmd, opts) | |
const err = proc.stderr.toString() | |
if (err) { | |
const _err = `[${date()}] ${err}` | |
appendFileSync(project.logFileTxt, _err + '\n\n') | |
appendFileSync(project.logFile, `<font color="#dc3545">${nl2br(_err)}</font><br><br>\n`) | |
} | |
let out = proc.stdout.toString() | |
if (proc.success && cmd.isSuccess(out)) { | |
out = `[${date()}] ${cmd.cmd}\n${out}\n\n` | |
appendFileSync(project.logFileTxt, out) | |
appendFileSync(project.logFile, nl2br(out) + '\n') | |
return onExit() | |
} | |
console.error(out) | |
appendFileSync(project.logFileTxt, out + '\n\n\n') | |
appendFileSync(project.logFile, `<font color="#dc3545">${nl2br(out)}</font><br><br>\n`) | |
out = `[${date()}] CI finished with status: Failed` | |
console.error(out) | |
appendFileSync(project.logFileTxt, out + '\n') | |
appendFileSync(project.logFile, `<font color="#dc3545">${out}</font>\n`) | |
project.is_running = false | |
} | |
})() | |
} | |
const nl2br = (o) => o.replace(/\n/g, '<br>\n') | |
const date = (d) => { d = new Date(); d.setHours(d.getHours() - 1); return d.toString().slice(0, 29) + '0700' } | |
const spawnProcess = (cmd, opts) => { opts.cwd || (opts.cwd = BASE_DIR + (opts.directory || opts.name)); return Bun.spawnSync(cmd.split(' '), { ...opts }) } |
This file contains hidden or 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
<?php | |
// usage token=Secret123&project_dir=project_name | |
$CI_SECRET = 'xxx'; | |
$BASE_DIR = '/var/www/html/'; | |
$_SERVER['REQUEST_METHOD'] === 'POST' OR die(header('HTTP/1.1 405').'#METHOD_NOT_ALLOWED'); | |
$token = $_SERVER['HTTP_X_GITLAB_TOKEN'] ??null; | |
$token OR die(header('HTTP/1.1 400').'#NO_TOKEN'); | |
$opts = []; | |
parse_str($token, $opts); | |
$opts['token'] === $CI_SECRET OR die(header('HTTP/1.1 400').'#INVALID_TOKEN'); | |
header('Content-Type: text/plain'); | |
$data = json_decode(file_get_contents('php://input')); | |
$project = preg_replace('/\'"|\.\./', '', ($opts['project_dir'] ??null) ?: explode('/',$data->project->path_with_namespace)[1]); | |
chdir($BASE_DIR.$project); | |
$branch = explode('/', $data->ref)[2]; | |
$host_branch = trim(explode('/', file_get_contents('.git/HEAD'))[2]); | |
$remote = parse_ini_file('.git/config', $section=true)["branch $host_branch"]["remote"]; | |
if ($host_branch != $branch) { | |
echo 'Branch not matched, Skip!'; | |
} else { | |
foreach ([ | |
"git fetch $remote $branch", | |
"git merge $remote/$branch --no-edit", | |
"composer --no-interaction --prefer-dist -o i", | |
"php yii migrate --interactive=0", | |
] as $cmd) { | |
$result = null; | |
print "\n$cmd\n"; | |
passthru($cmd, $result); | |
$result and print "Exit code: $result\n"; | |
} | |
} | |
echo "\n\ngit status\n"; | |
system("git status"); | |
echo "git log\n"; | |
exec("git log -n 5", $output); | |
$commit = null; | |
foreach ((array)$output as $line) { | |
if (trim($line)) { | |
if (strpos($line, 'commit ') === 0) { | |
$commit and print_r($commit); | |
$commit = [$line]; | |
} | |
else $commit[] = $line; | |
} | |
} | |
$commit and print_r($commit); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment