Skip to content
Open
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
43 changes: 38 additions & 5 deletions dashboard/builds.html
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,31 @@ <h2>FHIR IG Builds</h2>
})
}

const deleted = []
function deleteBranch(branchnum, org, repo, branch) {
if (deleted.includes(branchnum)) {
return;
}
if (!confirm(`Delete branch "${branch}" from ${org}/${repo}? This cannot be undone.`)) {
return;
}
deleted.push(branchnum)
document.getElementById(`delete-branch-${branchnum}`).classList.add("text-muted");
fetch("https://us-central1-fhir-org-starter-project.cloudfunctions.net/ig-commit-trigger", {
body: JSON.stringify({
"action": "delete",
"ref": `refs/heads/${branch}`,
"repository": {"full_name": `${org}/${repo}`}
}),
headers: {
'Content-Type': 'application/json'
},
method: 'POST',
referrer: 'no-referrer',
mode: 'cors'
})
}


function render({builds, qas}){
const sorter = (a, b) => {
Expand Down Expand Up @@ -252,14 +277,22 @@ <h2>FHIR IG Builds</h2>
<td sorttable_customkey="${date && date.toISOString() || '1900'}">
<a data-toggle="tooltip" title="${date && date.toISOString()}">${date ? timeFormatter.format(date) : "???"}</td>
<td><span class="badge pill-badge badge-${success ? "success" : "danger"}">${success ? "success" : "failure"}</span></td>
<td>
<div class="dropdown">
<button class="btn-sm btn-primary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Rebuild Branch
<td style="white-space: nowrap;">
<div class="dropdown" style="display:inline-block;">
<button class="btn-sm btn-primary dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Rebuild
</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<div class="dropdown-menu">
${choices.map(branch => `<a id="branch-${branchnum}" class="dropdown-item" onClick="rebuild(${branchnum++}, '${org}', '${repo}', '${branch.name}')">${branch.name + (branch.failing ? " [failing]" : "")}</a>`).join(`\n`)}
</div>
</div>
<div class="dropdown" style="display:inline-block;" data-toggle="tooltip" title="Delete a branch build">
<button class="btn-sm btn-primary dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
🗑
</button>
<div class="dropdown-menu">
${choices.map(branch => `<a id="delete-branch-${branchnum}" class="dropdown-item" onClick="deleteBranch(${branchnum++}, '${org}', '${repo}', '${branch.name}')">${branch.name}</a>`).join(`\n`)}
</div>
</div>
<a target="_blank" class="btn btn-primary btn-sm" href="https://build.fhir.org/ig/${org}/${repo}/branches/__default/${success ? "" : "failure/"}build.log">log</a>
<a target="_blank" class="btn btn-primary btn-sm" href="https://github.com/${org}/${repo}">gh</a>
Expand Down
5 changes: 3 additions & 2 deletions images/ci-build/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ RUN useradd -m -r -s /bin/bash fhir_upload && \

VOLUME /home/fhir_upload/uploading

ADD publish publish-ig reindex /home/fhir_upload/
RUN chown fhir_upload /home/fhir_upload/publish && chmod +x /home/fhir_upload/publish
ADD publish publish-ig reindex delete-branch /home/fhir_upload/
RUN chown fhir_upload /home/fhir_upload/publish /home/fhir_upload/delete-branch && \
chmod +x /home/fhir_upload/publish /home/fhir_upload/publish-ig /home/fhir_upload/reindex /home/fhir_upload/delete-branch

COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf

Expand Down
36 changes: 36 additions & 0 deletions images/ci-build/delete-branch
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/bin/bash

set -e

IG_ORG=$1
IG_REPO=$2
BRANCH=$3

if [ -z "$IG_ORG" ] || [ -z "$IG_REPO" ] || [ -z "$BRANCH" ]; then
echo "Usage: delete-branch ORG REPO BRANCH"
exit 1
fi

# Protect main branches from exempt orgs (but allow master to be deleted)
if [ "$BRANCH" = "main" ]; then
if [[ "$IG_ORG" =~ ^(HL7|FHIR|IHE|argonautproject)$ ]]; then
echo "Cannot delete protected main branch for $IG_ORG/$IG_REPO"
exit 1
fi
fi

TARGET_DIR=~/uploading/www/ig/$IG_ORG/$IG_REPO/branches/$BRANCH

if [ ! -d "$TARGET_DIR" ]; then
echo "Branch directory does not exist: $TARGET_DIR"
exit 0
fi

echo "Deleting branch: $IG_ORG/$IG_REPO/$BRANCH"
rm -rf "$TARGET_DIR"

# Trigger reindex
cd ~/reindex_queue
touch reindex_request_$(date --iso-8601=ns).sem

echo "Deleted and reindex triggered"
1 change: 1 addition & 0 deletions images/ig-publisher/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ RUN apt-get update && apt-get -y install inotify-tools python3 python3-pip pytho

ADD ./ci-files/watch-and-publish /usr/local/bin/watch-and-publish
ADD ./ci-files/publish /usr/local/bin/publish
ADD ./ci-files/delete /usr/local/bin/delete

RUN groupadd -r fhirgroup -g 2000 && \
useradd -r -u 1000 -g fhirgroup -m -d /home/fhiruser -s /sbin/nologin fhiruser && \
Expand Down
3 changes: 3 additions & 0 deletions images/ig-publisher/ci-files/delete
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash
echo "Delete branch $1/$2/$3"
ssh ci-build ./delete-branch "$@"
54 changes: 54 additions & 0 deletions triggers/ig-commit-trigger/delete-job.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"apiVersion": "batch/v1",
"kind": "Job",
"metadata": {
"labels": { },
"namespace": "fhir"
},
"spec": {
"activeDeadlineSeconds": 60,
"ttlSecondsAfterFinished": 30,
"template": {
"spec": {
"securityContext": {
"fsGroup": 2000,
"runAsGroup": 2000,
"runAsUser": 1000
},
"containers": [
{
"args": [],
"command": [
"/usr/local/bin/delete"
],
"env": [],
"image": "gcr.io/fhir-org-starter-project/ig-build",
"imagePullPolicy": "Always",
"name": "ig-delete",
"resources": {
"requests": {
"memory": "128Mi"
}
},
"volumeMounts": [
{
"mountPath": "/etc/ci_build_keys",
"name": "keys"
}
]
}
],
"restartPolicy": "Never",
"volumes": [
{
"name": "keys",
"secret": {
"defaultMode": 288,
"secretName": "ci-build-keys"
}
}
]
}
}
}
}
44 changes: 42 additions & 2 deletions triggers/ig-commit-trigger/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import functions from "@google-cloud/functions-framework";
import * as k8s from "@kubernetes/client-node";
import jobSource from "./job.json" with { type: "json" };
import deleteJobSource from "./delete-job.json" with { type: "json" };
import crypto from "crypto"


Expand All @@ -19,11 +20,13 @@ functions.http("ig-commit-trigger", async function (req, res) {
return;
}

const action = req.body.action || "build";

let org, repo, branch, commitHash;
try {
[org, repo] = req.body.repository.full_name.split("/");
branch = req.body.ref.split("/").slice(-1)[0];
commitHash = "" + req.body.after;
commitHash = "" + (req.body.after || "delete");
if (!org || !repo || !branch) {
throw "Bad inputs";
}
Expand All @@ -40,8 +43,45 @@ functions.http("ig-commit-trigger", async function (req, res) {
}

const jobGroupId = crypto.createHash('sha256').update(`${org}-${repo}-${branch}`, 'utf8').digest('hex').slice(0, 63);
console.log("Job group id", jobGroupId);
console.log("Job group id", jobGroupId, "action", action);

if (action === "delete") {
const jobId = `igdelete-${org}-${repo}-${branch}`
.toLocaleLowerCase()
.replace(/[^A-Za-z0-9]/g, "")
.slice(0, 63);

const job = JSON.parse(JSON.stringify(deleteJobSource));
job.metadata.name = jobId;
job.metadata.labels["job-group-id"] = jobGroupId;
job.spec.template.spec.containers[0].args = [org, repo, branch];

try {
await k8sBatch.createNamespacedJob({
namespace: "fhir",
body: job
});

return res.status(200).json({
deleted: true,
org: org,
repo: repo,
branch: branch,
jobId: jobId,
});
} catch (e) {
if (e.body?.message?.includes("already exists")) {
return res
.status(200)
.json({ deleted: false, reason: "Delete job already exists" });
} else {
console.error(e)
throw e;
}
}
}

// Build action
const jobId = `igbuild-${commitHash.slice(0, 6)}-${org}-${repo}-${branch}`
.toLocaleLowerCase()
.replace(/[^A-Za-z0-9]/g, "")
Expand Down