Setup CI with Azure Pipelines
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 020002e..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,75 +0,0 @@
-language: rust
-rust: stable
-dist: trusty
-
-git:
- depth: 1
-
-matrix:
- include:
- - name: "rustfmt"
- env: TARGET=x86_64-unknown-linux-gnu
- rust: stable
- addons:
- before_script:
- - rustup component add rustfmt
- script:
- - cargo fmt --all -- --check
- - cd crates/cargo-test-macro
- - cargo fmt --all -- --check
- - cd ../crates-io
- - cargo fmt --all -- --check
- - cd ../resolver-tests
- - cargo fmt --all -- --check
- - cd ../../
-
- - env: TARGET=x86_64-unknown-linux-gnu
- ALT=i686-unknown-linux-gnu
- if: branch != master OR type = pull_request
-
- - env: TARGET=x86_64-apple-darwin
- ALT=i686-apple-darwin
- os: osx
- osx_image: xcode9.2
- if: branch != master OR type = pull_request
-
- - env: TARGET=x86_64-unknown-linux-gnu
- ALT=i686-unknown-linux-gnu
- rust: beta
- if: branch != master OR type = pull_request
-
- - env: TARGET=x86_64-unknown-linux-gnu
- ALT=i686-unknown-linux-gnu
- rust: nightly
- install:
- - travis_retry curl -Lf https://github.com/rust-lang-nursery/mdBook/releases/download/v0.3.1/mdbook-v0.3.1-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=$HOME/.cargo/bin
- script:
- - cargo test --features=deny-warnings || travis_terminate 1
- - cargo doc --no-deps || travis_terminate 1
- - (cd src/doc && mdbook build --dest-dir ../../target/doc) || travis_terminate 1
- if: branch != master OR type = pull_request
-
- - name: resolver tests
- rust: stable
- before_script: true
- script:
- - cargo test --manifest-path crates/resolver-tests/Cargo.toml
- if: branch != master OR type = pull_request
-
- exclude:
- - rust: stable
-
-before_script:
- - rustup target add $ALT
- - rustup component add clippy || echo "clippy not available"
-script:
- - cargo test --features=deny-warnings
-
-notifications:
- email:
- on_success: never
-
-addons:
- apt:
- packages:
- - gcc-multilib
diff --git a/README.md b/README.md
index 9bf4fa7..813c44f 100644
--- a/README.md
+++ b/README.md
@@ -6,8 +6,7 @@
## Code Status
-[](https://travis-ci.com/rust-lang/cargo)
-[](https://ci.appveyor.com/project/rust-lang-libs/cargo)
+[](https://dev.azure.com/rust-lang/cargo/_build/latest?definitionId=18&branchName=master)
Code documentation: https://docs.rs/cargo/
diff --git a/appveyor.yml b/appveyor.yml
deleted file mode 100644
index 4173501..0000000
--- a/appveyor.yml
+++ /dev/null
@@ -1,22 +0,0 @@
-environment:
- matrix:
- - TARGET: x86_64-pc-windows-msvc
- OTHER_TARGET: i686-pc-windows-msvc
-
-install:
- - if NOT defined APPVEYOR_PULL_REQUEST_NUMBER if "%APPVEYOR_REPO_BRANCH%" == "master" appveyor exit
- - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
- - rustup-init.exe -y --default-host x86_64-pc-windows-msvc --default-toolchain nightly
- - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
- - if defined OTHER_TARGET rustup target add %OTHER_TARGET%
- - rustup component add clippy || exit 0
- - rustc -V
- - cargo -V
- - git submodule update --init
-
-clone_depth: 1
-
-build: false
-
-test_script:
- - cargo test --features=deny-warnings
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
new file mode 100644
index 0000000..5bb3f65
--- /dev/null
+++ b/azure-pipelines.yml
@@ -0,0 +1,91 @@
+trigger:
+ branches:
+ include:
+ - '*'
+ exclude:
+ - master
+pr:
+- master
+
+jobs:
+- job: Linux
+ pool:
+ vmImage: ubuntu-16.04
+ steps:
+ - template: ci/azure-test-all.yml
+ strategy:
+ matrix:
+ stable:
+ TOOLCHAIN: stable
+ beta:
+ TOOLCHAIN: beta
+ nightly:
+ TOOLCHAIN: nightly
+ variables:
+ OTHER_TARGET: i686-unknown-linux-gnu
+
+- job: macOS
+ pool:
+ vmImage: macos-10.13
+ steps:
+ - template: ci/azure-test-all.yml
+ variables:
+ TOOLCHAIN: stable
+ OTHER_TARGET: i686-apple-darwin
+
+- job: Windows
+ pool:
+ vmImage: windows-2019
+ steps:
+ - template: ci/azure-test-all.yml
+ strategy:
+ matrix:
+ x86_64-msvc:
+ TOOLCHAIN: stable-x86_64-pc-windows-msvc
+ OTHER_TARGET: i686-pc-windows-msvc
+- job: rustfmt
+ pool:
+ vmImage: ubuntu-16.04
+ steps:
+ - template: ci/azure-install-rust.yml
+ - bash: rustup component add rustfmt
+ displayName: "Install rustfmt"
+ - bash: cargo fmt --all -- --check
+ displayName: "Check rustfmt (cargo)"
+ - bash: cd crates/cargo-test-macro && cargo fmt --all -- --check
+ displayName: "Check rustfmt (cargo-test-macro)"
+ - bash: cd crates/crates-io && cargo fmt --all -- --check
+ displayName: "Check rustfmt (crates-io)"
+ - bash: cd crates/resolver-tests && cargo fmt --all -- --check
+ displayName: "Check rustfmt (resolver-tests)"
+ variables:
+ TOOLCHAIN: stable
+
+- job: resolver
+ pool:
+ vmImage: ubuntu-16.04
+ steps:
+ - template: ci/azure-install-rust.yml
+ - bash: cargo test --manifest-path crates/resolver-tests/Cargo.toml
+ displayName: "Resolver tests"
+ variables:
+ TOOLCHAIN: stable
+
+- job: docs
+ pool:
+ vmImage: ubuntu-16.04
+ steps:
+ - template: ci/azure-install-rust.yml
+ - bash: |
+ set -e
+ mkdir mdbook
+ curl -Lf https://github.com/rust-lang-nursery/mdBook/releases/download/v0.3.1/mdbook-v0.3.1-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook
+ echo "##vso[task.prependpath]`pwd`/mdbook"
+ displayName: "Install mdbook"
+ - bash: cargo doc --no-deps
+ displayName: "Build documentation"
+ - bash: cd src/doc && mdbook build --dest-dir ../../target/doc
+ displayName: "Build mdbook documentation"
+ variables:
+ TOOLCHAIN: stable
+
diff --git a/ci/azure-install-rust.yml b/ci/azure-install-rust.yml
new file mode 100644
index 0000000..c48d0d0
--- /dev/null
+++ b/ci/azure-install-rust.yml
@@ -0,0 +1,28 @@
+steps:
+ - bash: |
+ set -e
+ if command -v rustup; then
+ echo `command -v rustup` `rustup -V` already installed
+ rustup self update
+ elif [ "$AGENT_OS" = "Windows_NT" ]; then
+ curl -sSf -o rustup-init.exe https://win.rustup.rs
+ rustup-init.exe -y --default-toolchain $TOOLCHAIN
+ echo "##vso[task.prependpath]$USERPROFILE/.cargo/bin"
+ else
+ curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain $TOOLCHAIN
+ echo "##vso[task.prependpath]$HOME/.cargo/bin"
+ fi
+ displayName: Install rustup
+
+ - bash: |
+ set -e
+ rustup update $TOOLCHAIN
+ rustup default $TOOLCHAIN
+ displayName: Install rust
+
+ - bash: |
+ set -ex
+ rustup -V
+ rustc -Vv
+ cargo -V
+ displayName: Query rust and cargo versions
diff --git a/ci/azure-test-all.yml b/ci/azure-test-all.yml
new file mode 100644
index 0000000..6268584
--- /dev/null
+++ b/ci/azure-test-all.yml
@@ -0,0 +1,28 @@
+steps:
+- checkout: self
+ fetchDepth: 1
+
+- template: azure-install-rust.yml
+
+- bash: rustup target add $OTHER_TARGET
+ displayName: "Install cross-compile target"
+
+- bash: sudo apt install gcc-multilib
+ displayName: "Install gcc-multilib (linux)"
+ condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
+
+# Some tests rely on a clippy command to run, so let's try to install clippy to
+# we can be sure to run those tests.
+- bash: rustup component add clippy || echo "clippy not available"
+ displayName: "Install clippy (maybe)"
+
+# Deny warnings on CI to avoid warnings getting into the codebase, and note the
+# `force-system-lib-on-osx` which is intended to fix compile issues on OSX where
+# compiling curl from source on OSX yields linker errors on Azure.
+#
+# Note that the curl issue is traced back to alexcrichton/curl-rust#279 where it
+# looks like the OSX version we're actually running on is such that a symbol is
+# emitted that's never worked. For now force the system library to be used to
+# fix the link errors.
+- bash: cargo test --features 'deny-warnings curl/force-system-lib-on-osx'
+ displayName: "cargo test"
diff --git a/tests/testsuite/config.rs b/tests/testsuite/config.rs
index d54bc64..01f7927 100644
--- a/tests/testsuite/config.rs
+++ b/tests/testsuite/config.rs
@@ -2,12 +2,18 @@
use std::collections;
use std::fs;
-use crate::support::{lines_match, paths, project};
+use crate::support::{paths, project};
use cargo::core::{enable_nightly_features, Shell};
use cargo::util::config::{self, Config};
use cargo::util::toml::{self, VecStringOrBool as VSOB};
use serde::Deserialize;
+fn lines_match(a: &str, b: &str) -> bool {
+ // Perform a small amount of normalization for filesystem paths before we
+ // send this to the `lines_match` function.
+ crate::support::lines_match(&a.replace("\\", "/"), &b.replace("\\", "/"))
+}
+
#[cargo_test]
fn read_env_vars_for_config() {
let p = project()
diff --git a/tests/testsuite/support/mod.rs b/tests/testsuite/support/mod.rs
index 745dc87..ac7c55a 100644
--- a/tests/testsuite/support/mod.rs
+++ b/tests/testsuite/support/mod.rs
@@ -578,8 +578,8 @@
expect_stderr_unordered: Vec<String>,
expect_neither_contains: Vec<String>,
expect_stderr_with_without: Vec<(Vec<String>, Vec<String>)>,
- expect_json: Option<Vec<Value>>,
- expect_json_contains_unordered: Vec<Value>,
+ expect_json: Option<Vec<String>>,
+ expect_json_contains_unordered: Vec<String>,
stream_output: bool,
}
@@ -746,7 +746,7 @@
self.expect_json = Some(
expected
.split("\n\n")
- .map(|line| line.parse().expect("line to be a valid JSON value"))
+ .map(|line| line.to_string())
.collect(),
);
self
@@ -762,11 +762,8 @@
///
/// See `with_json` for more detail.
pub fn with_json_contains_unordered(&mut self, expected: &str) -> &mut Self {
- self.expect_json_contains_unordered.extend(
- expected
- .split("\n\n")
- .map(|line| line.parse().expect("line to be a valid JSON value")),
- );
+ self.expect_json_contains_unordered
+ .extend(expected.split("\n\n").map(|line| line.to_string()));
self
}
@@ -1110,25 +1107,51 @@
Err(..) => return Err(format!("{} was not utf8 encoded", description)),
Ok(actual) => actual,
};
- // Let's not deal with \r\n vs \n on windows...
- let actual = actual.replace("\r", "");
- let actual = actual.replace("\t", "<tab>");
- Ok(actual)
+ Ok(self.normalize_matcher(actual))
}
- fn replace_expected(&self, expected: &str) -> String {
+ fn normalize_matcher(&self, matcher: &str) -> String {
+ // Let's not deal with / vs \ (windows...)
+ let matcher = matcher.replace("\\\\", "/").replace("\\", "/");
+
+ // Weirdness for paths on Windows extends beyond `/` vs `\` apparently.
+ // Namely paths like `c:\` and `C:\` are equivalent and that can cause
+ // issues. The return value of `env::current_dir()` may return a
+ // lowercase drive name, but we round-trip a lot of values through `Url`
+ // which will auto-uppercase the drive name. To just ignore this
+ // distinction we try to canonicalize as much as possible, taking all
+ // forms of a path and canonicalizing them to one.
+ let replace_path = |s: &str, path: &Path, with: &str| {
+ let path_through_url = Url::from_file_path(path).unwrap().to_file_path().unwrap();
+ let path1 = path.display().to_string().replace("\\", "/");
+ let path2 = path_through_url.display().to_string().replace("\\", "/");
+ s.replace(&path1, with)
+ .replace(&path2, with)
+ .replace(with, &path1)
+ };
+
// Do the template replacements on the expected string.
- let replaced = match self.process_builder {
- None => expected.to_string(),
- Some(ref p) => match p.get_cwd() {
- None => expected.to_string(),
- Some(cwd) => expected.replace("[CWD]", &cwd.display().to_string()),
+ let matcher = match &self.process_builder {
+ None => matcher.to_string(),
+ Some(p) => match p.get_cwd() {
+ None => matcher.to_string(),
+ Some(cwd) => replace_path(&matcher, cwd, "[CWD]"),
},
};
- // On Windows, we need to use a wildcard for the drive,
- // because we don't actually know what it will be.
- replaced.replace("[ROOT]", if cfg!(windows) { r#"[..]:\"# } else { "/" })
+ // Similar to cwd above, perform similar treatment to the root path
+ // which in theory all of our paths should otherwise get rooted at.
+ let root = paths::root();
+ let matcher = replace_path(&matcher, &root, "[ROOT]");
+
+ // Let's not deal with \r\n vs \n on windows...
+ let matcher = matcher.replace("\r", "");
+
+ // It's easier to read tabs in outputs if they don't show up as literal
+ // hidden characters
+ let matcher = matcher.replace("\t", "<tab>");
+
+ return matcher;
}
fn match_std(
@@ -1140,7 +1163,7 @@
kind: MatchKind,
) -> MatchResult {
let out = match expected {
- Some(out) => self.replace_expected(out),
+ Some(out) => self.normalize_matcher(out),
None => return Ok(()),
};
@@ -1276,7 +1299,7 @@
) -> MatchResult {
let actual = self.normalize_actual("stderr", actual)?;
let contains = |s, line| {
- let mut s = self.replace_expected(s);
+ let mut s = self.normalize_matcher(s);
s.insert_str(0, "[..]");
s.push_str("[..]");
lines_match(&s, line)
@@ -1309,13 +1332,19 @@
}
}
- fn match_json(&self, expected: &Value, line: &str) -> MatchResult {
+ fn match_json(&self, expected: &str, line: &str) -> MatchResult {
+ let expected = self.normalize_matcher(expected);
+ let line = self.normalize_matcher(line);
let actual = match line.parse() {
Err(e) => return Err(format!("invalid json, {}:\n`{}`", e, line)),
Ok(actual) => actual,
};
+ let expected = match expected.parse() {
+ Err(e) => return Err(format!("invalid json, {}:\n`{}`", e, line)),
+ Ok(expected) => expected,
+ };
- find_json_mismatch(expected, &actual)
+ find_json_mismatch(&expected, &actual)
}
fn diff_lines<'a>(
@@ -1372,14 +1401,9 @@
/// - There is a wide range of macros (such as `[COMPILING]` or `[WARNING]`)
/// to match cargo's "status" output and allows you to ignore the alignment.
/// See `substitute_macros` for a complete list of macros.
-/// - `[ROOT]` is `/` or `[..]:\` on Windows.
+/// - `[ROOT]` the path to the test directory's root
/// - `[CWD]` is the working directory of the process that was run.
-pub fn lines_match(expected: &str, actual: &str) -> bool {
- // Let's not deal with / vs \ (windows...)
- // First replace backslash-escaped backslashes with forward slashes
- // which can occur in, for example, JSON output
- let expected = expected.replace("\\\\", "/").replace("\\", "/");
- let mut actual: &str = &actual.replace("\\\\", "/").replace("\\", "/");
+pub fn lines_match(expected: &str, mut actual: &str) -> bool {
let expected = substitute_macros(&expected);
for (i, part) in expected.split("[..]").enumerate() {
match actual.find(part) {
@@ -1742,7 +1766,7 @@
// This should actually be a test that `$CARGO_TARGET_DIR` is on an HFS
// filesystem, (or any filesystem with low-resolution mtimes). However,
// that's tricky to detect, so for now just deal with CI.
- cfg!(target_os = "macos") && env::var("CI").is_ok()
+ cfg!(target_os = "macos") && (env::var("CI").is_ok() || env::var("TF_BUILD").is_ok())
}
/// Some CI setups are much slower then the equipment used by Cargo itself.
diff --git a/tests/testsuite/tool_paths.rs b/tests/testsuite/tool_paths.rs
index 8633871..07dfa08 100644
--- a/tests/testsuite/tool_paths.rs
+++ b/tests/testsuite/tool_paths.rs
@@ -64,11 +64,15 @@
)
.build();
- foo.cargo("build --verbose").with_stderr("\
+ foo.cargo("build --verbose")
+ .with_stderr(
+ "\
[COMPILING] foo v0.5.0 ([CWD])
-[RUNNING] `rustc [..] -C ar=[ROOT]bogus/nonexistent-ar -C linker=[ROOT]bogus/nonexistent-linker [..]`
+[RUNNING] `rustc [..] -C ar=[..]bogus/nonexistent-ar -C linker=[..]bogus/nonexistent-linker [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
-").run();
+",
+ )
+ .run();
}
#[cargo_test]