44 workflow_dispatch :
55 schedule :
66 - cron : " 0 9 * * *"
7+ push :
8+ branches :
9+ - ' main'
710
811permissions :
912 contents : read
@@ -36,16 +39,26 @@ jobs:
3639 private-key : ${{ secrets.DOCKER_GITHUB_BUILDER_WRITE_PRIVATE_KEY }}
3740 owner : docker
3841 repositories : github-builder
42+ -
43+ name : Checkout
44+ uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
45+ with :
46+ token : ${{ steps.write-app.outputs.token }}
47+ fetch-depth : 0
48+ persist-credentials : false
3949 -
4050 name : Update dependency
51+ id : update
4152 uses : actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
4253 env :
4354 INPUT_DEP : ${{ matrix.dep }}
4455 with :
4556 github-token : ${{ steps.write-app.outputs.token }}
4657 script : |
4758 const dep = core.getInput('dep');
48-
59+ const fs = require('fs');
60+ const path = require('path');
61+
4962 const dependencyConfigs = {
5063 buildx: {
5164 key: 'BUILDX_VERSION',
99112 },
100113 sbom: {
101114 key: 'SBOM_IMAGE',
102- name: 'SBOM image',
115+ name: 'BuildKit Syft Scanner image',
103116 branch: 'deps/sbom-image',
104117 files: [
105118 '.github/workflows/build.yml',
@@ -147,7 +160,7 @@ jobs:
147160 },
148161 toolkit: {
149162 key: 'DOCKER_ACTIONS_TOOLKIT_MODULE',
150- name: 'docker/ actions-toolkit module',
163+ name: 'actions-toolkit module',
151164 branch: 'deps/docker-actions-toolkit-module',
152165 files: [
153166 '.github/workflows/build.yml',
@@ -215,20 +228,6 @@ jobs:
215228 return Buffer.from(data.content, data.encoding).toString('utf8');
216229 }
217230
218- async function getTextFile(github, owner, repo, path, ref) {
219- const response = await github.rest.repos.getContent({
220- owner,
221- repo,
222- path,
223- ref
224- });
225- return {
226- path,
227- sha: response.data.sha,
228- content: decodeContent(response.data)
229- };
230- }
231-
232231 function readEnvValue(content, key) {
233232 const pattern = new RegExp(`^ ${escapeRegExp(key)}: "([^"]*)"$`, 'm');
234233 const match = content.match(pattern);
@@ -266,74 +265,25 @@ jobs:
266265 return `${quoted.slice(0, -1).join(', ')}, and ${quoted.at(-1)}`;
267266 }
268267
269- async function findOpenPullRequest(github, context, branch, base) {
270- const pulls = await github.rest.pulls.list({
271- ...context.repo,
272- state: 'open',
273- head: `${context.repo.owner}:${branch}`,
274- base,
275- per_page: 100
276- });
277- return pulls.data[0] ?? null;
278- }
279-
280268 const config = dependencyConfigs[dep];
281269 if (!config) {
282270 core.setFailed(`Unknown dependency ${dep}`);
283271 return;
284272 }
285273
286- const repo = await github.rest.repos.get(context.repo);
287- const defaultBranch = repo.data.default_branch;
288- const branchRefName = `heads/${config.branch}`;
289- const openPullRequest = await findOpenPullRequest(github, context, config.branch, defaultBranch);
290-
291274 const target = await config.resolve({github});
292275 core.info(`Resolved ${config.key} to ${target.value} from ${config.sourceUrl}`);
293276
294- const baseFiles = await Promise.all(config.files.map((path) => getTextFile(github, context.repo.owner, context.repo.repo, path, defaultBranch)));
295- const baseValues = unique(baseFiles.map((file) => readEnvValue(file.content, config.key)));
296- const baseIsUpToDate = baseValues.every((value) => value === target.value);
297-
298- if (baseIsUpToDate) {
299- core.info(`${config.key} is already up to date on ${defaultBranch}`);
300- if (openPullRequest) {
301- await github.rest.pulls.update({
302- ...context.repo,
303- pull_number: openPullRequest.number,
304- state: 'closed'
305- });
306- core.notice(`Closed stale pull request #${openPullRequest.number}`);
307- }
308- return;
309- }
310-
311- let branchExists = false;
312- try {
313- await github.rest.git.getRef({
314- ...context.repo,
315- ref: branchRefName
316- });
317- branchExists = true;
318- } catch (error) {
319- if (error.status !== 404) {
320- throw error;
321- }
322- }
323-
324- const defaultRef = await github.rest.git.getRef({
325- ...context.repo,
326- ref: `heads/${defaultBranch}`
277+ const workingFiles = config.files.map((filePath) => {
278+ const absolutePath = path.join(process.env.GITHUB_WORKSPACE, filePath);
279+ const content = fs.readFileSync(absolutePath, 'utf8');
280+ return {
281+ path: filePath,
282+ absolutePath,
283+ content
284+ };
327285 });
328- const parentCommitSha = defaultRef.data.object.sha;
329-
330- // Always rebuild updater branches from the latest default branch head
331- // so stale dependency PRs do not accumulate merge conflicts.
332- const workingRef = defaultBranch;
333- const workingFiles = await Promise.all(
334- config.files.map((path) => getTextFile(github, context.repo.owner, context.repo.repo, path, workingRef))
335- );
336-
286+ const baseValues = unique(workingFiles.map((file) => readEnvValue(file.content, config.key)));
337287 const changes = [];
338288 for (const file of workingFiles) {
339289 const replacement = replaceEnvValue(file.content, config.key, target.value);
@@ -344,107 +294,41 @@ jobs:
344294 path: file.path,
345295 before: replacement.before,
346296 after: target.value,
347- content: replacement.content
297+ content: replacement.content,
298+ absolutePath: file.absolutePath
348299 });
349300 }
350301
351302 if (changes.length > 0) {
352- const parentCommit = await github.rest.git.getCommit({
353- ...context.repo,
354- commit_sha: parentCommitSha
355- });
356-
357- const tree = [];
358303 for (const change of changes) {
359- const blob = await github.rest.git.createBlob({
360- ...context.repo,
361- content: change.content,
362- encoding: 'utf-8'
363- });
364- tree.push({
365- path: change.path,
366- mode: '100644',
367- type: 'blob',
368- sha: blob.data.sha
369- });
370- }
371-
372- const newTree = await github.rest.git.createTree({
373- ...context.repo,
374- base_tree: parentCommit.data.tree.sha,
375- tree
376- });
377-
378- const commit = await github.rest.git.createCommit({
379- ...context.repo,
380- message: `chore(deps): bump ${config.key} to ${target.to}`,
381- tree: newTree.data.sha,
382- parents: [parentCommitSha]
383- });
384-
385- if (branchExists) {
386- await github.rest.git.updateRef({
387- ...context.repo,
388- ref: branchRefName,
389- sha: commit.data.sha,
390- force: true
391- });
392- } else {
393- await github.rest.git.createRef({
394- ...context.repo,
395- ref: `refs/${branchRefName}`,
396- sha: commit.data.sha
397- });
398- branchExists = true;
304+ fs.writeFileSync(change.absolutePath, change.content, 'utf8');
399305 }
306+ core.info(`New ${config.name} ${target.value} found`);
400307 } else {
401- core.info(`No file changes needed on branch ${config.branch }`);
308+ core.info(`No workspace changes needed for ${config.key }`);
402309 }
403310
404- const comparison = await github.rest.repos.compareCommits({
405- ...context.repo,
406- base: defaultBranch,
407- head: config.branch
408- });
409-
410- if (comparison.data.ahead_by === 0) {
411- core.info(`Branch ${config.branch} does not differ from ${defaultBranch}`);
412- if (openPullRequest) {
413- await github.rest.pulls.update({
414- ...context.repo,
415- pull_number: openPullRequest.number,
416- state: 'closed'
417- });
418- core.notice(`Closed stale pull request #${openPullRequest.number}`);
419- }
420- return;
421- }
422-
423- const title = `chore(deps): bump ${config.name} to ${target.to}`;
424311 const beforeValue = formatList(baseValues);
425- const body = [
426- `This updates ${config.key} from ${beforeValue} to \`${target.value}\`.`,
427- '',
428- `The source of truth for this update is ${config.sourceUrl}.`
429- ].join('\n');
430-
431- if (openPullRequest) {
432- await github.rest.pulls.update({
433- ...context.repo,
434- pull_number: openPullRequest.number,
435- title,
436- body
437- });
438- core.notice(`Updated pull request #${openPullRequest.number}`);
439- return;
440- }
441-
442- const pullRequest = await github.rest.pulls.create({
443- ...context.repo,
444- title,
445- body,
446- head: config.branch,
447- base: defaultBranch
448- });
449-
450- core.notice(`Created pull request #${pullRequest.data.number}`);
312+ const commitMessage = `chore(deps): update ${config.name} to ${target.to}`;
313+
314+ core.setOutput('branch', config.branch);
315+ core.setOutput('commit-message', commitMessage);
316+ core.setOutput('key', config.key);
317+ core.setOutput('before-value', beforeValue);
318+ core.setOutput('target-value', target.value);
319+ core.setOutput('source-url', config.sourceUrl);
320+ -
321+ name : Create pull request
322+ uses : peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
323+ with :
324+ base : main
325+ branch : ${{ steps.update.outputs.branch }}
326+ token : ${{ steps.write-app.outputs.token }}
327+ commit-message : ${{ steps.update.outputs.commit-message }}
328+ title : ${{ steps.update.outputs.commit-message }}
329+ signoff : true
330+ delete-branch : true
331+ body : |
332+ This updates ${{ steps.update.outputs.key }} from ${{ steps.update.outputs.before-value }} to `${{ steps.update.outputs.target-value }}`.
333+
334+ The source of truth for this update is ${{ steps.update.outputs.source-url }}.
0 commit comments