Skip to content

Commit 4398c15

Browse files
authored
Add Testing of Conda Artifacts (#18478)
* take advantage of additional test-matrix, add ci.conda.tests to jobs/ci.yml which further extends test matrix for conda artifacts * test our conda packages on windows/mac/linux py 3.6, 3.8, 3.9 * add common conda requirements file
1 parent 20a3129 commit 4398c15

File tree

13 files changed

+257
-7
lines changed

13 files changed

+257
-7
lines changed

doc/dev/conda-builds.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
Follow the instructions [here](https://docs.conda.io/projects/conda-build/en/latest/install-conda-build.html) to install `conda` and `conda-build`.
66

7+
**The Azure SDK Conda artifacts support `python3.8` and `python3.9` only.**
8+
79
## CI Build Process
810

911
There will be a `CondaArtifact` defined in the `ci.yml` of each service directory. (`sdk/<service>`)
@@ -15,9 +17,18 @@ A Conda Artifact defines:
1517
- Any other necessary details.
1618

1719
## How to Build an Azure SDK Conda Package Locally
20+
#### If using powershell, you will need to prep your environment before proceeding to the next step
21+
22+
```
23+
powershell -ExecutionPolicy ByPass -NoExit -Command "& '<path-to-conda-folder>\shell\condabin\conda-hook.ps1' ; conda activate '<path-to-conda-folder>' "
24+
```
25+
26+
Afterwards, invoke `conda init powershell` and re-create the pshell session.
1827

28+
By default, your powershell environment will now load `conda`. If you want pure pip, you will need to use explicit invocations of your `python` locations to create virtual envs.
1929
### Set up your conda environment
2030

31+
2132
You will notice that all the azure-sdk conda distributions have the **same** version number and requirement set. This is due to the fact that the azure-sdk team pushes our conda packages out in waves. To support this, all versions are set via a common environment variable `AZURESDK_CONDA_VERSION`.
2233

2334
We keep this environment variable set properly across all our builds by using a common `conda_env.yml` when creating our build environment. This environment definition ensures that:

eng/conda_env.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
variables:
2-
AZURESDK_CONDA_VERSION: '2021.05.01'
2+
AZURESDK_CONDA_VERSION: '2021.05.01b1'

eng/conda_test_requirements.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# install from root of repo
2+
aiohttp>=3.0; python_version >= '3.5'
3+
tools/azure-devtools
4+
tools/azure-sdk-tools
5+
mock;
6+
aiodns>=2.0; python_version >= '3.5'
7+
parameterized>=0.7.3; python_version >= '3.0'
8+
trio; python_version >= '3.5'
9+
typing_extensions>=3.7.2
10+
futures==3.3.0; python_version <= '2.7'
11+
cryptography
12+
adal
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
parameters:
2+
- name: TestPipeline
3+
type: boolean
4+
default: false
5+
- name: ServiceDirectory
6+
type: string
7+
default: ''
8+
- name: CondaArtifacts
9+
type: object
10+
default: []
11+
- name: TestMarkArgument
12+
type: string
13+
default: ''
14+
- name: PythonVersion
15+
type: string
16+
default: ''
17+
- name: OSVmImage
18+
type: string
19+
default: ''
20+
- name: Matrix
21+
type: string
22+
- name: DependsOn
23+
type: string
24+
default: ''
25+
- name: UsePlatformContainer
26+
type: boolean
27+
default: false
28+
- name: TestTimeoutInMinutes
29+
type: number
30+
default: 0
31+
- name: CloudConfig
32+
type: object
33+
default: {}
34+
35+
jobs:
36+
- job:
37+
displayName: 'Test Conda'
38+
condition: |
39+
and(
40+
succeededOrFailed(),
41+
ne(variables['Skip.TestConda'], 'true')
42+
)
43+
timeoutInMinutes: ${{ parameters.TestTimeoutInMinutes }}
44+
45+
dependsOn:
46+
- ${{ parameters.DependsOn }}
47+
48+
strategy:
49+
matrix: $[ ${{ parameters.Matrix }} ]
50+
51+
pool:
52+
name: $(Pool)
53+
vmImage: $(OSVmImage)
54+
55+
${{ if eq(parameters.UsePlatformContainer, 'true') }}:
56+
# Add a default so the job doesn't fail when the matrix is empty
57+
container: $[ variables['Container'] ]
58+
59+
variables:
60+
- template: ../variables/globals.yml
61+
62+
steps:
63+
- task: DownloadPipelineArtifact@2
64+
inputs:
65+
artifactName: 'conda'
66+
targetPath: $(Build.ArtifactStagingDirectory)
67+
68+
- template: /eng/common/pipelines/templates/steps/set-test-pipeline-version.yml
69+
parameters:
70+
PackageName: "azure-template"
71+
ServiceDirectory: "template"
72+
TestPipeline: ${{ parameters.TestPipeline }}
73+
74+
- task: UsePythonVersion@0
75+
displayName: 'Use Python $(PythonVersion)'
76+
inputs:
77+
versionSpec: $(PythonVersion)
78+
79+
- pwsh: |
80+
# due to faulty deployed scripts/how the path gets manipulated by conda actions on
81+
# ubuntu and mac, we can't rely on bin/scripts being referenced correctly. see
82+
# https://github.com/MicrosoftDocs/azure-devops-docs/issues/3812
83+
$activateMethod = "source $($env:CONDA)/bin/activate"
84+
85+
# pypy3 is not a true python executable. in conda-land, we need to call it using pypy3, NOT python
86+
87+
# on windows, we need to add "--user" as otherwise pip won't successfully install/uninstall due to
88+
# how windows holds reservation on pip.exe. this is unnecessary on ubuntu/mac.
89+
$requirementSuffix = ""
90+
91+
# we always want to prepend the path with conda bin
92+
Write-Host "##vso[task.prependpath]]$($env:CONDA)/bin"
93+
94+
if ($IsWindows) {
95+
# powershell does not have an equivalent of call/source, which is necessary when
96+
# using conda in azure devops. Note that we use `activate` natively here, as
97+
# a later path prepend of the /scripts directory actually works.
98+
$activateMethod = "call activate"
99+
$requirementSuffix = " --user"
100+
101+
# on windows only, need to prepend with the scripts directory as well
102+
Write-Host "##vso[task.prependpath]$($env:CONDA)/Scripts"
103+
}
104+
105+
if("$(PythonVersion)" -eq "pypy3"){
106+
Write-Host "##vso[task.setvariable variable=PyVersion]-c conda-forge pypy3.7 pip"
107+
}
108+
else {
109+
Write-Host "##vso[task.setvariable variable=PyVersion]python=$(PythonVersion)"
110+
}
111+
112+
# we will use these variables extensively later
113+
Write-Host "##vso[task.setvariable variable=activate.method]$activateMethod"
114+
Write-Host "##vso[task.setvariable variable=requirement.suffix]$requirementSuffix"
115+
displayName: 'Evaluate OS Specific PATH and Parameters'
116+
117+
- ${{ each artifact in parameters.CondaArtifacts }}:
118+
# due to the fact that `pypy3` and `conda-build` conda packages are INCOMPATIBLE, we have to create
119+
# a separate env to install `conda-build` and use that to `conda index` the local file channel
120+
- script: |
121+
echo "conda create --name ${{ artifact.name }} $(PyVersion) --yes"
122+
conda create --name ${{ artifact.name }} $(PyVersion) --yes
123+
124+
echo "conda create --name index-env --yes"
125+
conda create --name index-env --yes
126+
127+
echo "conda install --name index-env --yes --quiet conda-build"
128+
conda install --name index-env --yes --quiet conda-build
129+
130+
echo "$(activate.method) index-env"
131+
$(activate.method) index-env
132+
133+
echo "conda index $(Build.ArtifactStagingDirectory)/${{ artifact.name }}"
134+
conda index $(Build.ArtifactStagingDirectory)/${{ artifact.name }}
135+
displayName: 'Prepare Conda Environment for Testing ${{ artifact.name }}, Index the Target Local Artifact'
136+
137+
- script: |
138+
echo "$(activate.method) ${{ artifact.name }}"
139+
$(activate.method) ${{ artifact.name }}
140+
141+
echo "python -m pip install -r eng/ci_tools.txt $(requirement.suffix)"
142+
python -m pip install -r eng/ci_tools.txt $(requirement.suffix)
143+
displayName: 'Activate Conda Environment and Install General Dependencies ${{ artifact.name }}'
144+
145+
- pwsh: |
146+
mkdir $(Agent.BuildDirectory)/conda/
147+
Write-Host "##vso[task.setvariable variable=conda.build]$(Agent.BuildDirectory)/conda_checkout"
148+
displayName: 'Create Conda Working Directory for Testing'
149+
150+
- script: |
151+
echo "$(activate.method) ${{ artifact.name }}"
152+
$(activate.method) ${{ artifact.name }}
153+
154+
echo "python -m pip install -r $(Build.SourcesDirectory)/eng/conda_test_requirements.txt"
155+
python -m pip install -r $(Build.SourcesDirectory)/eng/conda_test_requirements.txt
156+
157+
python -m pip uninstall azure-core -y
158+
displayName: 'Prep Conda Environment w/ Dependencies'
159+
160+
- script: |
161+
echo "conda install --name ${{ artifact.name }} ${{ artifact.name }} -c $(Build.ArtifactStagingDirectory)/${{ artifact.name }} --yes -c $(AzureSDKCondaChannel)"
162+
conda install --name ${{ artifact.name }} ${{ artifact.name }} -c $(Build.ArtifactStagingDirectory)/${{ artifact.name }} --yes -c $(AzureSDKCondaChannel)
163+
164+
echo "conda install --name ${{ artifact.name }} azure-identity -c $(Build.ArtifactStagingDirectory)/${{ artifact.name }} -c $(AzureSDKCondaChannel) --yes"
165+
conda install --name ${{ artifact.name }} azure-identity -c $(Build.ArtifactStagingDirectory)/${{ artifact.name }} -c $(AzureSDKCondaChannel) --yes
166+
167+
echo "$(activate.method) ${{ artifact.name }}"
168+
$(activate.method) ${{ artifact.name }}
169+
python -m pip freeze
170+
displayName: 'Install ${{ artifact.name }} Conda Package'
171+
172+
- ${{ each checkout in artifact.checkout }}:
173+
- pwsh:
174+
Write-Host "Clean up Conda Build Directory $(conda.build)"
175+
Remove-Item $(conda.build)/* -Recurse -Force
176+
displayName: 'Clean Up Before Testing ${{ artifact.name }}'
177+
178+
- template: /eng/common/pipelines/templates/steps/sparse-checkout.yml
179+
parameters:
180+
Paths:
181+
- "${{ checkout.checkout_path }}"
182+
- "sdk/conftest.py"
183+
- "tools/"
184+
Repositories:
185+
- Name: "Azure/azure-sdk-for-python"
186+
Commitish: "${{ checkout.Package }}_${{ checkout.Version }}"
187+
WorkingDirectory: "$(conda.build)"
188+
SkipDefaultCheckout: true
189+
190+
- script: |
191+
echo "$(activate.method) ${{ artifact.name }}"
192+
$(activate.method) ${{ artifact.name }}
193+
python -m pytest $(conda.build)/${{ checkout.checkout_path }}/${{ checkout.package }}
194+
displayName: 'Run Tests for ${{ checkout.package }}'

eng/pipelines/templates/jobs/ci.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,29 @@ jobs:
126126
ToxEnvParallel: ${{ parameters.ToxEnvParallel }}
127127
InjectedPackages: ${{ parameters.InjectedPackages }}
128128

129+
- ${{ if gt(length(parameters.CondaArtifacts), 0) }}:
130+
- template: /eng/common/pipelines/templates/jobs/archetype-sdk-tests-generate.yml
131+
parameters:
132+
JobTemplatePath: /eng/pipelines/templates/jobs/ci.conda.tests.yml
133+
GenerateJobName: generate_conda_matrix
134+
DependsOn:
135+
- 'Build'
136+
MatrixConfigs:
137+
- Name: Python_ci_conda_envs
138+
Path: eng/pipelines/templates/stages/platform-matrix-conda-support.json
139+
Selection: sparse
140+
GenerateVMJobs: true
141+
MatrixFilters: ${{ parameters.MatrixFilters }}
142+
MatrixReplace: ${{ parameters.MatrixReplace }}
143+
CloudConfig:
144+
Cloud: Public
145+
AdditionalParameters:
146+
ServiceDirectory: ${{ parameters.ServiceDirectory }}
147+
TestPipeline: ${{ parameters.TestPipeline }}
148+
TestMarkArgument: ${{ parameters.TestMarkArgument }}
149+
TestTimeoutInMinutes: ${{ parameters.TestTimeoutInMinutes }}
150+
CondaArtifacts: ${{ parameters.CondaArtifacts}}
151+
129152
- job: 'RunRegression'
130153
condition: and(succeededOrFailed(), or(eq(variables['Run.Regression'], 'true'), and(eq(variables['Build.Reason'], 'Schedule'), eq(variables['System.TeamProject'],'internal'))))
131154
displayName: 'Run Regression'

eng/pipelines/templates/stages/archetype-conda-release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ parameters:
99
stages:
1010
- ${{if and(eq(variables['Build.Reason'], 'Manual'), eq(variables['System.TeamProject'], 'internal'))}}:
1111
- ${{ each artifact in parameters.CondaArtifacts }}:
12-
- stage: Release_${{ replace(artifact.name, '-', '_') }}
12+
- stage: Release_${{ replace(artifact.name, '-', '_') }}_To_Blob
1313
displayName: 'Conda Release: ${{artifact.name}}'
1414
dependsOn: ${{parameters.DependsOn}}
1515
condition: and(succeeded(), ne(variables['SetDevVersion'], 'true'), ne(variables['Skip.Release'], 'true'), ne(variables['Build.Repository.Name'], 'Azure/azure-sdk-for-python-pr'))
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"matrix": {
3+
"Agent": {
4+
"ubuntu-18.04": { "OSVmImage": "MMSUbuntu18.04", "Pool": "azsdk-pool-mms-ubuntu-1804-general" },
5+
"windows-2019": { "OSVmImage": "MMS2019", "Pool": "azsdk-pool-mms-win-2019-general" },
6+
"macOS-10.15": { "OSVmImage": "macOS-10.15", "Pool": "Azure Pipelines" }
7+
},
8+
"PythonVersion": [ "3.6", "3.8", "3.9" ]
9+
}
10+
}

eng/pipelines/templates/steps/build-conda-artifacts.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,9 @@ steps:
7474
7575
- bash: |
7676
source activate ${{ artifact.name }}
77-
conda-build . --output-folder "$(Agent.BuildDirectory)/conda/output" -c $(AzureSDKCondaChannel)
77+
conda-build . --output-folder "$(Agent.BuildDirectory)/conda/output/${{ artifact.name }}" -c $(AzureSDKCondaChannel)
7878
displayName: 'Activate Conda Environment and Build ${{ artifact.name }}'
79-
workingDirectory: $(Build.SourcesDirectory)/sdk/${{ parameters.ServiceDirectory }}
79+
workingDirectory: $(Build.SourcesDirectory)/sdk/${{ parameters.ServiceDirectory }}/conda-recipe
8080
8181
- template: /eng/common/pipelines/templates/steps/publish-artifact.yml
8282
parameters:

scripts/devops_tasks/build_conda_artifacts.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333

3434
VERSION_REGEX = re.compile(r"\s*AZURESDK_CONDA_VERSION\s*:\s*[\'](.*)[\']\s*")
3535

36-
SUMMARY_TEMPLATE = "- Generated from {}."
36+
SUMMARY_TEMPLATE = " - Generated from {}."
3737

3838
NAMESPACE_EXTENSION_TEMPLATE = """__path__ = __import__('pkgutil').extend_path(__path__, __name__) # type: str
3939
"""

sdk/core/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ extends:
4646
safeName: azurecommon
4747
CondaArtifacts:
4848
- name: azure-core
49-
meta_source: meta.yaml
49+
meta_source: conda-recipe/meta.yaml
5050
common_root: azure
5151
checkout:
5252
- package: azure-core
File renamed without changes.

sdk/storage/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ extends:
5656
safeName: azuremgmtstoragesync
5757
CondaArtifacts:
5858
- name: azure-storage
59-
meta_source: meta.yaml
59+
meta_source: conda-recipe/meta.yaml
6060
common_root: azure/storage
6161
checkout:
6262
- package: azure-storage-blob
File renamed without changes.

0 commit comments

Comments
 (0)