Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: read target framework from any PropertyGroup #102

Merged
merged 3 commits into from
Aug 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,16 @@ workflows:
- master

# UNIX tests
- test-unix:
name: Unix Tests for Node=10
context: nodejs-install
node_version: '10'
requires:
- Lint
filters:
branches:
ignore:
- master
- test-unix:
name: Unix Tests for Node=12
context: nodejs-install
Expand All @@ -133,6 +143,16 @@ workflows:
- master

# Windows tests
- test-windows:
name: Windows Tests for Node=10
context: nodejs-install
node_version: '10.21.0'
requires:
- Lint
filters:
branches:
ignore:
- master
- test-windows:
name: Windows Tests for Node=12
context: nodejs-install
Expand Down
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ module.exports = {
env: {
node: true,
es6: true,
jest: true,
},
plugins: ['@typescript-eslint'],
extends: [
Expand Down
10 changes: 10 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module.exports = {
testEnvironment: 'node',
transform: {
'^.+\\.(ts)?$': 'ts-jest',
},
testMatch: ['**/*.spec.ts'],
collectCoverage: false,
moduleFileExtensions: ['ts', 'js', 'json'],
forceExit: true,
};
38 changes: 22 additions & 16 deletions lib/nuget-parser/csproj-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,39 +24,45 @@ export async function getTargetFrameworksFromProjFile(

const csprojContents = fs.readFileSync(csprojPath);

let frameworks: (TargetFramework | undefined)[] = [];
let targetFrameworks: (TargetFramework | undefined)[] = [];
parseXML.parseString(csprojContents, (err, parsedCsprojContents) => {
if (err) {
reject(new FileNotProcessableError(err));
return;
}
const versionLoc = parsedCsprojContents?.Project?.PropertyGroup?.[0];
const versions = []
.concat(
(
versionLoc?.TargetFrameworkVersion?.[0] ||
versionLoc?.TargetFramework?.[0] ||
versionLoc?.TargetFrameworks?.[0] ||
''
).split(';'),
)
.filter(Boolean);

if (versions.length < 1) {
const parsedTargetFrameworks = parsedCsprojContents?.Project?.PropertyGroup?.reduce(
(targetFrameworks, propertyGroup) => {
const targetFrameworkSource =
propertyGroup?.TargetFrameworkVersion?.[0] ||
propertyGroup?.TargetFramework?.[0] ||
propertyGroup?.TargetFrameworks?.[0] ||
'';

return targetFrameworks
.concat(targetFrameworkSource.split(';'))
.filter(Boolean);
},
[],
);

if (parsedTargetFrameworks.length < 1) {
debug(
'Could not find TargetFrameworkVersion/TargetFramework' +
'/TargetFrameworks defined in the Project.PropertyGroup field of ' +
'your .csproj file',
);
}
frameworks = versions.map(toReadableFramework).filter(Boolean);
if (versions.length > 1 && frameworks.length < 1) {
targetFrameworks = parsedTargetFrameworks
.map(toReadableFramework)
.filter(Boolean);
if (parsedTargetFrameworks.length > 1 && targetFrameworks.length < 1) {
debug(
'Could not find valid/supported .NET version in csproj file located at' +
csprojPath,
);
}
resolve(frameworks[0]);
resolve(targetFrameworks[0]);
});
});
}
Expand Down
9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"main": "dist/index.js",
"scripts": {
"test": "npm run lint && npm run unit-test",
"unit-test": "tap --no-coverage test/*.test.ts --timeout=300",
"unit-test": "jest && tap --no-coverage test/*.test.ts --timeout=300",
"lint": "prettier --check \"./lib/**/*.ts\" && eslint -c .eslintrc.js \"./lib/**/*\"",
"lint:fix": "prettier --write \"./lib/**/*.ts\" && eslint -c .eslintrc.js --fix \"./lib/**/*\"",
"build": "tsc",
Expand All @@ -23,7 +23,7 @@
"author": "snyk.io",
"license": "Apache-2.0",
"engines": {
"node": ">=12"
"node": ">=10"
},
"files": [
"bin",
Expand All @@ -42,13 +42,16 @@
"xml2js": "^0.4.17"
},
"devDependencies": {
"@types/node": "^12",
"@types/jest": "^27.0.0",
"@types/node": "^10",
"@typescript-eslint/eslint-plugin": "^2.31.0",
"@typescript-eslint/parser": "^2.31.0",
"eslint": "^6.8.0",
"eslint-config-prettier": "^6.15.0",
"jest": "^27.0.6",
"prettier": "^1.19.1",
"tap": "^14.10.7",
"ts-jest": "^27.0.4",
"typescript": "^3.8.3"
}
}
32 changes: 32 additions & 0 deletions test/csproj.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { getTargetFrameworksFromProjFile } from '../lib/nuget-parser/csproj-parser';

const targetFrameworkInNonFirstPropertyGroup =
'./test/stubs/target-framework-version-in-non-first-property-group';
const multipleTargetFrameworksPath =
'./test/stubs/target_framework/csproj_multiple';

describe('getTargetFrameworksFromProjFile', () => {
it('should parse target framework version even if it is in property group that is not first', async () => {
const targetFramework = await getTargetFrameworksFromProjFile(
targetFrameworkInNonFirstPropertyGroup,
);

expect(targetFramework).toMatchObject({
framework: '.NETFramework',
original: 'v4.7.2',
version: '4.7.2',
});
});

it('should return first target framwork if multiple ones are available', async () => {
const targetFramework = await getTargetFrameworksFromProjFile(
multipleTargetFrameworksPath,
);

expect(targetFramework).toMatchObject({
framework: '.NETCore',
original: 'netcoreapp2.0',
version: '2.0',
});
});
});
16 changes: 4 additions & 12 deletions test/csproj.test.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,28 @@
import * as tap from 'tap';
const test = tap.test;
import * as plugin from '../lib/index';
import {getTargetFrameworksFromProjFile} from '../lib/nuget-parser/csproj-parser';

const multipleFrameworksPath = './test/stubs/target_framework/csproj_multiple/';
const noProjectPath = './test/stubs/target_framework/no_csproj/';
const noValidFrameworksPath = './test/stubs/target_framework/no_target_valid_framework';
const noDeps = './test/stubs/target_framework/no-dependencies/';
const manifestFile = 'obj/project.assets.json';

test('parse dotnet with csproj containing multiple versions retrieves first one', async (t) => {
const dotnetVersions = await getTargetFrameworksFromProjFile(
multipleFrameworksPath);
t.equal('netcoreapp2.0', dotnetVersions!.original);
});

test('parse dotnet with vbproj', async (t) => {
test('parse dotnet with vbproj', async t => {
const res = await plugin.inspect(noProjectPath, manifestFile);
t.equal(res.package.name, 'no_csproj');
t.equal(res.plugin.targetRuntime, 'netcoreapp2.0');
});

test('parse dotnet with no deps', async (t) => {
test('parse dotnet with no deps', async t => {
const res = await plugin.inspect(noDeps, manifestFile);
t.equal(Object.keys(res.package.dependencies).length, 0);
});

test('parse dotnet with no valid framework defined', async (t) => {
test('parse dotnet with no valid framework defined', async t => {
try {
await plugin.inspect(noValidFrameworksPath, manifestFile);
t.fail('Expected error to be thrown!');
} catch(err) {
} catch (err) {
t.equal(err.message, 'No frameworks were found in project.assets.json', 'expected error');
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'HOOPP_DEV|AnyCPU'">
<OutputPath>bin\</OutputPath>
<DefineConstants>TRACE;STANDARD;PRO;</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'TFSTokenized|AnyCPU'">
<OutputPath>bin\</OutputPath>
<DefineConstants>TRACE;STANDARD;PRO;</DefineConstants>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release Pro|AnyCPU' ">
<OutputPath>bin\</OutputPath>
<DefineConstants>TRACE;STANDARD;PRO;</DefineConstants>
</PropertyGroup>
</Project>