Skip to content

Commit

Permalink
Fixed Clean and added Publish support to MSBuild package (Azure#10618)
Browse files Browse the repository at this point in the history
  • Loading branch information
majastrz committed May 5, 2023
1 parent d423d61 commit ffbc432
Show file tree
Hide file tree
Showing 19 changed files with 257 additions and 29 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ jobs:
path: ./src/Bicep.MSBuild.E2eTests/examples/local-packages

- name: Build CLI Package
run: dotnet build --configuration release /p:RuntimeSuffix=${{ matrix.rid }} ./src/Bicep.Cli.Nuget/nuget.proj
run: dotnet build --configuration Release /p:RuntimeSuffix=${{ matrix.rid }} ./src/Bicep.Cli.Nuget/nuget.proj

- name: Upload CLI Package
uses: actions/upload-artifact@v3
Expand Down
1 change: 1 addition & 0 deletions src/Bicep.MSBuild.E2eTests/examples/csharp/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Console.WriteLine("Hello, World!");
24 changes: 24 additions & 0 deletions src/Bicep.MSBuild.E2eTests/examples/csharp/csharp.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!--
Do not include this project in the solution. It is intended to validate our MSBuild task.
-->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<!--
Pickup latest available packages (including prerelease) from local feed configured in NuGet.config.
-->
<ItemGroup>
<PackageReference Include="Azure.Bicep.CommandLine.$(RuntimeSuffix)" Version="*-*" />
<PackageReference Include="Azure.Bicep.MSBuild" Version="*-*" />
</ItemGroup>

<ItemGroup>
<Bicep Include="empty.bicep"/>
</ItemGroup>
</Project>

Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<!-- Mitigation for https://github.com/microsoft/MSBuildSdks/issues/155 -->
<Import Project="$(MSBuildToolsPath)\Microsoft.Common.CrossTargeting.targets" Condition="$(IsCrossTargetingBuild) == 'true'" />
<Import Project="$(MSBuildToolsPath)\Microsoft.Common.targets" Condition="$(IsCrossTargetingBuild) != 'true'" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
param one string

output two string = one
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!--
Do not include this project in the solution. It is intended to validate our MSBuild task.
-->
<Project Sdk="Microsoft.Build.NoTargets">
<PropertyGroup>
<!-- Ensure the package supports multi-targeting -->
<TargetFrameworks>net7.0;net472</TargetFrameworks>
<LanguageTargets>$(MSBuildThisFileDirectory)\multitarget-mitigation.targets</LanguageTargets> <!-- https://github.com/microsoft/MSBuildSdks/issues/155 -->
</PropertyGroup>

<!--
Pickup latest available packages (including prerelease) from local feed configured in NuGet.config.
-->
<ItemGroup>
<PackageReference Include="Azure.Bicep.CommandLine.$(RuntimeSuffix)" Version="*-*" />
<PackageReference Include="Azure.Bicep.MSBuild" Version="*-*" />
</ItemGroup>

<ItemGroup>
<Bicep Include="passthrough.bicep"/>
<Bicep Include="empty.bicep"/>
<Bicep Include="subdir\theAnswer.bicep"/>
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
var theAnswer = 42

// need to output var to prevent linter warning
output outint int = theAnswer
31 changes: 31 additions & 0 deletions src/Bicep.MSBuild.E2eTests/src/csharp.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { Example } from "./example";

describe("msbuild", () => {
it("should build and clean a c# project with Bicep files", () => {
const example = new Example("csharp", "csharp.csproj");
example.cleanProjectDir();

const buildResult = example.build();
expect(buildResult.stderr).toBe("");

example.expectFile("bin/Debug/net7.0/csharp.dll");
const templateRelativePath = "bin/Debug/net7.0/empty.json";
example.expectTemplate(templateRelativePath);

const cleanResult = example.clean();
expect(cleanResult.stderr).toBe("");
example.expectNoFile(templateRelativePath);

example.cleanProjectDir();

example.publish(null);
expect(buildResult.stderr).toBe("");

// both build and publish outputs should be present
example.expectTemplate(templateRelativePath);
example.expectTemplate("bin/Debug/net7.0/publish/empty.json");
});
});
15 changes: 15 additions & 0 deletions src/Bicep.MSBuild.E2eTests/src/empty.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { Example } from "./example";

describe("msbuild", () => {
it("should build project without bicep file successfully", () => {
const example = new Example("empty");
example.cleanProjectDir();

const result = example.build();

expect(result.stderr).toBe("");
});
});
75 changes: 59 additions & 16 deletions src/Bicep.MSBuild.E2eTests/src/example.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,18 @@ export class Example {
readonly projectDir: string;
readonly projectFile: string;

constructor(projectName: string) {
constructor(projectName: string, projectFile?: string) {
const projectDir = path.normalize(
path.join(__dirname, `../examples/${projectName}/`)
);
this.projectDir = projectDir;
this.projectFile = path.join(projectDir, `${projectName}.proj`);
this.projectFile = path.join(
projectDir,
projectFile ?? `${projectName}.proj`
);
}

public clean(): void {
public cleanProjectDir(): void {
const result = spawn.sync("git", ["clean", "-dfx", "--", this.projectDir], {
cwd: this.projectDir,
stdio: "pipe",
Expand All @@ -29,17 +32,68 @@ export class Example {
}
}

public clean(expectSuccess = true): SpawnSyncReturns<string> {
return this.runMsBuild("clean", null, expectSuccess);
}

public build(expectSuccess = true): SpawnSyncReturns<string> {
return this.runMsBuild("build", null, expectSuccess);
}

public publish(
targetFramework: string | null,
expectSuccess = true
): SpawnSyncReturns<string> {
return this.runMsBuild("publish", targetFramework, expectSuccess);
}

public expectTemplate(relativeFilePath: string): void {
const filePath = this.resolveRelativePath(relativeFilePath);
this.expectFile(relativeFilePath);

// we don't need to do full template validation
// (the CLI tests already cover it)
// this will throw if JSON is not valid
JSON.parse(fs.readFileSync(filePath, { encoding: "utf-8" }));
}

public expectFile(relativeFilePath: string): void {
const filePath = this.resolveRelativePath(relativeFilePath);
// eslint-disable-next-line jest/no-standalone-expect
expect(fs.existsSync(filePath)).toBeTruthy();
}

public expectNoFile(relativeFilePath: string): void {
const filePath = this.resolveRelativePath(relativeFilePath);
// eslint-disable-next-line jest/no-standalone-expect
expect(fs.existsSync(filePath)).toBeFalsy();
}

private resolveRelativePath(relativeFilePath: string): string {
return path.join(this.projectDir, relativeFilePath);
}

private runMsBuild(
verb: string,
targetFramework: string | null,
expectSuccess: boolean
): SpawnSyncReturns<string> {
const runtimeSuffix = process.env.RuntimeSuffix;
if (!runtimeSuffix) {
throw new Error(
"Please set the RuntimeSuffix environment variable to a .net runtime ID to run these tests. Possible values: win-x64, linux-x64, osx-x64"
);
}

const result = spawn.sync(
"dotnet",
["build", `/p:RuntimeSuffix=${runtimeSuffix}`, "/bl", this.projectFile],
[
verb,
"/nr:false",
`/p:RuntimeSuffix=${runtimeSuffix}`,
targetFramework ? `/p:TargetFramework=${targetFramework}` : "",
"/bl",
this.projectFile,
],
{
cwd: this.projectDir,
stdio: "pipe",
Expand All @@ -54,17 +108,6 @@ export class Example {
return result;
}

public expectTemplate(relativeFilePath: string): void {
const filePath = path.join(this.projectDir, relativeFilePath);
// eslint-disable-next-line jest/no-standalone-expect
expect(fs.existsSync(filePath)).toBeTruthy();

// we don't need to do full template validation
// (the CLI tests already cover it)
// this will throw if JSON is not valid
JSON.parse(fs.readFileSync(filePath, { encoding: "utf-8" }));
}

private handleFailure(tool: string, result: SpawnSyncReturns<string>) {
if (result.stderr.length > 0) {
throw new Error(`Unexpected StdErr content:\n${result.stderr}`);
Expand Down
2 changes: 1 addition & 1 deletion src/Bicep.MSBuild.E2eTests/src/fail.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Example } from "./example";
describe("msbuild", () => {
it("build failures should produce expected diagnostics", () => {
const example = new Example("fail");
example.clean();
example.cleanProjectDir();

const result = example.build(false);

Expand Down
2 changes: 1 addition & 1 deletion src/Bicep.MSBuild.E2eTests/src/fatal.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Example } from "./example";
describe("msbuild", () => {
it("fatal bicep errors should produce an msbuild diagnostic", () => {
const example = new Example("fatal");
example.clean();
example.cleanProjectDir();

const result = example.build(false);

Expand Down
2 changes: 1 addition & 1 deletion src/Bicep.MSBuild.E2eTests/src/missingCli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Example } from "./example";
describe("msbuild", () => {
it("should produce a friendly error message if CLI is missing from the path", () => {
const example = new Example("missingCli");
example.clean();
example.cleanProjectDir();

const result = example.build(false);

Expand Down
4 changes: 2 additions & 2 deletions src/Bicep.MSBuild.E2eTests/src/multiple.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
import { Example } from "./example";

describe("msbuild", () => {
it("multiple", () => {
it("should build a multi-targeting project with customized output paths successfully", () => {
const example = new Example("multiple");
example.clean();
example.cleanProjectDir();

const result = example.build();

Expand Down
22 changes: 17 additions & 5 deletions src/Bicep.MSBuild.E2eTests/src/simple.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,26 @@
import { Example } from "./example";

describe("msbuild", () => {
it("simple", () => {
it("should build and clean project with single Bicep file", () => {
const example = new Example("simple");
example.clean();
example.cleanProjectDir();

const result = example.build();
const buildResult = example.build();
expect(buildResult.stderr).toBe("");
const templateRelativePath = "bin/Debug/net472/empty.json";
example.expectTemplate(templateRelativePath);

expect(result.stderr).toBe("");
const cleanResult = example.clean();
expect(cleanResult.stderr).toBe("");
example.expectNoFile(templateRelativePath);

example.expectTemplate("bin/Debug/net472/empty.json");
example.cleanProjectDir();

example.publish(null);
expect(buildResult.stderr).toBe("");

// both build and publish outputs should be present
example.expectTemplate(templateRelativePath);
example.expectTemplate("bin/Debug/net472/publish/empty.json");
});
});
44 changes: 44 additions & 0 deletions src/Bicep.MSBuild.E2eTests/src/simpleMultiTargeting.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { Example } from "./example";

describe("msbuild", () => {
it("should build a multi-targeting project with default output paths successfully", () => {
const example = new Example("simpleMultiTarget");
example.cleanProjectDir();

const buildResult = example.build();
expect(buildResult.stderr).toBe("");

example.expectTemplate("bin/Debug/net7.0/empty.json");
example.expectTemplate("bin/Debug/net7.0/passthrough.json");
example.expectTemplate("bin/Debug/net7.0/theAnswer.json");

example.expectTemplate("bin/Debug/net472/empty.json");
example.expectTemplate("bin/Debug/net472/passthrough.json");
example.expectTemplate("bin/Debug/net472/theAnswer.json");

const cleanResult = example.clean();
expect(cleanResult.stderr).toBe("");

example.expectNoFile("bin/Debug/net7.0/empty.json");
example.expectNoFile("bin/Debug/net7.0/passthrough.json");
example.expectNoFile("bin/Debug/net7.0/theAnswer.json");

example.expectNoFile("bin/Debug/net472/empty.json");
example.expectNoFile("bin/Debug/net472/passthrough.json");
example.expectNoFile("bin/Debug/net472/theAnswer.json");

const publishResult = example.publish("net472");
expect(publishResult.stderr).toBe("");

example.expectNoFile("bin/Debug/net7.0/publish/empty.json");
example.expectNoFile("bin/Debug/net7.0/publish/passthrough.json");
example.expectNoFile("bin/Debug/net7.0/publish/theAnswer.json");

example.expectTemplate("bin/Debug/net472/publish/empty.json");
example.expectTemplate("bin/Debug/net472/publish/passthrough.json");
example.expectTemplate("bin/Debug/net472/publish/theAnswer.json");
});
});
Loading

0 comments on commit ffbc432

Please sign in to comment.