Skip to content

Commit 38273bd

Browse files
committed
(chore) Add automated dependency update workflow
Adds a workflow and script to automatically check for and update OpenMRS dependencies, including verification and deduplication. Other changes include: - Augmenting the existing Transifex integration pull workflow with auto-approve/merge capabilities - Improving workflow documentation - Moving config files such as the i18next parser config and Jest setup into the tools directory - Updating the primary CI workflow to use Node 20
1 parent 99ddf3a commit 38273bd

File tree

10 files changed

+264
-93
lines changed

10 files changed

+264
-93
lines changed

.github/workflows/e2e.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121
- name: Setup node
2222
uses: actions/setup-node@v4
2323
with:
24-
node-version: 18
24+
node-version: 20
2525

2626
- name: Cache dependencies
2727
id: cache-dependencies

.github/workflows/node.js.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Node.js CI
1+
name: OpenMRS CI
22

33
on:
44
push:
@@ -23,7 +23,7 @@ jobs:
2323
- name: 🛠️ Setup Node.js
2424
uses: actions/setup-node@v4
2525
with:
26-
node-version: "18"
26+
node-version: 20
2727

2828
- name: 💾 Cache dependencies
2929
id: cache
@@ -66,7 +66,7 @@ jobs:
6666
- name: 🛠️ Setup Node.js
6767
uses: actions/setup-node@v4
6868
with:
69-
node-version: "18"
69+
node-version: 20
7070

7171
- name: 💾 Cache dependencies
7272
id: cache
@@ -120,7 +120,7 @@ jobs:
120120
- name: 🛠️ Use Node.js
121121
uses: actions/setup-node@v4
122122
with:
123-
node-version: "18"
123+
node-version: 20
124124
registry-url: 'https://registry.npmjs.org'
125125

