feat(dotnet): adds additional files to detect .net projects (#1303)

* adds additional files to detect .net projects

* test .net output with a regex pattern
This commit is contained in:
Daniel A. White 2020-06-21 04:22:20 -04:00 committed by GitHub
parent d21cb62e3a
commit b238574100
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 82 additions and 18 deletions

View File

@ -460,9 +460,19 @@ The `dotnet` module shows the relevant version of the .NET Core SDK for the curr
the SDK has been pinned in the current directory, the pinned version is shown. Otherwise the module the SDK has been pinned in the current directory, the pinned version is shown. Otherwise the module
shows the latest installed version of the SDK. shows the latest installed version of the SDK.
This module will only be shown in your prompt when one of the following files are present in the This module will only be shown in your prompt when one or more of the following files are present in the
current directory: `global.json`, `project.json`, `*.sln`, `*.csproj`, `*.fsproj`, `*.xproj`. You'll current directory:
also need the .NET Core command-line tools installed in order to use it correctly. * `global.json`
* `project.json`
* `Directory.Build.props`
* `Directory.Build.targets`
* `Packages.props`
* `*.sln`
* `*.csproj`
* `*.fsproj`
* `*.xproj`
You'll also need the .NET Core SDK installed in order to use it correctly.
Internally, this module uses its own mechanism for version detection. Typically it is twice as fast Internally, this module uses its own mechanism for version detection. Typically it is twice as fast
as running `dotnet --version`, but it may show an incorrect version if your .NET project has an as running `dotnet --version`, but it may show an incorrect version if your .NET project has an

View File

@ -12,6 +12,9 @@ type JValue = serde_json::Value;
const GLOBAL_JSON_FILE: &str = "global.json"; const GLOBAL_JSON_FILE: &str = "global.json";
const PROJECT_JSON_FILE: &str = "project.json"; const PROJECT_JSON_FILE: &str = "project.json";
const DIRECTORY_BUILD_PROPS_FILE: &str = "Directory.Build.props";
const DIRECTORY_BUILD_TARGETS_FILE: &str = "Directory.Build.targets";
const PACKAGES_PROPS_FILE: &str = "Packages.props";
/// A module which shows the latest (or pinned) version of the dotnet SDK /// A module which shows the latest (or pinned) version of the dotnet SDK
/// ///
@ -23,7 +26,13 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
// check for the version using the JSON files // check for the version using the JSON files
let is_dotnet_project = context let is_dotnet_project = context
.try_begin_scan()? .try_begin_scan()?
.set_files(&[GLOBAL_JSON_FILE, PROJECT_JSON_FILE]) .set_files(&[
GLOBAL_JSON_FILE,
PROJECT_JSON_FILE,
DIRECTORY_BUILD_PROPS_FILE,
DIRECTORY_BUILD_TARGETS_FILE,
PACKAGES_PROPS_FILE,
])
.set_extensions(&["sln", "csproj", "fsproj", "xproj"]) .set_extensions(&["sln", "csproj", "fsproj", "xproj"])
.is_match(); .is_match();
@ -196,6 +205,7 @@ fn get_dotnet_file_type(path: &Path) -> Option<FileType> {
match extension_lower.as_ref().map(|f| f.as_ref()) { match extension_lower.as_ref().map(|f| f.as_ref()) {
Some("sln") => return Some(FileType::SolutionFile), Some("sln") => return Some(FileType::SolutionFile),
Some("csproj") | Some("fsproj") | Some("xproj") => return Some(FileType::ProjectFile), Some("csproj") | Some("fsproj") | Some("xproj") => return Some(FileType::ProjectFile),
Some("props") | Some("targets") => return Some(FileType::MsBuildFile),
_ => (), _ => (),
}; };
@ -259,6 +269,7 @@ enum FileType {
ProjectFile, ProjectFile,
GlobalJson, GlobalJson,
SolutionFile, SolutionFile,
MsBuildFile,
} }
struct Version(String); struct Version(String);

View File

@ -1,9 +1,14 @@
use super::common; use super::common;
use regex::Regex;
use std::fs::{DirBuilder, OpenOptions}; use std::fs::{DirBuilder, OpenOptions};
use std::io::{self, Error, ErrorKind, Write}; use std::io::{self, Error, ErrorKind, Write};
use std::process::{Command, Stdio}; use std::process::{Command, Stdio};
use tempfile::{self, TempDir}; use tempfile::{self, TempDir};
const DOTNET_OUTPUT_PATTERN: &str = "•NET v\\d+?\\.\\d+?\\.\\d?";
const DOTNET_PINNED_VERSION: &str = "1.2.3";
const DOTNET_PINNED_VERSION_OUTPUT_PATTERN: &str = "•NET v1\\.2\\.3";
#[test] #[test]
#[ignore] #[ignore]
fn shows_nothing_in_directory_with_zero_relevant_files() -> io::Result<()> { fn shows_nothing_in_directory_with_zero_relevant_files() -> io::Result<()> {
@ -12,12 +17,39 @@ fn shows_nothing_in_directory_with_zero_relevant_files() -> io::Result<()> {
workspace.close() workspace.close()
} }
#[test]
#[ignore]
fn shows_latest_in_directory_with_directory_build_props_file() -> io::Result<()> {
let workspace = create_workspace(false)?;
touch_path(&workspace, "Directory.Build.props", None)?;
expect_output(&workspace, ".", Some(DOTNET_OUTPUT_PATTERN))?;
workspace.close()
}
#[test]
#[ignore]
fn shows_latest_in_directory_with_directory_build_targets_file() -> io::Result<()> {
let workspace = create_workspace(false)?;
touch_path(&workspace, "Directory.Build.targets", None)?;
expect_output(&workspace, ".", Some(DOTNET_OUTPUT_PATTERN))?;
workspace.close()
}
#[test]
#[ignore]
fn shows_latest_in_directory_with_packages_props_file() -> io::Result<()> {
let workspace = create_workspace(false)?;
touch_path(&workspace, "Packages.props", None)?;
expect_output(&workspace, ".", Some(DOTNET_OUTPUT_PATTERN))?;
workspace.close()
}
#[test] #[test]
#[ignore] #[ignore]
fn shows_latest_in_directory_with_solution() -> io::Result<()> { fn shows_latest_in_directory_with_solution() -> io::Result<()> {
let workspace = create_workspace(false)?; let workspace = create_workspace(false)?;
touch_path(&workspace, "solution.sln", None)?; touch_path(&workspace, "solution.sln", None)?;
expect_output(&workspace, ".", Some("•NET v2.2.402"))?; expect_output(&workspace, ".", Some(DOTNET_OUTPUT_PATTERN))?;
workspace.close() workspace.close()
} }
@ -26,7 +58,7 @@ fn shows_latest_in_directory_with_solution() -> io::Result<()> {
fn shows_latest_in_directory_with_csproj() -> io::Result<()> { fn shows_latest_in_directory_with_csproj() -> io::Result<()> {
let workspace = create_workspace(false)?; let workspace = create_workspace(false)?;
touch_path(&workspace, "project.csproj", None)?; touch_path(&workspace, "project.csproj", None)?;
expect_output(&workspace, ".", Some("•NET v2.2.402"))?; expect_output(&workspace, ".", Some(DOTNET_OUTPUT_PATTERN))?;
workspace.close() workspace.close()
} }
@ -35,7 +67,7 @@ fn shows_latest_in_directory_with_csproj() -> io::Result<()> {
fn shows_latest_in_directory_with_fsproj() -> io::Result<()> { fn shows_latest_in_directory_with_fsproj() -> io::Result<()> {
let workspace = create_workspace(false)?; let workspace = create_workspace(false)?;
touch_path(&workspace, "project.fsproj", None)?; touch_path(&workspace, "project.fsproj", None)?;
expect_output(&workspace, ".", Some("•NET v2.2.402"))?; expect_output(&workspace, ".", Some(DOTNET_OUTPUT_PATTERN))?;
workspace.close() workspace.close()
} }
@ -44,7 +76,7 @@ fn shows_latest_in_directory_with_fsproj() -> io::Result<()> {
fn shows_latest_in_directory_with_xproj() -> io::Result<()> { fn shows_latest_in_directory_with_xproj() -> io::Result<()> {
let workspace = create_workspace(false)?; let workspace = create_workspace(false)?;
touch_path(&workspace, "project.xproj", None)?; touch_path(&workspace, "project.xproj", None)?;
expect_output(&workspace, ".", Some("•NET v2.2.402"))?; expect_output(&workspace, ".", Some(DOTNET_OUTPUT_PATTERN))?;
workspace.close() workspace.close()
} }
@ -53,7 +85,7 @@ fn shows_latest_in_directory_with_xproj() -> io::Result<()> {
fn shows_latest_in_directory_with_project_json() -> io::Result<()> { fn shows_latest_in_directory_with_project_json() -> io::Result<()> {
let workspace = create_workspace(false)?; let workspace = create_workspace(false)?;
touch_path(&workspace, "project.json", None)?; touch_path(&workspace, "project.json", None)?;
expect_output(&workspace, ".", Some("•NET v2.2.402"))?; expect_output(&workspace, ".", Some(DOTNET_OUTPUT_PATTERN))?;
workspace.close() workspace.close()
} }
@ -61,9 +93,9 @@ fn shows_latest_in_directory_with_project_json() -> io::Result<()> {
#[ignore] #[ignore]
fn shows_pinned_in_directory_with_global_json() -> io::Result<()> { fn shows_pinned_in_directory_with_global_json() -> io::Result<()> {
let workspace = create_workspace(false)?; let workspace = create_workspace(false)?;
let global_json = make_pinned_sdk_json("1.2.3"); let global_json = make_pinned_sdk_json(DOTNET_PINNED_VERSION);
touch_path(&workspace, "global.json", Some(&global_json))?; touch_path(&workspace, "global.json", Some(&global_json))?;
expect_output(&workspace, ".", Some("•NET v1.2.3"))?; expect_output(&workspace, ".", Some(DOTNET_PINNED_VERSION_OUTPUT_PATTERN))?;
workspace.close() workspace.close()
} }
@ -71,10 +103,14 @@ fn shows_pinned_in_directory_with_global_json() -> io::Result<()> {
#[ignore] #[ignore]
fn shows_pinned_in_project_below_root_with_global_json() -> io::Result<()> { fn shows_pinned_in_project_below_root_with_global_json() -> io::Result<()> {
let workspace = create_workspace(false)?; let workspace = create_workspace(false)?;
let global_json = make_pinned_sdk_json("1.2.3"); let global_json = make_pinned_sdk_json(DOTNET_PINNED_VERSION);
touch_path(&workspace, "global.json", Some(&global_json))?; touch_path(&workspace, "global.json", Some(&global_json))?;
touch_path(&workspace, "project/project.csproj", None)?; touch_path(&workspace, "project/project.csproj", None)?;
expect_output(&workspace, "project", Some("•NET v1.2.3"))?; expect_output(
&workspace,
"project",
Some(DOTNET_PINNED_VERSION_OUTPUT_PATTERN),
)?;
workspace.close() workspace.close()
} }
@ -82,10 +118,14 @@ fn shows_pinned_in_project_below_root_with_global_json() -> io::Result<()> {
#[ignore] #[ignore]
fn shows_pinned_in_deeply_nested_project_within_repository() -> io::Result<()> { fn shows_pinned_in_deeply_nested_project_within_repository() -> io::Result<()> {
let workspace = create_workspace(true)?; let workspace = create_workspace(true)?;
let global_json = make_pinned_sdk_json("1.2.3"); let global_json = make_pinned_sdk_json(DOTNET_PINNED_VERSION);
touch_path(&workspace, "global.json", Some(&global_json))?; touch_path(&workspace, "global.json", Some(&global_json))?;
touch_path(&workspace, "deep/path/to/project/project.csproj", None)?; touch_path(&workspace, "deep/path/to/project/project.csproj", None)?;
expect_output(&workspace, "deep/path/to/project", Some("•NET v1.2.3"))?; expect_output(
&workspace,
"deep/path/to/project",
Some(DOTNET_PINNED_VERSION_OUTPUT_PATTERN),
)?;
workspace.close() workspace.close()
} }
@ -137,7 +177,7 @@ fn make_pinned_sdk_json(version: &str) -> String {
json_text.replace("INSERT_VERSION", version) json_text.replace("INSERT_VERSION", version)
} }
fn expect_output(workspace: &TempDir, run_from: &str, contains: Option<&str>) -> io::Result<()> { fn expect_output(workspace: &TempDir, run_from: &str, pattern: Option<&str>) -> io::Result<()> {
let run_path = workspace.path().join(run_from); let run_path = workspace.path().join(run_from);
let output = common::render_module("dotnet") let output = common::render_module("dotnet")
.current_dir(run_path) .current_dir(run_path)
@ -147,8 +187,11 @@ fn expect_output(workspace: &TempDir, run_from: &str, contains: Option<&str>) ->
// This can be helpful for debugging // This can be helpful for debugging
eprintln!("The dotnet module showed: {}", text); eprintln!("The dotnet module showed: {}", text);
match contains { match pattern {
Some(contains) => assert!(text.contains(contains)), Some(pattern) => {
let re = Regex::new(pattern).unwrap();
assert!(re.is_match(&text));
}
None => assert!(text.is_empty()), None => assert!(text.is_empty()),
} }