Skip to content

Commit

Permalink
Merge pull request #1110 from Green-Software-Foundation/release-v1.0.0
Browse files Browse the repository at this point in the history
Release v1.0.0
  • Loading branch information
narekhovhannisyan authored Jan 9, 2025
2 parents 3dbf094 + 90f7604 commit 8854b66
Show file tree
Hide file tree
Showing 41 changed files with 1,850 additions and 203 deletions.
3 changes: 3 additions & 0 deletions adopters.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@ One adopter we will highlight in this file is Amadeus. They have used IF at a la
"At Amadeus, the Impact Framework (IF) has become an essential brick in our software carbon measurement engine. Its scalability provides us with a transparent and robust way to model the energy consumption and carbon emissions of our whole cloud infrastructure. Its open-source nature fosters collaboration and innovation, making it a critical part of our efforts to drive environmental responsibility."

*Robin Castellon, Amadeus*


NCS Group Singapore also used IF and various IF plugins to measure the software carbon intensity of their top 5 Azure apps (as reported by Teck Chun Pang, NCS Group, Singapore)
22 changes: 22 additions & 0 deletions manifests/examples/builtins/csv-import/success.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: csv-import
description: successful path
tags:
initialize:
plugins:
data-import:
method: CSVImport
path: 'builtin'
config:
filepath: manifests/examples/builtins/csv-import/test.csv
# filepath: https://raw.githubusercontent.com/Green-Software-Foundation/if-data/main/cloud-metdata-aws-instances.csv
output: '*'
tree:
children:
child:
pipeline:
compute:
- data-import
inputs:
- timestamp: 2023-07-06T00:00
duration: 300
physical-processor: AMD 3020e
4 changes: 4 additions & 0 deletions manifests/examples/builtins/csv-import/test.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
timestamp,duration,cpu-util,energy
2023-07-06T00:00,1,20,5
2023-07-06T00:01,1,30,10
2023-07-06T00:02,1,40,15
84 changes: 84 additions & 0 deletions manifests/outputs/builtins/csv-import/success.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
name: csv-import
description: successful path
tags: null
initialize:
plugins:
data-import:
path: builtin
method: CSVImport
config:
filepath: manifests/examples/builtins/csv-import/test.csv
output: '*'
execution:
command: >-
/Users/manushak/.npm/_npx/1bf7c3c15bf47d04/node_modules/.bin/ts-node
/Users/manushak/Documents/Projects/Green-Software/if/src/if-run/index.ts -m
manifests/examples/builtins/csv-import/success.yaml -o
manifests/outputs/builtins/csv-import/success
environment:
if-version: 0.7.2
os: macOS
os-version: 14.6.1
node-version: 18.20.4
date-time: 2024-12-06T06:45:15.935Z (UTC)
dependencies:
- '@babel/core@7.22.10'
- '@babel/preset-typescript@7.23.3'
- '@commitlint/cli@18.6.0'
- '@commitlint/config-conventional@18.6.0'
- '@grnsft/if-core@0.0.28'
- >-
@grnsft/if-eco-ci-plugin@0.0.1 extraneous ->
file:../../../if-eco-ci-plugin
- '@jest/globals@29.7.0'
- '@types/jest@29.5.8'
- '@types/js-yaml@4.0.9'
- '@types/luxon@3.4.2'
- '@types/node@20.9.0'
- axios-mock-adapter@1.22.0
- axios@1.7.7
- cross-env@7.0.3
- csv-parse@5.5.6
- csv-stringify@6.4.6
- fixpack@4.0.0
- gts@5.2.0
- husky@8.0.3
- jest@29.7.0
- js-yaml@4.1.0
- lint-staged@15.2.10
- luxon@3.4.4
- release-it@16.3.0
- rimraf@5.0.5
- ts-command-line-args@2.5.1
- ts-jest@29.1.1
- typescript-cubic-spline@1.0.1
- typescript@5.2.2
- winston@3.11.0
- zod@3.23.8
status: success
tree:
children:
child:
pipeline:
compute:
- data-import
inputs:
- timestamp: 2023-07-06T00:00
duration: 300
physical-processor: AMD 3020e
outputs:
- timestamp: 2023-07-06T00:00
duration: 300
physical-processor: AMD 3020e
- timestamp: 2023-07-06T00:00
duration: 1
cpu-util: 20
energy: 5
- timestamp: 2023-07-06T00:01
duration: 1
cpu-util: 30
energy: 10
- timestamp: 2023-07-06T00:02
duration: 1
cpu-util: 40
energy: 15
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@grnsft/if",
"description": "Impact Framework",
"version": "1.0.0-beta.0",
"version": "1.0.0",
"author": {
"name": "Green Software Foundation",
"email": "info@gsf.com"
Expand Down
63 changes: 62 additions & 1 deletion src/__tests__/common/util/helpers.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
import {execFileSync} from 'child_process';

jest.mock('node:readline/promises', () =>
require('../../../__mocks__/readline')
);

import {parseManifestFromStdin} from '../../../common/util/helpers';
jest.mock('child_process', () => {
const originalModule = jest.requireActual('child_process');
return {
...originalModule,
execFileSync: jest.fn(() => {
return 'Command executed successfully';
}),
};
});

import {
parseManifestFromStdin,
runHelpCommand,
} from '../../../common/util/helpers';

describe('common/util/helpers: ', () => {
describe('parseManifestFromStdin(): ', () => {
Expand Down Expand Up @@ -41,4 +56,50 @@ describe('common/util/helpers: ', () => {
expect(response).toEqual(expectedMessage);
});
});

describe('runHelpCommand(): ', () => {
const originalEnv = process.env;
it('calls process.exit with code 1 on error.', () => {
expect.assertions(3);

jest.spyOn(process, 'exit').mockImplementation((code?: number) => {
expect(code).toEqual(1);
throw new Error(`process.exit(${code}) called`);
});

expect(() => runHelpCommand('if-run')).toThrow('process.exit(1) called');
expect(execFileSync).toHaveBeenCalledWith(
'npm',
['run', 'if-run', '--silent', '--', '-h'],
{
cwd: process.env.CURRENT_DIR || process.cwd(),
stdio: 'inherit',
shell: false,
}
);
});

it('executes when the script runs from the global.', () => {
expect.assertions(3);
process.env.npm_config_global = 'true';

jest.spyOn(process, 'exit').mockImplementation((code?: number) => {
expect(code).toEqual(1);
throw new Error(`process.exit(${code}) called`);
});

expect(() => runHelpCommand('if-run')).toThrow('process.exit(1) called');
expect(execFileSync).toHaveBeenCalledWith(
'if-run',
['--silent', '--', '-h'],
{
cwd: process.env.CURRENT_DIR || process.cwd(),
stdio: 'inherit',
shell: false,
}
);
});

process.env = originalEnv;
});
});
39 changes: 31 additions & 8 deletions src/__tests__/if-check/util/args.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
import {execFileSync} from 'child_process';

jest.mock('child_process', () => {
const originalModule = jest.requireActual('child_process');
return {
...originalModule,
execFileSync: jest.fn(() => {
return 'Command executed successfully';
}),
};
});

jest.mock('../../../common/util/fs', () => ({
isFileExists: () => {
if (process.env.fileExists === 'true') {
Expand Down Expand Up @@ -151,17 +163,28 @@ describe('if-check/util: ', () => {
}
});

it('throws an error if parsing failed.', async () => {
it('runs help command if the passed argument is incorrect.', async () => {
expect.assertions(3);
jest.spyOn(process, 'exit').mockImplementation((code?: number) => {
expect(code).toEqual(1);
throw new Error(`process.exit(${code}) called`);
});

process.env.result = 'env-throw-error';
expect.assertions(1);

try {
await parseIfCheckArgs();
} catch (error) {
if (error instanceof Error) {
expect(error).toEqual(new ParseCliParamsError('mock-error'));
await expect(parseIfCheckArgs()).rejects.toThrow(
'process.exit(1) called'
);

expect(execFileSync).toHaveBeenCalledWith(
'npm',
['run', 'if-check', '--silent', '--', '-h'],
{
cwd: process.env.CURRENT_DIR || process.cwd(),
stdio: 'inherit',
shell: false,
}
}
);
});

it('throws error if parsing failed (not instance of error).', async () => {
Expand Down
101 changes: 101 additions & 0 deletions src/__tests__/if-check/util/npm.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,51 @@ jest.mock('child_process', () => {
Array.isArray(args) ? `${file} ${args.join(' ')}` : file.trim()
)
).toBeTruthy();
break;
case 'if-check-prefix':
expect(
[
'npm run if-env -- --prefix=.. -m ./src/__mocks__/mock-manifest.yaml',
'npm run if-run -- --prefix=.. -m ./src/__mocks__/mock-manifest.yaml -o src/__mocks__/re-mock-manifest',
'npm run if-diff -- --prefix=.. -s src/__mocks__/re-mock-manifest.yaml -t ./src/__mocks__/mock-manifest.yaml',
'node -p Boolean(process.stdout.isTTY)',
].includes(
Array.isArray(args) ? `${file} ${args.join(' ')}` : file.trim()
)
).toBeTruthy();
break;
case 'if-check-global':
expect(
[
'if-env -m ./src/__mocks__/mock-manifest.yaml',
'if-run -m ./src/__mocks__/mock-manifest.yaml -o src/__mocks__/re-mock-manifest',
'if-diff -s src/__mocks__/re-mock-manifest.yaml -t ./src/__mocks__/mock-manifest.yaml',
'node -p Boolean(process.stdout.isTTY)',
].includes(
Array.isArray(args) ? `${file} ${args.join(' ')}` : file.trim()
)
).toBeTruthy();

break;
case 'if-check-tty':
expect(
[
'if-env -m ./src/__mocks__/mock-manifest.yaml',
'if-run -m ./src/__mocks__/mock-manifest.yaml -o src/__mocks__/re-mock-manifest',
'if-diff -s src/__mocks__/re-mock-manifest.yaml -t ./src/__mocks__/mock-manifest.yaml',
'tty | if-diff -s src/__mocks__/re-mock-manifest.yaml -t ./src/__mocks__/mock-manifest.yaml',
'node -p Boolean(process.stdout.isTTY)',
].includes(
Array.isArray(args) ? `${file} ${args.join(' ')}` : file.trim()
)
).toBeTruthy();

break;
}

if (process.env.NPM_INSTALL === 'if-check-tty') {
return true;
}
return;
},
};
Expand All @@ -44,7 +87,16 @@ jest.mock('child_process', () => {
import {executeCommands} from '../../../if-check/util/npm';

describe('if-check/util/npm: ', () => {
const originalEnv = process.env;
describe('executeCommands(): ', () => {
beforeEach(() => {
jest.clearAllMocks();
});

afterEach(() => {
process.env = originalEnv;
});

it('successfully executes with correct commands.', async () => {
process.env.NPM_INSTALL = 'if-check';
const manifest = './src/__mocks__/mock-manifest.yaml';
Expand All @@ -57,5 +109,54 @@ describe('if-check/util/npm: ', () => {
'✔ if-check successfully verified mock-manifest.yaml\n'
);
});

it('successfully executes with prefix.', async () => {
process.env.CURRENT_DIR = 'mock-dir';
process.env.NPM_INSTALL = 'if-check-prefix';
const manifest = './src/__mocks__/mock-manifest.yaml';
const logSpy = jest.spyOn(global.console, 'log');

await executeCommands(manifest, false);

expect.assertions(6);
expect(logSpy).toHaveBeenCalledWith(
'✔ if-check successfully verified mock-manifest.yaml\n'
);
delete process.env.CURRENT_DIR;
});

it('successfully executes when it runs from the global.', async () => {
process.env.NPM_INSTALL = 'if-check-global';
process.env.npm_config_global = 'true';

const manifest = './src/__mocks__/mock-manifest.yaml';
const logSpy = jest.spyOn(global.console, 'log');

await executeCommands(manifest, false);

expect.assertions(6);
expect(logSpy).toHaveBeenCalledWith(
'✔ if-check successfully verified mock-manifest.yaml\n'
);
});

it('successfully executes when the `tty` is true.', async () => {
const originalIsTTY = process.stdin.isTTY;
process.stdin.isTTY = true;
process.env.NPM_INSTALL = 'if-check-tty';
process.env.npm_config_global = 'true';

const manifest = './src/__mocks__/mock-manifest.yaml';
const logSpy = jest.spyOn(global.console, 'log');

await executeCommands(manifest, false);

expect.assertions(6);
expect(logSpy).toHaveBeenCalledWith(
'✔ if-check successfully verified mock-manifest.yaml\n'
);

process.stdin.isTTY = originalIsTTY;
});
});
});
Loading

0 comments on commit 8854b66

Please sign in to comment.