Skip to content
Draft
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
157 changes: 157 additions & 0 deletions .github/workflows/build-pull-request-jenkins.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
name: Build Pull Request Jenkins

on:
pull_request:
paths-ignore:
- '.github/**'
- 'docs/**'
- '!.github/workflows/**'

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: true

permissions:
contents: read
pull-requests: read

jobs:
jenkins-ci-docker:
runs-on: ubuntu-latest
env:
JENKINS_URL: ${{ vars.JENKINS_URL || 'https://starjenkins.sdcc.bnl.gov' }}
JENKINS_JOB: ${{ vars.JENKINS_JOB || 'star-sw-ci-pipeline' }}
JENKINS_USER: ${{ secrets.JENKINS_USER }}
JENKINS_TOKEN: ${{ secrets.JENKINS_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
BRANCH_NAME: ${{ github.event.pull_request.head.ref }}
GIT_COMMIT: ${{ github.event.pull_request.head.sha }}
REPO_URL: ${{ github.event.pull_request.head.repo.clone_url }}
steps:
- name: Validate Jenkins configuration
run: |
set -euo pipefail
for var in JENKINS_URL JENKINS_JOB JENKINS_USER JENKINS_TOKEN PR_NUMBER BRANCH_NAME GIT_COMMIT REPO_URL; do
if [ -z "${!var:-}" ]; then
echo "::error::Missing required value for ${var}"
exit 1
fi
done

- name: Fetch Jenkins crumb
id: crumb
run: |
set -euo pipefail
curl_auth="${JENKINS_USER}:${JENKINS_TOKEN}"
crumb="$(curl --silent --show-error --fail --retry 3 --retry-all-errors --user "$curl_auth" \
"${JENKINS_URL}/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,%22:%22,//crumb)")"
echo "::add-mask::$crumb"
echo "value=$crumb" >> "$GITHUB_OUTPUT"

- name: Cancel older Jenkins builds for this PR
env:
JENKINS_CRUMB: ${{ steps.crumb.outputs.value }}
run: |
set -euo pipefail
curl_auth="${JENKINS_USER}:${JENKINS_TOKEN}"

build_api="${JENKINS_URL}/job/${JENKINS_JOB}/api/json?tree=builds[number,url,building,actions[parameters[name,value]]]"
queue_api="${JENKINS_URL}/queue/api/json?tree=items[id,task[name],actions[parameters[name,value]]]"

running_builds="$(
curl --globoff --silent --show-error --fail --retry 3 --retry-all-errors --user "$curl_auth" "$build_api" |
jq -r --arg pr "$PR_NUMBER" --arg branch "$BRANCH_NAME" --arg repo "$REPO_URL" '
def param($name): ([.actions[]?.parameters[]? | select(.name == $name) | (.value | tostring)][0] // "");
.builds[]?
| select(.building == true)
| select(
(param("PR_NUMBER") != "" and param("PR_NUMBER") == $pr)
or
(param("PR_NUMBER") == "" and param("BRANCH_NAME") == $branch and param("REPO_URL") == $repo)
)
| .url
'
)"

queued_items="$(
curl --globoff --silent --show-error --fail --retry 3 --retry-all-errors --user "$curl_auth" "$queue_api" |
jq -r --arg job "$JENKINS_JOB" --arg pr "$PR_NUMBER" --arg branch "$BRANCH_NAME" --arg repo "$REPO_URL" '
def param($name): ([.actions[]?.parameters[]? | select(.name == $name) | (.value | tostring)][0] // "");
.items[]?
| select(.task.name == $job)
| select(
(param("PR_NUMBER") != "" and param("PR_NUMBER") == $pr)
or
(param("PR_NUMBER") == "" and param("BRANCH_NAME") == $branch and param("REPO_URL") == $repo)
)
| .id
'
)"

if [ -n "$queued_items" ]; then
while IFS= read -r item_id; do
[ -n "$item_id" ] || continue
echo "Canceling queued Jenkins item ${item_id}"
curl --silent --show-error --fail \
--request POST \
--retry 3 \
--retry-all-errors \
--user "$curl_auth" \
--header "$JENKINS_CRUMB" \
--output /dev/null \
"${JENKINS_URL}/queue/cancelItem?id=${item_id}"
done <<< "$queued_items"
fi

if [ -n "$running_builds" ]; then
while IFS= read -r build_url; do
[ -n "$build_url" ] || continue
echo "Stopping running Jenkins build ${build_url}"
curl --silent --show-error --fail \
--request POST \
--retry 3 \
--retry-all-errors \
--user "$curl_auth" \
--header "$JENKINS_CRUMB" \
--output /dev/null \
"${build_url}stop"
done <<< "$running_builds"
fi

- name: Trigger Jenkins docker job
env:
JENKINS_CRUMB: ${{ steps.crumb.outputs.value }}
run: |
set -euo pipefail
curl_auth="${JENKINS_USER}:${JENKINS_TOKEN}"
response_headers="$(mktemp)"

curl --silent --show-error --fail \
--request POST \
--retry 3 \
--retry-all-errors \
--user "$curl_auth" \
--header "$JENKINS_CRUMB" \
--data-urlencode "PR_NUMBER=${PR_NUMBER}" \
--data-urlencode "BRANCH_NAME=${BRANCH_NAME}" \
--data-urlencode "GIT_COMMIT=${GIT_COMMIT}" \
--data-urlencode "REPO_URL=${REPO_URL}" \
--dump-header "$response_headers" \
--output /dev/null \
"${JENKINS_URL}/job/${JENKINS_JOB}/buildWithParameters"

queue_url="$(awk 'BEGIN {IGNORECASE=1} /^Location:/ {print $2}' "$response_headers" | tr -d '\r')"

echo "Triggered Jenkins job ${JENKINS_JOB} for ${BRANCH_NAME}@${GIT_COMMIT}"
if [ -n "$queue_url" ]; then
echo "Queue item: ${queue_url}"
{
echo "### Jenkins Triggered"
echo
echo "- Job: \`${JENKINS_JOB}\`"
echo "- Pull request: \`${PR_NUMBER}\`"
echo "- Branch: \`${BRANCH_NAME}\`"
echo "- Commit: \`${GIT_COMMIT}\`"
echo "- Queue item: ${queue_url}"
} >> "$GITHUB_STEP_SUMMARY"
fi
6 changes: 6 additions & 0 deletions .github/workflows/build-pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ concurrency:

jobs:
build:
# Temporary guard while validating the Jenkins-backed PR workflow on the
# `jenkins-ci-pipeline` branch without running the normal Docker build matrix.
if: github.event.pull_request.head.ref != 'jenkins-ci-pipeline'
runs-on: ubuntu-latest
strategy:
matrix:
Expand Down Expand Up @@ -42,6 +45,7 @@ jobs:
path: /tmp/star-sw-${{ env.STARENV }}.tar

test:
if: github.event.pull_request.head.ref != 'jenkins-ci-pipeline'
runs-on: ubuntu-latest
needs: build
strategy:
Expand All @@ -68,6 +72,7 @@ jobs:
sh -c "set -e; MALLOC_CHECK_=3 $TEST_CMD 2>&1 | tee log; grep 'Run completed' log"

ROOT5_test_doEvents:
if: github.event.pull_request.head.ref != 'jenkins-ci-pipeline'
runs-on: ubuntu-latest
needs: build
strategy:
Expand All @@ -93,6 +98,7 @@ jobs:
sh -c "set -e; $TEST_CMD 2>&1 | tee log; grep '<StIOMaker::Finish> IO:' log"

ROOT5_test_find_vertex:
if: github.event.pull_request.head.ref != 'jenkins-ci-pipeline'
runs-on: ubuntu-latest
needs: build
strategy:
Expand Down
114 changes: 114 additions & 0 deletions Jenkinsfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
pipeline {
agent none

options {
timestamps()
skipDefaultCheckout(true)
parallelsAlwaysFailFast()
}

parameters {
string(name: 'PR_NUMBER', defaultValue: '', description: 'Pull request number, optional')
string(name: 'BRANCH_NAME', defaultValue: 'main', description: 'Branch to build')
string(name: 'GIT_COMMIT', defaultValue: '', description: 'Commit SHA to build, optional')
string(name: 'REPO_URL', defaultValue: 'https://github.com/star-bnl/star-sw.git', description: 'Repository URL')
}

environment {
ARTIFACT_DIR = 'artifacts'
}

stages {
stage('Build Docker Images') {
matrix {
agent any

axes {
axis {
name 'STAR_BASE'
values 'root5', 'root6'
}
axis {
name 'COMPILER'
values 'gcc485', 'gcc11'
}
}

stages {
stage('Checkout') {
steps {
checkout([
$class: 'GitSCM',
branches: [[name: "*/${params.BRANCH_NAME}"]],
userRemoteConfigs: [[
url: "${params.REPO_URL}",
refspec: '+refs/heads/*:refs/remotes/origin/* +refs/tags/*:refs/tags/*'
]]
])
}
}

stage('Checkout exact commit if provided') {
when {
expression { return params.GIT_COMMIT?.trim() }
}
steps {
sh '''
set -euxo pipefail
git fetch --all --tags
git checkout "${GIT_COMMIT}"
git rev-parse HEAD
'''
}
}

stage('Prepare Docker Buildx') {
steps {
sh '''
set -euxo pipefail
command -v docker
docker --version
docker buildx version
docker buildx use default || true
docker buildx inspect default --bootstrap || docker buildx inspect --bootstrap
'''
}
}

stage('Build Docker Image') {
steps {
sh '''
set -euxo pipefail
starenv="${STAR_BASE}-${COMPILER}"
image_tag="ghcr.io/star-bnl/star-sw-${starenv}"
image_tar="${ARTIFACT_DIR}/star-sw-${starenv}.tar"

mkdir -p "${ARTIFACT_DIR}"

docker buildx build \
--progress plain \
--build-arg "starenv=${STAR_BASE}" \
--build-arg "compiler=${COMPILER}" \
--tag "${image_tag}" \
--output "type=docker,dest=${image_tar}" \
.
'''
}
}

stage('Archive Docker Image') {
steps {
archiveArtifacts artifacts: "artifacts/star-sw-${STAR_BASE}-${COMPILER}.tar", fingerprint: true
}
}
}
}
}
}

post {
always {
echo "Build finished: ${currentBuild.currentResult}"
}
}
}