126126
- name: 💾 Cache dependencies
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# Workflow to automatically check and update OpenMRS dependencies
2+
# Runs hourly and can be triggered manually
3+
4+
name: 'Check for OpenMRS Dependency Updates'
5+
6+
on:
7+
workflow_dispatch:
8+
schedule:
9+
# Runs every hour at minute 30
10+
- cron: '30 * * * *'
11+
12+
jobs:
13+
check-for-updates:
14+
name: Check for updates to OpenMRS libraries
15+
runs-on: ubuntu-latest
16+
17+
if: github.repository_owner == 'openmrs'
18+
19+
permissions:
20+
contents: write
21+
pull-requests: write
22+
23+
steps:
24+
# Step 1: Check out repository
25+
- name: Checkout repository
26+
uses: actions/checkout@v4
27+
with:
28+
fetch-depth: 1 # Shallow clone for better performance
29+
30+
# Step 2: Setup Node.js environment
31+
- name: 🟢 Setup Node.js
32+
uses: actions/setup-node@v4
33+
with:
34+
node-version: 20
35+
36+
# Step 3: Cache dependencies
37+
- name: 💾 Cache dependencies
38+
id: cache
39+
uses: actions/cache@v4
40+
with:
41+
path: '**/node_modules'
42+
key: ${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
43+
44+
# Step 4: Install dependencies if cache miss
45+
- name: 📦 Install dependencies
46+
if: steps.cache.outputs.cache-hit != 'true'
47+
run: yarn install --immutable
48+
49+
# Step 5: Run dependency update check
50+
- name: ✅ Check for updates
51+
run: node ./tools/update-openmrs-deps.mjs
52+
53+
# Step 6: Create PR with updates if necessary
54+
- name: ⬆️ Create PR if necessary
55+
id: cpr
56+
uses: peter-evans/create-pull-request@v7
57+
with:
58+
commit-message: '(chore) Update OpenMRS dependencies'
59+
title: '(chore) Update OpenMRS dependencies'
60+
body: |
61+
# OpenMRS Dependencies Update
62+
63+
This PR contains updates to OpenMRS dependencies.
64+
65+
## Changes
66+
* Automated dependency updates for OpenMRS packages
67+
* Generated by the OpenMRS Dependency Update workflow
68+
69+
## Verification
70+
- [ ] All dependencies are valid versions
71+
- [ ] No breaking changes introduced
72+
73+
> This PR was automatically generated and will be automatically merged if checks pass.
74+
branch: 'chore/update-openmrs-deps'
75+
author: 'OpenMRS Bot <infrastructure@openmrs.org>'
76+
token: ${{ secrets.OMRS_BOT_GH_TOKEN }}
77+
labels: |
78+
dependencies
79+
automated-pr
80+
delete-branch: true # Clean up branch after merge
81+
82+
# Step 7: Auto-approve the PR if created or updated
83+
- name: ✅ Auto approve PR
84+
if: steps.cpr.outputs.pull-request-operation == 'created' || steps.cpr.outputs.pull-request-operation == 'updated'
85+
run: gh pr review --approve "${{ steps.cpr.outputs.pull-request-number }}"
86+
env:
87+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
88+
89+
# Step 8: Auto-merge the PR if created or updated
90+
- name: 🔀 Auto merge PR
91+
if: steps.cpr.outputs.pull-request-operation == 'created' || steps.cpr.outputs.pull-request-operation == 'updated'
92+
run: gh pr merge --auto --squash "${{ steps.cpr.outputs.pull-request-number }}"
93+
env:
94+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

jest.config.js

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
1+
/**
2+
* @returns {Promise<import('jest').Config>}
3+
*/
14
module.exports = {
25
clearMocks: true,
36
transform: {
4-
"^.+\\.tsx?$": "@swc/jest",
7+
'^.+\\.tsx?$': '@swc/jest',
58
},
6-
transformIgnorePatterns: ["/node_modules/(?!@openmrs)"],
9+
transformIgnorePatterns: ['/node_modules/(?!@openmrs)'],
710
moduleNameMapper: {
8-
"\\.(s?css)$": "identity-obj-proxy",
9-
"@openmrs/esm-framework": "@openmrs/esm-framework/mock",
10-
"^dexie$": require.resolve("dexie"),
11-
"^lodash-es/(.*)$": "lodash/$1",
12-
"^lodash-es$": "lodash",
13-
"^uuid$": "<rootDir>/node_modules/uuid/dist/index.js",
11+
'\\.(s?css)$': 'identity-obj-proxy',
12+
'@openmrs/esm-framework': '@openmrs/esm-framework/mock',
13+
'^dexie$': require.resolve('dexie'),
14+
'^lodash-es/(.*)$': 'lodash/$1',
15+
'^lodash-es$': 'lodash',
16+
'^uuid$': '<rootDir>/node_modules/uuid/dist/index.js',
1417
},
15-
setupFilesAfterEnv: ["<rootDir>/src/setup-tests.ts"],
16-
testEnvironment: "jsdom",
18+
setupFilesAfterEnv: ['<rootDir>/tools/setup-tests.ts'],
19+
testEnvironment: 'jsdom',
1720
testEnvironmentOptions: {
18-
url: "http://localhost/",
21+
url: 'http://localhost/',
1922
},
20-
testPathIgnorePatterns: ["<rootDir>/e2e"],
23+
testPathIgnorePatterns: ['<rootDir>/e2e'],
2124
};

src/setup-tests.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.

tools/setup-tests.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import '@testing-library/jest-dom';

tools/update-openmrs-deps.mjs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { execSync } from 'node:child_process';
2+
3+
try {
4+
execSync(`yarn up --fixed '@openmrs/esm-framework@next' '@openmrs/esm-form-engine-lib@next' 'openmrs@next'`, {
5+
stdio: ['ignore', 'inherit', 'inherit'],
6+
windowsHide: true,
7+
});
8+
} catch (error) {
9+
console.error(`Error while updating dependencies: ${error.message ?? error}`);
10+
process.exit(1);
11+
}
12+
13+
try {
14+
execSync(`yarn dedupe`, {
15+
stdio: ['ignore', 'inherit', 'inherit'],
16+
windowsHide: true,
17+
});
18+
} catch (error) {
19+
console.error(`Error while deduplicating dependencies: ${error.message ?? error}`);
20+
process.exit(1);
21+
}
22+
23+
try {
24+
execSync(`git diff-index --quiet HEAD --`, {
25+
stdio: 'ignore',
26+
windowsHide: true,
27+
});
28+
process.exit(0);
29+
} catch (error) {
30+
// git diff-index --quite HEAD --
31+
// exits with status 1 if there are changes; we only need to run yarn verify if there are changes
32+
}
33+
34+
try {
35+
execSync(`yarn verify`, {
36+
stdio: ['ignore', 'inherit', 'inherit'],
37+
windowsHide: true,
38+
});
39+
} catch (error) {
40+
console.error(`Error while running yarn verify: ${error.message ?? error}. Updates require manual intervention.`);
41+
process.exit(1);
42+
}

webpack.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
const config = (module.exports = require("openmrs/default-webpack-config"));
1+
const config = (module.exports = require('openmrs/default-webpack-config'));
22
module.exports = config;

0 commit comments

Comments
 (0)