├── sub ├── src │ ├── setup.rs │ └── lib.rs ├── Cargo.lock └── Cargo.toml ├── .gitignore ├── .editorconfig ├── Cargo.lock ├── Cargo.toml ├── src └── lib.rs ├── LICENSE ├── CHANGELOG.md ├── install-rust.yml ├── azure-pipelines.yml ├── nightly-only.yml ├── default.yml ├── coverage.yml └── README.md /sub/src/setup.rs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | src/setup.rs 3 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*.yml] 4 | indent_style = space 5 | indent_size = 2 6 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "ci-demo" 5 | version = "0.1.0" 6 | 7 | -------------------------------------------------------------------------------- /sub/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "ci-demo" 5 | version = "0.1.0" 6 | -------------------------------------------------------------------------------- /sub/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | #[test] 3 | fn always_test() {} 4 | 5 | #[cfg(test)] 6 | #[test] 7 | fn require_env() { 8 | std::env::var("SUBENV_IS_SET").unwrap(); 9 | } 10 | 11 | #[cfg(test)] 12 | #[test] 13 | fn require_setup_file() { 14 | include_str!("setup.rs"); 15 | } 16 | 17 | // check that minrust gets set correctly 18 | #[allow(unused_imports)] 19 | use std::sync::atomic::AtomicU64; 20 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ci-demo" 3 | version = "0.1.0" 4 | authors = ["Jon Gjengset "] 5 | edition = "2018" 6 | 7 | [features] 8 | opt_out = [] 9 | opt_in = [] 10 | ci = [] 11 | default = ["opt_out"] 12 | 13 | [badges] 14 | azure-devops = { project = "crate-ci/crate-ci", pipeline = "azure-pipelines", build = "3" } 15 | codecov = { repository = "crate-ci/azure-pipelines", branch = "master", service = "github" } 16 | -------------------------------------------------------------------------------- /sub/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ci-demo" 3 | version = "0.1.0" 4 | authors = ["Jon Gjengset "] 5 | edition = "2018" 6 | 7 | [features] 8 | opt_out = [] 9 | opt_in = [] 10 | ci = [] 11 | default = ["opt_out"] 12 | 13 | [badges] 14 | azure-devops = { project = "crate-ci/crate-ci", pipeline = "azure-pipelines", build = "3" } 15 | codecov = { repository = "crate-ci/azure-pipelines", branch = "master", service = "github" } 16 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(all(test, feature = "opt_in"))] 2 | #[test] 3 | fn opt_in_test() {} 4 | 5 | #[cfg(all(test, feature = "opt_out"))] 6 | #[test] 7 | fn opt_out_test() {} 8 | 9 | #[cfg(test)] 10 | #[test] 11 | fn always_test() {} 12 | 13 | #[cfg(test)] 14 | #[test] 15 | fn require_env() { 16 | std::env::var("ENV_IS_SET").unwrap(); 17 | } 18 | 19 | #[cfg(test)] 20 | #[test] 21 | fn require_setup_file() { 22 | include_str!("setup.rs"); 23 | } 24 | 25 | // check that minrust gets set correctly 26 | #[allow(unused_imports)] 27 | use std::sync::atomic::AtomicU64; 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Jon Gjengset 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [0.4] - 2020-03-16 8 | ### Changed 9 | - Ubuntu and macOS images updated to the latest available (18.04 and 10 | 10.15 respectively). 11 | 12 | ## [0.3] - 2019-12-28 13 | ### Added 14 | - `default.yml` opinionated default CI for "regular" Rust crates. 15 | - `install-rust.yml` task for installing Rust 16 | 17 | ### Changed 18 | 19 | ### Removed 20 | - Everything in `azure/`, pretty much all customization options. 21 | The intention is that each project now either uses `defaults.yml` or 22 | copy-pastes it into their own `azure-pipelines.yml` and modifies it as 23 | needed. 24 | See [#73](https://github.com/crate-ci/azure-pipelines/pull/73). 25 | 26 | ## [0.2] - 2019-10-18 27 | ### Added 28 | 29 | ### Changed 30 | - Features changed from being a string to being a list ([#65](https://github.com/crate-ci/azure-pipelines/pull/65)) 31 | 32 | [0.4]: https://github.com/crate-ci/azure-pipelines/compare/v0.3...v0.4 33 | [0.3]: https://github.com/crate-ci/azure-pipelines/compare/v0.2...v0.3 34 | [0.2]: https://github.com/crate-ci/azure-pipelines/compare/v0.1...v0.2 35 | -------------------------------------------------------------------------------- /install-rust.yml: -------------------------------------------------------------------------------- 1 | # defaults for any parameters that aren't specified 2 | parameters: 3 | rust: stable 4 | components: [] 5 | targets: [] 6 | 7 | steps: 8 | # Linux and macOS. 9 | - script: | 10 | set -e 11 | curl https://sh.rustup.rs -sSf | sh -s -- -y --profile minimal --default-toolchain $RUSTUP_TOOLCHAIN 12 | echo "##vso[task.setvariable variable=PATH;]$PATH:$HOME/.cargo/bin" 13 | env: 14 | RUSTUP_TOOLCHAIN: ${{parameters.rust}} 15 | displayName: "Install rust (*nix)" 16 | condition: not(eq(variables['Agent.OS'], 'Windows_NT')) 17 | 18 | # Windows. 19 | - script: | 20 | curl -sSf -o rustup-init.exe https://win.rustup.rs 21 | rustup-init.exe -y --profile minimal --default-toolchain %RUSTUP_TOOLCHAIN% --default-host x86_64-pc-windows-msvc 22 | set PATH=%PATH%;%USERPROFILE%\.cargo\bin 23 | echo "##vso[task.setvariable variable=PATH;]%PATH%;%USERPROFILE%\.cargo\bin" 24 | env: 25 | RUSTUP_TOOLCHAIN: ${{parameters.rust}} 26 | displayName: "Install rust (windows)" 27 | condition: eq(variables['Agent.OS'], 'Windows_NT') 28 | 29 | # Set correct toolchain 30 | - bash: | 31 | rustup default $RUSTUP_TOOLCHAIN 32 | rustup update $RUSTUP_TOOLCHAIN 33 | env: 34 | RUSTUP_TOOLCHAIN: ${{parameters.rust}} 35 | displayName: "Set correct Rust version" 36 | 37 | # Install additional targets: 38 | - ${{ each target in parameters.targets }}: 39 | - script: rustup target add ${{ target }} 40 | displayName: "Adding target '${{ target }}'" 41 | 42 | # Install additional components: 43 | - ${{ each component in parameters.components }}: 44 | - script: rustup component add ${{ component }} 45 | displayName: "Adding component '${{ component }}'" 46 | 47 | # See what we got 48 | - script: | 49 | rustc --version 50 | cargo --version 51 | rustup --version 52 | displayName: Check installed rust version 53 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | stages: 2 | - stage: primary 3 | jobs: 4 | - template: default.yml 5 | parameters: 6 | minrust: 1.34.0 # integer atomics 7 | codecov_token: $(CODECOV_TOKEN_SECRET) 8 | env: 9 | ENV_IS_SET: true 10 | setup: 11 | - script: touch src/setup.rs 12 | displayName: touch src/setup.rs 13 | - stage: subdir 14 | jobs: 15 | - template: default.yml 16 | parameters: 17 | minrust: 1.34.0 # integer atomics 18 | codecov_token: $(CODECOV_TOKEN_SECRET) 19 | dir: sub 20 | env: 21 | SUBENV_IS_SET: true 22 | setup: 23 | - script: touch sub/src/setup.rs 24 | displayName: touch sub/src/setup.rs 25 | # should work without code coverage token 26 | - stage: bad_coverage_token 27 | dependsOn: [] 28 | jobs: 29 | - template: default.yml 30 | parameters: 31 | minrust: 1.34.0 32 | codecov_token: $(DOES_NOT_EXIST) 33 | env: 34 | ENV_IS_SET: true 35 | setup: 36 | - script: touch src/setup.rs 37 | displayName: touch src/setup.rs 38 | # visual check that cross: false is indeed Linux-only 39 | - stage: no_cross 40 | dependsOn: [] 41 | jobs: 42 | - template: default.yml 43 | parameters: 44 | minrust: 1.34.0 45 | cross: false 46 | env: 47 | ENV_IS_SET: true 48 | setup: 49 | - script: touch src/setup.rs 50 | displayName: touch src/setup.rs 51 | # visual check that the develop-nightly image is used for tarpaulin 52 | - stage: ci_image 53 | dependsOn: [] 54 | jobs: 55 | - template: coverage.yml 56 | parameters: 57 | token: $(CODECOV_TOKEN_SECRET) 58 | version: develop 59 | nightly: true # check that even with this set to true, image is still develop 60 | env: 61 | ENV_IS_SET: true 62 | setup: 63 | - script: touch src/setup.rs 64 | displayName: touch src/setup.rs 65 | -------------------------------------------------------------------------------- /nightly-only.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | min: false 3 | setup: [] 4 | services: {} 5 | env: {} 6 | cross: true 7 | dir: "." 8 | 9 | jobs: 10 | - job: style 11 | displayName: Style linting 12 | pool: 13 | vmImage: ubuntu-22.04 14 | continueOnError: true 15 | steps: 16 | # latest nightly may not have rustfmt/clippy 17 | # we can't check for both: 18 | # https://github.com/rust-lang/rustup-components-history/issues/9 19 | # but we at least check for one. 20 | # rustfmt _seems_ to break most often: 21 | - bash: | 22 | echo '##vso[task.setvariable variable=nightly]nightly-'$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/rustfmt) 23 | displayName: "Determine latest style nightly" 24 | - template: install-rust.yml 25 | parameters: 26 | rust: $(nightly) 27 | components: 28 | - rustfmt 29 | - clippy 30 | # Run any user-specific setup steps 31 | - ${{ parameters.setup }} 32 | - script: cargo fmt --all -- --check 33 | workingDirectory: ${{ parameters.dir }} 34 | displayName: cargo fmt --check 35 | - script: cargo clippy --all 36 | workingDirectory: ${{ parameters.dir }} 37 | displayName: cargo clippy -- -D warnings 38 | - job: main 39 | displayName: Compile and test 40 | dependsOn: [] 41 | ${{ if eq('true', parameters.cross) }}: 42 | strategy: 43 | matrix: 44 | Linux: 45 | vmImage: ubuntu-22.04 46 | rust: nightly 47 | MacOS: 48 | vmImage: macOS-12 49 | rust: nightly 50 | Windows: 51 | vmImage: windows-2019 52 | rust: nightly 53 | ${{ if ne('true', parameters.cross) }}: 54 | strategy: 55 | matrix: 56 | Linux: 57 | vmImage: ubuntu-22.04 58 | rust: nightly 59 | pool: 60 | vmImage: $(vmImage) 61 | services: 62 | ${{ insert }}: ${{ parameters.services }} 63 | steps: 64 | - template: install-rust.yml 65 | parameters: 66 | rust: $(rust) 67 | # Run any user-specific setup steps 68 | - ${{ parameters.setup }} 69 | - script: cargo check 70 | workingDirectory: ${{ parameters.dir }} 71 | displayName: cargo check 72 | - script: cargo check --no-default-features 73 | workingDirectory: ${{ parameters.dir }} 74 | displayName: cargo check --no-default-features 75 | - script: cargo check --all-features 76 | workingDirectory: ${{ parameters.dir }} 77 | displayName: cargo check --all-features 78 | - script: cargo test --all-features 79 | workingDirectory: ${{ parameters.dir }} 80 | displayName: cargo test 81 | env: 82 | ${{ insert }}: ${{ parameters.env }} 83 | - script: cargo doc --no-deps 84 | workingDirectory: ${{ parameters.dir }} 85 | displayName: cargo doc 86 | - ${{ if ne('false', parameters.min) }}: 87 | - job: msrv 88 | displayName: "${{ format('Minimum supported Rust nightly: {0}', parameters.min) }}" 89 | dependsOn: [] 90 | # This represents the minimum Rust version supported. 91 | # Tests are not run as tests may require newer versions of nightly. 92 | pool: 93 | vmImage: ubuntu-22.04 94 | steps: 95 | - template: install-rust.yml 96 | parameters: 97 | rust: "${{ format('nightly-{0}', parameters.min) }}" 98 | # Run any user-specific setup steps 99 | - ${{ parameters.setup }} 100 | - script: cargo check 101 | workingDirectory: ${{ parameters.dir }} 102 | displayName: cargo check 103 | - script: cargo check --no-default-features 104 | workingDirectory: ${{ parameters.dir }} 105 | displayName: cargo check --no-default-features 106 | - script: cargo check --all-features 107 | workingDirectory: ${{ parameters.dir }} 108 | displayName: cargo check --all-features 109 | - ${{ if ne('', parameters.codecov_token) }}: 110 | - template: coverage.yml 111 | parameters: 112 | token: ${{ parameters.codecov_token }} 113 | setup: ${{ parameters.setup }} 114 | services: ${{ parameters.services }} 115 | env: ${{ parameters.env }} 116 | dir: ${{ parameters.dir }} 117 | nightly: true 118 | -------------------------------------------------------------------------------- /default.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | minrust: 1.32.0 # Rust 2018 with uniform paths 3 | setup: [] 4 | services: {} 5 | env: {} 6 | cross: true 7 | dir: "." 8 | 9 | jobs: 10 | - job: style 11 | displayName: Style linting 12 | strategy: 13 | matrix: 14 | stable: 15 | rust: stable 16 | beta: 17 | rust: beta 18 | pool: 19 | vmImage: ubuntu-22.04 20 | continueOnError: $[eq(variables.rust, 'beta')] 21 | steps: 22 | - template: install-rust.yml 23 | parameters: 24 | rust: $(rust) 25 | components: 26 | - rustfmt 27 | - clippy 28 | # Run any user-specific setup steps 29 | - ${{ parameters.setup }} 30 | - script: cargo fmt --all -- --check 31 | workingDirectory: ${{ parameters.dir }} 32 | displayName: cargo fmt --check 33 | - script: cargo clippy --all -- -D warnings 34 | workingDirectory: ${{ parameters.dir }} 35 | displayName: cargo clippy -- -D warnings 36 | - job: main 37 | displayName: Compile and test 38 | dependsOn: [] 39 | ${{ if eq('true', parameters.cross) }}: 40 | strategy: 41 | matrix: 42 | "Linux (nightly)": 43 | vmImage: ubuntu-22.04 44 | rust: nightly 45 | "Linux (beta)": 46 | vmImage: ubuntu-22.04 47 | rust: beta 48 | Linux: 49 | vmImage: ubuntu-22.04 50 | rust: stable 51 | MacOS: 52 | vmImage: macOS-12 53 | rust: stable 54 | Windows: 55 | vmImage: windows-2019 56 | rust: stable 57 | ${{ if ne('true', parameters.cross) }}: 58 | strategy: 59 | matrix: 60 | "Linux (nightly)": 61 | vmImage: ubuntu-22.04 62 | rust: nightly 63 | "Linux (beta)": 64 | vmImage: ubuntu-22.04 65 | rust: beta 66 | Linux: 67 | vmImage: ubuntu-22.04 68 | rust: stable 69 | pool: 70 | vmImage: $(vmImage) 71 | services: 72 | ${{ insert }}: ${{ parameters.services }} 73 | continueOnError: $[eq(variables.rust, 'nightly')] 74 | steps: 75 | - template: install-rust.yml 76 | parameters: 77 | rust: $(rust) 78 | # Run any user-specific setup steps 79 | - ${{ parameters.setup }} 80 | - script: cargo check 81 | workingDirectory: ${{ parameters.dir }} 82 | displayName: cargo check 83 | - script: cargo check --no-default-features 84 | workingDirectory: ${{ parameters.dir }} 85 | displayName: cargo check --no-default-features 86 | - script: cargo check --all-features 87 | workingDirectory: ${{ parameters.dir }} 88 | displayName: cargo check --all-features 89 | - script: cargo test --all-features 90 | workingDirectory: ${{ parameters.dir }} 91 | displayName: cargo test 92 | env: 93 | ${{ insert }}: ${{ parameters.env }} 94 | - script: cargo doc --no-deps 95 | workingDirectory: ${{ parameters.dir }} 96 | displayName: cargo doc 97 | - ${{ if ne('false', parameters.minrust) }}: 98 | - job: msrv 99 | displayName: "${{ format('Minimum supported Rust version: {0}', parameters.minrust) }}" 100 | dependsOn: [] 101 | # This represents the minimum Rust version supported. 102 | # Tests are not run as tests may require newer versions of rust. 103 | pool: 104 | vmImage: ubuntu-22.04 105 | steps: 106 | - template: install-rust.yml 107 | parameters: 108 | rust: ${{ parameters.minrust }} 109 | # Run any user-specific setup steps 110 | - ${{ parameters.setup }} 111 | - script: cargo check 112 | workingDirectory: ${{ parameters.dir }} 113 | displayName: cargo check 114 | - script: cargo check --no-default-features 115 | workingDirectory: ${{ parameters.dir }} 116 | displayName: cargo check --no-default-features 117 | - script: cargo check --all-features 118 | workingDirectory: ${{ parameters.dir }} 119 | displayName: cargo check --all-features 120 | - ${{ if ne('', parameters.codecov_token) }}: 121 | - template: coverage.yml 122 | parameters: 123 | token: ${{ parameters.codecov_token }} 124 | setup: ${{ parameters.setup }} 125 | services: ${{ parameters.services }} 126 | env: ${{ parameters.env }} 127 | dir: ${{ parameters.dir }} 128 | -------------------------------------------------------------------------------- /coverage.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | nightly: false 3 | version: 'latest' 4 | doctests: false 5 | setup: [] 6 | services: {} 7 | env: {} 8 | args: '' 9 | dir: "." 10 | 11 | jobs: 12 | - job: precheck 13 | displayName: Check for code coverage token 14 | pool: 15 | vmImage: ubuntu-22.04 16 | steps: 17 | # workaround for https://github.com/MicrosoftDocs/vsts-docs/issues/4841 18 | # note that we intentionally do not leak the secret itself 19 | - bash: | 20 | if [[ -n $CHECK ]] && [[ ! $CHECK == '$('* ]]; then 21 | echo '##vso[task.setvariable variable=has_secret;isOutput=true]true' 22 | else 23 | echo '##vso[task.setvariable variable=has_secret;isOutput=true]false' 24 | fi 25 | name: secret_check 26 | displayName: Is the token set? 27 | env: 28 | CHECK: ${{ parameters.token }} 29 | - job: tarpaulin 30 | dependsOn: precheck 31 | displayName: tarpaulin 32 | condition: and(succeeded(), eq(dependencies.precheck.outputs['secret_check.has_secret'], 'true')) 33 | pool: 34 | vmImage: ubuntu-22.04 35 | services: 36 | ${{ insert }}: ${{ parameters.services }} 37 | continueOnError: ${{ parameters.nightly }} 38 | container: 39 | ${{ if ne('latest', parameters.version) }}: 40 | image: ${{ format('xd009642/tarpaulin:{0}', parameters.version) }} 41 | ${{ if eq('latest', parameters.version) }}: 42 | ${{ if eq('true', parameters.nightly) }}: 43 | image: 'xd009642/tarpaulin:latest-nightly' 44 | ${{ if ne('true', parameters.nightly) }}: 45 | image: 'xd009642/tarpaulin:latest' 46 | options: --security-opt seccomp=unconfined 47 | steps: 48 | # Run any user-specific setup steps 49 | - ${{ parameters.setup }} 50 | - ${{ if eq('true', parameters.doctests) }}: 51 | - script: cargo tarpaulin ${{ parameters.args }} --run-types Doctests --run-types Tests --out Xml 52 | workingDirectory: ${{ parameters.dir }} 53 | displayName: Run tarpaulin 54 | env: 55 | ${{ insert }}: ${{ parameters.env }} 56 | - ${{ if ne('true', parameters.doctests) }}: 57 | - script: cargo tarpaulin ${{ parameters.args }} --out Xml 58 | workingDirectory: ${{ parameters.dir }} 59 | displayName: Run tarpaulin 60 | env: 61 | ${{ insert }}: ${{ parameters.env }} 62 | - bash: | 63 | curl -Os https://uploader.codecov.io/latest/linux/codecov 64 | curl -Os https://uploader.codecov.io/latest/linux/codecov.SHA256SUM 65 | shasum -a 256 -c codecov.SHA256SUM 66 | curl -Os https://uploader.codecov.io/latest/linux/codecov.SHA256SUM.sig 67 | gpg --import <<-EOF 68 | -----BEGIN PGP PUBLIC KEY BLOCK----- 69 | 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 117 | =ch7z 118 | -----END PGP PUBLIC KEY BLOCK----- 119 | EOF 120 | gpg --verify codecov.SHA256SUM.sig codecov.SHA256SUM 121 | chmod +x codecov 122 | ./codecov -t ${CODECOV_TOKEN} 123 | workingDirectory: ${{ parameters.dir }} 124 | displayName: Upload results to codecov 125 | env: 126 | CODECOV_TOKEN: ${{ parameters.token }} 127 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://dev.azure.com/crate-ci/crate-ci/_apis/build/status/azure-pipelines?branchName=master)](https://dev.azure.com/crate-ci/crate-ci/_build/latest?definitionId=3&branchName=master) 2 | [![Codecov](https://codecov.io/github/crate-ci/azure-pipelines/coverage.svg?branch=master)](https://codecov.io/gh/crate-ci/azure-pipelines) 3 | [![Documentation](https://img.shields.io/badge/documentation-here-blue.svg)](https://crate-ci.github.io/azure-pipelines/) 4 | 5 | Ah, so you want to set up continuous integration (CI) testing for your 6 | Rust project, and you decided you wanted to use Azure Pipelines for it? 7 | Well, you're in the right place! 8 | 9 | Azure Pipelines, like many other CI services, basically requires you to 10 | fully spell out all the steps to your CI. This is very handy if you have 11 | a complex CI pipeline, but is pretty inconvenient if you just want 12 | something that _just works_. This project aims to bridge that gap. It 13 | also tries to guide you through how to even get Azure Pipelines set up 14 | in the first place, which can be a daunting thing to get right! 15 | 16 | If you're curious what your CI will ultimately look like, go take a look 17 | at [`tracing-timing`'s 18 | CI](https://dev.azure.com/jonhoo/jonhoo/_build/latest?definitionId=1&branchName=master) 19 | for example. By default, it tests on all platforms, checks that your 20 | code compiles with and without any features it may have, and ensures 21 | that your code works with an older Rust version. You can also 22 | mix-and-match these checks if you wish. 23 | 24 | The repository provides three main templates: 25 | 26 | - `default.yml`, which is a highly opinionated default CI that you can 27 | use for most "normal" Rust projects. 28 | - `nightly-only.yml`, which is a highly opinionated default CI that you 29 | can use for Rust projects that only support nightly versions of Rust. 30 | - `install-rust.yml`, a minimal template that just installs Rust and 31 | has you write out the commands you want CI to run (see 32 | `default.yml` for inspiration). You can specify a Rust version, 33 | additional targets, and additional components. 34 | 35 | Below are instructions for how to set up your repository with testing 36 | from this repository, for setting up code coverage, and for configuring 37 | various parameters of the default CI template. 38 | 39 | --- 40 | 41 | ## If you've done this before: 42 | 43 | If you've done this before, and just want the standard YAML again for 44 | `azure-pipelines.yml`, here it is: 45 | 46 | ```yaml 47 | jobs: 48 | - template: default.yml@templates 49 | 50 | resources: 51 | repositories: 52 | - repository: templates 53 | type: github 54 | name: crate-ci/azure-pipelines 55 | ref: refs/heads/v0.4 56 | endpoint: YOU_NEED_TO_SET_THIS 57 | ``` 58 | 59 | --- 60 | 61 | ## If you're getting something new set up: 62 | 63 | Getting Azure Pipelines and its connection to GitHub set up correctly is 64 | not entirely straightforward. This document takes you through _exactly_ 65 | the steps you need to do. Stray from these at your own risk. 66 | 67 | ### Setting up Azure DevOps 68 | 69 | Azure _loves_ to try to get you to sign in to GitHub using OAuth, 70 | thereby giving them access to all your public _and private_ repos. This 71 | makes us sad. Here's how you do it "the new way" instead. 72 | 73 | First, make sure you have the Azure Pipelines GitHub Application installed: 74 | 75 | - Install the GitHub Azure Pipelines app: https://github.com/apps/azure-pipelines 76 | - Click "Configure" 77 | - Click the user or organization you want CI for 78 | - Towards the bottom, either choose "All repositories" or select the 79 | repository you want CI for 80 | 81 | Then, make sure you have an Azure Project for your GitHub organization: 82 | 83 | - "Create project" over at https://dev.azure.com/ 84 | - Make it public (probably) 85 | 86 | Note that Azure associates only _one_ of your projects with a given 87 | organization's GitHub Apps install, so you _cannot_ have multiple Azure 88 | Projects that are linked to different GitHub projects under the same 89 | GitHub user/organization. This is stupid, but such is life. 90 | 91 | This template uses [Build 92 | stages](https://docs.microsoft.com/en-us/azure/devops/pipelines/process/stages), 93 | which is a [preview 94 | feature](https://docs.microsoft.com/en-us/azure/devops/project/navigation/preview-features) 95 | of Azure Pipelines. You therefore need to enable support for it. To do 96 | so, click your profile icon in the top-right corner and click "Preview 97 | features". In the drop-down at the top in the panel that appears, choose 98 | "for this organization", then enable "Multi-stage pipelines". 99 | 100 | ### Adding CI for a GitHub repository 101 | 102 | At this point I'll assume you have an Azure Project correctly set up for 103 | your GitHub user or organization (as described above). 104 | 105 | Before we continue, there's a fun little step you have to do first. Go 106 | to "Project settings" (bottom left), the "Service connections" (under 107 | "Pipelines"). There should be one thing listed there, and it's your 108 | authenticated connection to GitHub. Note down its name. 109 | 110 | Now, create a file `azure-pipelines.yml` in the root of the repository 111 | you want CI for. If you want all the bells and whistles, write: 112 | 113 | ```yaml 114 | jobs: 115 | - template: default.yml@templates 116 | 117 | resources: 118 | repositories: 119 | - repository: templates 120 | type: github 121 | name: crate-ci/azure-pipelines 122 | ref: refs/heads/v0.4 123 | endpoint: PLACEHOLDER 124 | ``` 125 | 126 | Where `PLACEHOLDER` is the service connection name we found above. 127 | The template also has a number of [configuration 128 | options](configuration.md) with opinionated defaults. If you have a 129 | particularly "weird" project, you can also [mix-and-match individual CI 130 | components](custom.md). 131 | 132 | Once that's all committed and pushed, it's time to set up the Pipeline in Azure: 133 | 134 | - Go to https://dev.azure.com/ 135 | - Click the appropriate project 136 | - Click "Pipelines" 137 | - Click "New Pipeline" 138 | - Click "Use the classic editor to create a pipeline without YAML.". 139 | You must do this ([bug 140 | report](https://developercommunity.visualstudio.com/content/problem/642369/pipelines-creation-falls-back-to-github-oauth-auth.html)). 141 | If you just click GitHub, you're taken to the OAuth authentication 142 | page that surrenders all your secrets. 143 | - Click "GitHub" 144 | - Choose your repository using the triple-dot button 145 | - Click "Continue" 146 | - Give your pipeline a name -- probably the name of your project 147 | - Click "Apply" next to "YAML" 148 | - Under "Agent pool", select "Hosted" 149 | - Under "YAML file path", select "azure-pipelines.yml" 150 | - Click "Save & queue" towards the top. 151 | And then click it again... 152 | - Click "Save and run" bottom right 153 | 154 | *Hopefully* Azure was now happy with your efforts. If it is, you'll be 155 | taken to your new shiny "Pipeline summary" page, and it will show you 156 | your build and tests progress! Congrats, you now have Azure Pipelines 157 | CI! If you instead get a big red box at the top of the "Run pipeline" 158 | box with an error, try to see if you can figure out which part of the 159 | magic incantation you missed. If it all looks right to you, file an 160 | issue! 161 | 162 | --- 163 | 164 | ## If you want to add support for code coverage: 165 | 166 | This pipeline is also set up to use 167 | [`tarpaulin`](https://github.com/xd009642/tarpaulin) and 168 | [codecov.io](https://codecov.io/) for test coverage reporting. To enable 169 | this, here's what you have to do: 170 | 171 | - Sign up for https://codecov.io/ if you haven't already 172 | - Log in (again, if you haven't already) 173 | - Install the [GitHub Codecov Application](https://github.com/marketplace/codecov) 174 | - Click "Configure" next to "Codecov" [here](https://github.com/settings/installations) 175 | - Either enable access to "All repositories", or grant permission just 176 | for the project you want coverage for. 177 | - Go to https://codecov.io/gh/GITHUB_USER_OR_ORG/PROJECT/settings 178 | - Copy the "Repository Upload Token" 179 | - Go to https://dev.azure.com/ 180 | - Click the Azure project for the owner of the project you want coverage for 181 | - Click "Pipelines" 182 | - Click the pipeline for the project you want coverage for 183 | - Click "Edit" top-right 184 | - Click the vertical triple dots top-right 185 | - Click "Variables" 186 | - Click "Add", name it whatever you wish (I use `CODECOV_TOKEN_SECRET`), 187 | paste in the "Repository Upload Token" from Codecov, and click the 188 | little padlock to mark the variable as "secret". 189 | - Click the little arrow next to "Save & queue" near the top 190 | - Click "Save" 191 | - Click "Save" again 192 | 193 | Note that this gives access to your Codecov API key to anyone with push 194 | access to the repository! [Use it 195 | wisely](https://docs.microsoft.com/en-us/azure/devops/pipelines/process/variables#secret-variables). 196 | Forks of your repository do _not_ have access to secrets by default. 197 | 198 | Now just add this to your entries in `azure-pipelines.yml` that use the 199 | templates `default.yml`: 200 | 201 | ```yaml 202 | parameters: 203 | codecov_token: $(CODECOV_TOKEN_SECRET) 204 | ``` 205 | 206 | You may also want to give yourself a nice badge! Just go to the Settings 207 | page on codecov.io again and click "Badge" on the left. To add it your 208 | crates.io page, add this to `Cargo.toml`: 209 | 210 | ```toml 211 | codecov = { repository = "GH_USER/GH_PROJECT", branch = "master", service = "github" } 212 | ``` 213 | 214 | ### Code coverage for PRs 215 | 216 | **If you [are really 217 | sure](https://docs.microsoft.com/en-us/azure/devops/pipelines/repos/github#validate-contributions-from-forks)** 218 | you want to allow coverage to run for the arbitrary code people may 219 | submit in PRs to see your secrets, here's what you do: 220 | 221 | - Navigate to the project's pipeline 222 | - Click "Edit" top-right 223 | - Click the vertical triple-dot top-right, and then "Triggers" 224 | - Choose your repository under "Pull request validation" 225 | - Check the box next to "Build pull requests from forks of this repository" 226 | - Then, check the box next to "Make secrets available to builds of forks" 227 | - You may also want to check "Require a team member's comment before building a pull request" 228 | 229 | **If you instead want to simply skip coverage on pull requests**, do 230 | _not_ check the box next to "Make secrets available to builds of forks". 231 | You should not need to change anything else. 232 | 233 | --- 234 | 235 | ## If you want to configure `default.yml` 236 | 237 | The main template, `default.yml` comes configured with some 238 | opinionated defaults. It will check your crate against a minimum Rust 239 | version, check your project without features, and with all of them, and 240 | it will run both rustfmt, clippy, and beta/nightly check on your 241 | codebase. If, for whatever reason, you disagree with some of these 242 | choices, or have a project with particular needs, copy-paste `default.yml` 243 | into your `azure-pipelines.yml`, and replace 244 | 245 | ```yaml 246 | - template: install-rust.yml 247 | ``` 248 | 249 | with 250 | 251 | ```yaml 252 | - template: install-rust.yml@templates 253 | ``` 254 | 255 | Then you can tweak it to your heart's desire! 256 | 257 | There are some smaller configuration parameters available for `default.yml` 258 | too. Most of these also apply to `nightly-only.yml`. 259 | 260 | ### Testing on multiple platforms 261 | 262 | ```yaml 263 | jobs: 264 | - template: default.yml@templates 265 | parameters: 266 | cross: = true 267 | ``` 268 | 269 | By default, your pipeline will test on Linux, MacOS, and Windows. To 270 | only test on Linux, set `cross` to `false`. 271 | 272 | ### Minimum Supported Rust Version (MSRV) 273 | 274 | ```yaml 275 | jobs: 276 | - template: default.yml@templates 277 | parameters: 278 | minrust: = 1.32.0 279 | ``` 280 | 281 | By default, your pipeline will test against a minimum Rust version to 282 | ensure that users of your crates are not required to run on the latest 283 | stable version. The default minimum version may be bumped occasionally, 284 | but will always stay at least 4 releases behind the newest release (~6 285 | months). If you wish to test a _particular_ minimum version, say 1.34.0, 286 | you would give that version number as the `minrust` parameter to 287 | `default.yml`. If you wish to disable the MSRV check, set `minrust` 288 | to `false`. 289 | 290 | #### Minimum supported nightly 291 | 292 | If you are using the `nightly-only.yml` template, the equivalent of MSRV 293 | checking is to check that you support some particular "oldest" nightly. 294 | You can check this by specifying a date for the `min` parameter: 295 | 296 | ```yaml 297 | jobs: 298 | - template: nightly-only.yml@templates 299 | parameters: 300 | minrust: = false 301 | ``` 302 | 303 | 304 | ### Environment variables 305 | 306 | ```yaml 307 | jobs: 308 | - template: default.yml@templates 309 | parameters: 310 | env: 311 | : 312 | ``` 313 | 314 | If you tests require particular environment variables to be set, you can 315 | set these using the `env` parameter. The given environment variables 316 | will be passed in whenever your tests are run. You can set multiple 317 | environment variables, and you can use 318 | [variables](https://docs.microsoft.com/en-us/azure/devops/pipelines/process/variables). 319 | 320 | ### Additional setup steps 321 | 322 | ```yaml 323 | jobs: 324 | - template: default.yml 325 | parameters: 326 | setup: 327 | - 328 | ``` 329 | 330 | Occasionally your project requires additional setup steps for tests to 331 | be run. This may include installing packages, downloading dependencies, 332 | fetch files, or anything else you might think of. To add such extra 333 | steps, use the `setup` parameter and give it a list of 334 | [tasks](https://docs.microsoft.com/en-us/azure/devops/pipelines/process/tasks) 335 | (you can see all of Azure's built-in tasks 336 | [here](https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/)). 337 | --------------------------------------------------------------------------------