Skip to content

Commit 87ea2c3

Browse files
committed
chore(ci): Build modified backends on PR
Signed-off-by: Richard Palethorpe <[email protected]>
1 parent 0a1e27c commit 87ea2c3

File tree

3 files changed

+142
-5
lines changed

3 files changed

+142
-5
lines changed

.github/workflows/backend_build.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ on:
5555
type: string
5656
secrets:
5757
dockerUsername:
58-
required: true
58+
required: false
5959
dockerPassword:
60-
required: true
60+
required: false
6161
quayUsername:
6262
required: true
6363
quayPassword:
@@ -187,7 +187,7 @@ jobs:
187187
password: ${{ secrets.dockerPassword }}
188188

189189
- name: Login to Quay.io
190-
# if: github.event_name != 'pull_request'
190+
if: secrets.quayPassword != ''
191191
uses: docker/login-action@v3
192192
with:
193193
registry: quay.io
@@ -230,12 +230,12 @@ jobs:
230230
file: ${{ inputs.dockerfile }}
231231
cache-from: type=gha
232232
platforms: ${{ inputs.platforms }}
233-
push: true
233+
push: ${{ secrets.quayPassword != '' }}
234234
tags: ${{ steps.meta_pull_request.outputs.tags }}
235235
labels: ${{ steps.meta_pull_request.outputs.labels }}
236236

237237

238238

239239
- name: job summary
240240
run: |
241-
echo "Built image: ${{ steps.meta.outputs.labels }}" >> $GITHUB_STEP_SUMMARY
241+
echo "Built image: ${{ steps.meta.outputs.labels }}" >> $GITHUB_STEP_SUMMARY

.github/workflows/backend_pr.yml

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
name: 'build backend container images (PR-filtered)'
2+
3+
on:
4+
pull_request:
5+
6+
concurrency:
7+
group: ci-backends-pr-${{ github.head_ref || github.ref }}-${{ github.repository }}
8+
cancel-in-progress: true
9+
10+
jobs:
11+
generate-matrix:
12+
runs-on: ubuntu-latest
13+
outputs:
14+
matrix: ${{ steps.set-matrix.outputs.matrix }}
15+
has-backends: ${{ steps.set-matrix.outputs.has-backends }}
16+
steps:
17+
- name: Checkout repository
18+
uses: actions/checkout@v4
19+
20+
- name: Setup Bun
21+
uses: oven-sh/setup-bun@v2
22+
23+
- name: Install dependencies
24+
run: |
25+
bun add js-yaml
26+
bun add @octokit/core
27+
28+
# filters the matrix in backend.yml
29+
- name: Filter matrix for changed backends
30+
id: set-matrix
31+
env:
32+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
33+
GITHUB_EVENT_PATH: ${{ github.event_path }}
34+
run: bun run scripts/changed-backends.js
35+
36+
backend-jobs:
37+
needs: generate-matrix
38+
uses: ./.github/workflows/backend_build.yml
39+
if: needs.generate-matrix.outputs.has-backends == 'true'
40+
with:
41+
tag-latest: ${{ matrix.tag-latest }}
42+
tag-suffix: ${{ matrix.tag-suffix }}
43+
build-type: ${{ matrix.build-type }}
44+
cuda-major-version: ${{ matrix.cuda-major-version }}
45+
cuda-minor-version: ${{ matrix.cuda-minor-version }}
46+
platforms: ${{ matrix.platforms }}
47+
runs-on: ${{ matrix.runs-on }}
48+
base-image: ${{ matrix.base-image }}
49+
backend: ${{ matrix.backend }}
50+
dockerfile: ${{ matrix.dockerfile }}
51+
skip-drivers: ${{ matrix.skip-drivers }}
52+
context: ${{ matrix.context }}
53+
secrets:
54+
quayUsername: ${{ secrets.LOCALAI_REGISTRY_USERNAME }}
55+
quayPassword: ${{ secrets.LOCALAI_REGISTRY_PASSWORD }}
56+
strategy:
57+
fail-fast: true
58+
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}

scripts/changed-backends.js

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import fs from "fs";
2+
import yaml from "js-yaml";
3+
import { Octokit } from "@octokit/core";
4+
5+
// Load backend.yml and parse matrix.include
6+
const backendYml = yaml.load(fs.readFileSync(".github/workflows/backend.yml", "utf8"));
7+
const jobs = backendYml.jobs;
8+
const backendJob = jobs["backend-jobs"];
9+
const strategy = backendJob.strategy;
10+
const matrix = strategy.matrix;
11+
const includes = matrix.include;
12+
13+
// Set up Octokit for PR changed files
14+
const token = process.env.GITHUB_TOKEN;
15+
const octokit = new Octokit({ auth: token });
16+
17+
const eventPath = process.env.GITHUB_EVENT_PATH;
18+
const event = JSON.parse(fs.readFileSync(eventPath, "utf8"));
19+
20+
let prNumber, repo, owner;
21+
if (event.pull_request) {
22+
prNumber = event.pull_request.number;
23+
repo = event.repository.name;
24+
owner = event.repository.owner.login;
25+
} else {
26+
throw new Error("This workflow must be triggered by a pull_request event.");
27+
}
28+
29+
async function getChangedFiles() {
30+
let files = [];
31+
let page = 1;
32+
while (true) {
33+
const res = await octokit.request('GET /repos/{owner}/{repo}/pulls/{pull_number}/files', {
34+
owner,
35+
repo,
36+
pull_number: prNumber,
37+
per_page: 100,
38+
page
39+
});
40+
files = files.concat(res.data.map(f => f.filename));
41+
if (res.data.length < 100) break;
42+
page++;
43+
}
44+
return files;
45+
}
46+
47+
// Infer backend path
48+
function inferBackendPath(item) {
49+
if (item.dockerfile.endsWith("python")) {
50+
return `backend/python/${item.backend}`;
51+
}
52+
if (item.dockerfile.endsWith("golang")) {
53+
return `backend/go/${item.backend}`;
54+
}
55+
if (item.dockerfile.endsWith("llama-cpp")) {
56+
return `backend/cpp/llama-cpp`;
57+
}
58+
return null;
59+
}
60+
61+
(async () => {
62+
const changedFiles = await getChangedFiles();
63+
64+
console.log("Changed files:", changedFiles);
65+
66+
const filtered = includes.filter(item => {
67+
const backendPath = inferBackendPath(item);
68+
if (!backendPath) return false;
69+
return changedFiles.some(file => file.startsWith(backendPath));
70+
});
71+
72+
console.log("Filtered files:", filtered);
73+
74+
const hasBackends = filtered.length > 0 ? 'true' : 'false';
75+
console.log("Has backends?:", hasBackends);
76+
77+
fs.appendFileSync(process.env.GITHUB_OUTPUT, `has-backends=${hasBackends}\n`);
78+
fs.appendFileSync(process.env.GITHUB_OUTPUT, `matrix=${JSON.stringify({ include: filtered })}\n`);
79+
})();

0 commit comments

Comments
 (0)