Skip to content

Commit

Permalink
Merge branch 'medic:master' into duplicate-prevention
Browse files Browse the repository at this point in the history
  • Loading branch information
ChinHairSaintClair authored Nov 6, 2024
2 parents 9526730 + 32bd626 commit 48d32cc
Show file tree
Hide file tree
Showing 16 changed files with 2,636 additions and 145 deletions.
1,965 changes: 1,965 additions & 0 deletions scripts/deploy/package-lock.json

Large diffs are not rendered by default.

21 changes: 12 additions & 9 deletions scripts/deploy/src/certificate.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ const CERT_SOURCES = {
const cert = config.CERT_FILE;
const key = config.KEY_FILE;

const obtainCertificateAndKey = async function(values) {
const obtainCertificateAndKey = async (values) => {
console.log('Obtaining certificate...');
const certSource = values.cert_source || '';
const certSource = values?.cert_source || '';

const handlers = {
[CERT_SOURCES.FILE]: () => handleFileSource(values),
Expand All @@ -31,7 +31,7 @@ const obtainCertificateAndKey = async function(values) {
await handler();
};

const handleFileSource = function({ certificate_crt_file_path, certificate_key_file_path }) {
const handleFileSource = ({ certificate_crt_file_path, certificate_key_file_path }) => {
if (!certificate_crt_file_path || !certificate_key_file_path) {
throw new CertificateError('certificate_crt_file_path and certificate_key_file_path must be set for file source');
}
Expand All @@ -40,7 +40,7 @@ const handleFileSource = function({ certificate_crt_file_path, certificate_key_f
copyFile(certificate_key_file_path, key);
};

const handleMyIpSource = async function() {
const handleMyIpSource = async () => {
const [crtData, keyData] = await Promise.all([
fetchData(`${config.CERT_API_URL}/fullchain`),
fetchData(`${config.CERT_API_URL}/key`)
Expand All @@ -50,27 +50,30 @@ const handleMyIpSource = async function() {
writeFile(key, keyData);
};

const copyFile = function(src, dest) {
const copyFile = (src, dest) => {
try {
fs.copyFileSync(src, dest);
} catch (error) {
throw new CertificateError(`Failed to copy file from ${src} to ${dest}: ${error.message}`);
}
};

const writeFile = function(filename, data) {
const writeFile = (filename, data) => {
try {
fs.writeFileSync(filename, data);
} catch (error) {
throw new CertificateError(`Failed to write file ${filename}: ${error.message}`);
}
};

const fetchData = async function(url) {
const fetchData = async (url) => {
try {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), config.FETCH_TIMEOUT);
const response = await fetch(url, { signal: controller.signal });
if (!response.ok) {
throw response;
}
clearTimeout(timeoutId);
return await response.text();
} catch (error) {
Expand Down Expand Up @@ -104,12 +107,12 @@ const createSecret = async function (namespace, values) {
cleanupFiles();
};

const cleanupFiles = function() {
const cleanupFiles = () => {
deleteFile(cert);
deleteFile(key);
};

const deleteFile = function(filename) {
const deleteFile = (filename) => {
try {
if (fs.existsSync(filename)) {
fs.unlinkSync(filename);
Expand Down
2 changes: 1 addition & 1 deletion scripts/deploy/src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ export default {
MEDIC_REPO_NAME: process.env.MEDIC_REPO_NAME || 'medic',
MEDIC_REPO_URL: process.env.MEDIC_REPO_URL || 'https://docs.communityhealthtoolkit.org/helm-charts',
CHT_CHART_NAME: process.env.CHT_CHART_NAME || 'medic/cht-chart-4x',
DEFAULT_CHART_VERSION: process.env.DEFAULT_CHART_VERSION || '1.0.*',
DEFAULT_CHART_VERSION: process.env.DEFAULT_CHART_VERSION || '1.*.*',
IMAGE_TAG_API_URL: process.env.IMAGE_TAG_API_URL || 'https://staging.dev.medicmobile.org/_couch/builds_4',
CERT_FILE: process.env.CERT_FILE || 'certificate.crt',
KEY_FILE: process.env.KEY_FILE || 'private.key',
Expand Down
70 changes: 38 additions & 32 deletions scripts/deploy/src/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ import fetch from 'node-fetch';
import yaml from 'js-yaml';
import path from 'path';

const MEDIC_REPO_NAME = 'medic';
const MEDIC_REPO_URL = 'https://docs.communityhealthtoolkit.org/helm-charts';
const CHT_CHART_NAME = `${MEDIC_REPO_NAME}/cht-chart-4x`;
const DEFAULT_CHART_VERSION = '1.1.*';
import config from './config.js';
const { MEDIC_REPO_NAME, MEDIC_REPO_URL, CHT_CHART_NAME, DEFAULT_CHART_VERSION, IMAGE_TAG_API_URL } = config;

import { fileURLToPath } from 'url';
import { obtainCertificateAndKey, createSecret } from './certificate.js';
Expand All @@ -16,7 +14,7 @@ import { UserRuntimeError } from './error.js';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const readFile = function(f) {
const readFile = (f) => {
try {
return yaml.load(fs.readFileSync(f, 'utf8'));
} catch (err) {
Expand All @@ -25,22 +23,22 @@ const readFile = function(f) {
}
};

const prepare = function(f) {
const prepare = (f) => {
const values = readFile(f);
const environment = values.environment || '';
const scriptPath = path.join(__dirname, 'prepare.sh');
child_process.execSync(`${scriptPath} ${environment}`, { stdio: 'inherit' }); //NoSONAR
};

const loadValues = function(f) {
const loadValues = (f) => {
if (!f) {
console.error('No values file provided. Please specify a values file using -f <file>');
process.exit(1);
}
return readFile(f);
};

const determineNamespace = function(values) {
const determineNamespace = (values) => {
const namespace = values.namespace || '';
if (!namespace) {
console.error('Namespace is not specified.');
Expand All @@ -49,43 +47,48 @@ const determineNamespace = function(values) {
return namespace;
};

const getImageTag = async function(chtversion) {
const response = await fetch(`https://staging.dev.medicmobile.org/_couch/builds_4/medic:medic:${chtversion}`);
const getImageTag = async (chtVersion) => {
const response = await fetch(`${IMAGE_TAG_API_URL}/medic:medic:${chtVersion}`);
const data = await response.json();
const tag = data.tags && data.tags[0];
const tag = data.tags?.[0];
if (!tag) {
return Promise.reject(new UserRuntimeError('cht image tag not found'));
}
return tag.image.split(':').pop();
};

const getChartVersion = function(values) {
const getChartVersion = (values) => {
return values.cht_chart_version || DEFAULT_CHART_VERSION;
};

const helmCmd = (action, positionalArgs, params) => {
const flagsArray = Object.entries(params).map(([key, value]) => {
if (value === true) {
return `--${key}`;
}
if (value) {
return `--${key} ${value}`;
}
return ''; //If value is falsy, don't include the flag
}).filter(Boolean);
const flagsArray = Object
.entries(params)
.map(([key, value]) => {
if (value === true) {
return `--${key}`;
}
if (value) {
return `--${key} ${value}`;
}
return ''; //If value is falsy, don't include the flag
})
.filter(Boolean);

const command = `helm ${action} ${positionalArgs.join(' ')} ${flagsArray.join(' ')}`;
return child_process.execSync(command, { stdio: 'inherit' }); //NoSONAR
return child_process.execSync(command, { stdio: 'inherit' });
};

const helmInstallOrUpdate = function(valuesFile, namespace, values, imageTag) {
const helmInstallOrUpdate = (valuesFile, namespace, values, imageTag) => {
const chartVersion = getChartVersion(values);
ensureMedicHelmRepo();
const projectName = values.project_name || '';
const namespaceExists = checkNamespaceExists(namespace);

try {
const releaseExists = child_process.execSync(`helm list -n ${namespace}`).toString() //NoSONAR
const releaseExists = child_process
.execSync(`helm list -n ${namespace}`)
.toString()
.includes(projectName);

const commonOpts = {
Expand Down Expand Up @@ -121,29 +124,32 @@ const helmInstallOrUpdate = function(valuesFile, namespace, values, imageTag) {
}
};

const checkNamespaceExists = function(namespace) {
const checkNamespaceExists = (namespace) => {
try {
const result = child_process.execSync(`kubectl get namespace ${namespace}`).toString(); //NoSONAR
return result.includes(namespace); //NoSONAR
const result = child_process.execSync(`kubectl get namespace ${namespace}`).toString();
return result.includes(namespace);
} catch (err) {
return false;
}
};

const ensureMedicHelmRepo = function() {
const ensureMedicHelmRepo = () => {
try {
const repoList = child_process.execSync(`helm repo list -o json`).toString();
const repos = JSON.parse(repoList);
const medicRepo = repos.find(repo => repo.name === MEDIC_REPO_NAME);

if (!medicRepo) {
console.log(`Helm repo ${MEDIC_REPO_NAME} not found, adding..`);
child_process.execSync(`helm repo add ${MEDIC_REPO_NAME} ${MEDIC_REPO_URL}`, { stdio: 'inherit' }); //NoSONAR
child_process.execSync(`helm repo add ${MEDIC_REPO_NAME} ${MEDIC_REPO_URL}`, { stdio: 'inherit' });
return;
} else if (medicRepo.url.replace(/\/$/, '') !== MEDIC_REPO_URL) {
}

if (medicRepo.url.replace(/\/$/, '') !== MEDIC_REPO_URL) {
throw new UserRuntimeError(`Medic repo found but url not matching '${MEDIC_REPO_URL}', see: helm repo list`);
}
// Get the latest
child_process.execSync(`helm repo update ${MEDIC_REPO_NAME}`, { stdio: 'inherit' }); //NoSONAR
child_process.execSync(`helm repo update ${MEDIC_REPO_NAME}`, { stdio: 'inherit' });
} catch (err) {
console.error(err.message);
if (err.stack) {
Expand All @@ -153,7 +159,7 @@ const ensureMedicHelmRepo = function() {
}
};

const install = async function(f) {
const install = async (f) => {
prepare(f);
const values = loadValues(f);
const namespace = determineNamespace(values);
Expand Down
2 changes: 1 addition & 1 deletion shared-libs/search/src/generate-search-requests.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ const sortByLastVisitedDate = () => {
const makeCombinedParams = (freetextRequest, typeKey) => {
const type = typeKey[0];
const params = {};
if (freetextRequest.key) {
if (freetextRequest.params.key) {
params.key = [ type, freetextRequest.params.key[0] ];
} else {
params.startkey = [ type, freetextRequest.params.startkey[0] ];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ describe('Pregnancy danger sign follow-up form', () => {
const person = personFactory.build();

const fillPregnancyDangerSignFollowUpForm = async (attendToVisit, hasDangerSigns) => {
await genericForm.selectContact(person.name);
await genericForm.selectContact(person.name, 'What is the patient\'s name?');
await genericForm.nextPage();
await commonEnketoPage.selectRadioButton('Did the woman visit the health facility as recommended?', attendToVisit);
await commonEnketoPage.selectRadioButton('Is she still experiencing any danger signs?', hasDangerSigns);
Expand Down
39 changes: 39 additions & 0 deletions tests/e2e/default/telemetry/forms/select_contact_telemetry.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?xml version="1.0"?>
<h:html xmlns="http://www.w3.org/2002/xforms" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:jr="http://openrosa.org/javarosa" xmlns:orx="http://openrosa.org/xforms">
<h:head>
<h:title>Select contact by type and without type</h:title>
<model>
<itext>
<translation lang="en">
<text id="/data/select_contact_by_type:label">
<value>Select the contact by type</value>
</text>
<text id="/data/select_contact_without_type:label">
<value>Select the contact without type</value>
</text>
</translation>
</itext>
<instance>
<data id="select_contact_telemetry" prefix="J1!select_contact_telemetry!" delimiter="#" version="2024-10-30 16-00">
<select_contact_by_type/>
<select_contact_without_type/>
<meta tag="hidden">
<instanceID/>
</meta>
</data>
</instance>
<bind nodeset="/data/select_contact_by_type" type="db:person"/>
<bind nodeset="/data/select_contactselect_contact_without_type"/>
</model>
</h:head>
<h:body class="pages">
<group appearance="field-list" ref="/data">
<input appearance="select-contact" ref="/data/select_contact_by_type">
<label ref="jr:itext('/data/select_contact_by_type:label')"/>
</input>
<input appearance="select-contact" ref="/data/select_contact_without_type">
<label ref="jr:itext('/data/select_contact_without_type:label')"/>
</input>
</group>
</h:body>
</h:html>
Loading

0 comments on commit 48d32cc

Please sign in to comment.