Skip to content

Commit 29f4d2c

Browse files
authored
Refactor Artifacts at rest for safe/easy deployment (#16187)
* update build_packages to output to a deeper subfolder * extend find_whl and find_sdst in common_tasks.py/tox_helper_tasks.py to search recursive in preparation for updated artifacts * remove 'artifacts' artifact. update 'packages' artifact so that package artifacts are stored within folders aligning with each ci.yml artifact * update archetype-sdk-release to leverage new artifact storage. no more staging. * update test_regression.py to install package we need to test AFTER we install the dependent package. this ensures that `alpha` versions are always present
1 parent 3c4f257 commit 29f4d2c

12 files changed

+113
-85
lines changed

build_package.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
import os
1111
import glob
1212
import sys
13-
from subprocess import check_call
1413

14+
from subprocess import check_call
1515

1616
DEFAULT_DEST_FOLDER = "./dist"
1717

eng/pipelines/templates/jobs/archetype-sdk-client.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ jobs:
211211
BeforeTestSteps:
212212
- task: DownloadPipelineArtifact@0
213213
inputs:
214-
artifactName: 'artifacts'
214+
artifactName: 'packages'
215215
targetPath: $(Build.ArtifactStagingDirectory)
216216

217217
- template: ../steps/set-dev-build.yml

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

Lines changed: 42 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ stages:
3131
deploy:
3232
steps:
3333
- checkout: self
34+
3435
- ${{if eq(parameters.TestPipeline, 'true')}}:
3536
- task: PowerShell@2
3637
displayName: Prep template pipeline for release
@@ -40,24 +41,26 @@ stages:
4041
workingDirectory: $(Build.SourcesDirectory)
4142
filePath: eng/scripts/SetTestPipelineVersion.ps1
4243
arguments: '-BuildID $(Build.BuildId)'
44+
4345
- ${{if ne(artifact.skipVerifyChangeLog, 'true')}}:
4446
- template: /eng/common/pipelines/templates/steps/verify-changelog.yml
4547
parameters:
4648
PackageName: ${{artifact.name}}
4749
ServiceName: ${{parameters.ServiceDirectory}}
4850
ForRelease: true
49-
- template: /eng/pipelines/templates/steps/stage-filtered-artifacts.yml
50-
parameters:
51-
SourceFolder: ${{parameters.ArtifactName}}
52-
TargetFolder: ${{artifact.safeName}}
53-
PackageName: ${{artifact.name}}
51+
5452
- pwsh: |
55-
Get-ChildItem -Recurse $(Pipeline.Workspace)/${{artifact.safeName}}
53+
$packageDirectory = "${{artifact.name}}".Replace("_", "-")
54+
echo "##vso[task.setvariable variable=Package.Name]$packageDirectory"
55+
56+
- pwsh: |
57+
Get-ChildItem -Recurse $(Pipeline.Workspace)/${{parameters.ArtifactName}}/$(Package.Name)
5658
workingDirectory: $(Pipeline.Workspace)
5759
displayName: Output Visible Artifacts
60+
5861
- template: /eng/common/pipelines/templates/steps/create-tags-and-git-release.yml
5962
parameters:
60-
ArtifactLocation: $(Pipeline.Workspace)/${{artifact.safeName}}
63+
ArtifactLocation: $(Pipeline.Workspace)/${{parameters.ArtifactName}}/$(Package.Name)
6164
PackageRepository: PyPI
6265
ReleaseSha: $(Build.SourceVersion)
6366
RepoId: Azure/azure-sdk-for-python
@@ -83,19 +86,17 @@ stages:
8386
artifact: ${{parameters.ArtifactName}}
8487
timeoutInMinutes: 5
8588

86-
- template: /eng/pipelines/templates/steps/stage-filtered-artifacts.yml
87-
parameters:
88-
SourceFolder: ${{parameters.ArtifactName}}
89-
TargetFolder: ${{artifact.safeName}}
90-
PackageName: ${{artifact.name}}
91-
9289
- task: UsePythonVersion@0
9390

9491
- script: |
9592
set -e
9693
pip install twine readme-renderer[md]
9794
displayName: Install Twine
9895
96+
- pwsh: |
97+
$packageDirectory = "${{artifact.name}}".Replace("_", "-")
98+
echo "##vso[task.setvariable variable=Package.Name]$packageDirectory"
99+
99100
- task: TwineAuthenticate@1
100101
displayName: 'Authenticate to registry: pypi.org'
101102
inputs:
@@ -108,17 +109,17 @@ stages:
108109

109110
- script: |
110111
set -e
111-
twine upload --repository 'pypi' --config-file $(PYPIRC_PATH) $(Pipeline.Workspace)/${{artifact.safeName}}/*.whl
112+
twine upload --repository 'pypi' --config-file $(PYPIRC_PATH) $(Pipeline.Workspace)/${{parameters.ArtifactName}}/$(Package.Name)/*.whl
112113
echo "Uploaded whl to pypi"
113-
twine upload --repository 'pypi' --config-file $(PYPIRC_PATH) $(Pipeline.Workspace)/${{artifact.safeName}}/*.zip
114+
twine upload --repository 'pypi' --config-file $(PYPIRC_PATH) $(Pipeline.Workspace)/${{parameters.ArtifactName}}/$(Package.Name)/*.zip
114115
echo "Uploaded zip to pypi"
115116
displayName: 'Publish package to registry: pypi.org'
116117
117118
- script: |
118119
set -e
119-
twine upload --repository ${{parameters.DevFeedName}} --config-file $(PYPIRC_PATH) $(Pipeline.Workspace)/${{artifact.safeName}}/*.whl
120+
twine upload --repository ${{parameters.DevFeedName}} --config-file $(PYPIRC_PATH) $(Pipeline.Workspace)/${{parameters.ArtifactName}}/$(Package.Name)/*.whl
120121
echo "Uploaded whl to devops feed"
121-
twine upload --repository ${{parameters.DevFeedName}} --config-file $(PYPIRC_PATH) $(Pipeline.Workspace)/${{artifact.safeName}}/*.zip
122+
twine upload --repository ${{parameters.DevFeedName}} --config-file $(PYPIRC_PATH) $(Pipeline.Workspace)/${{parameters.ArtifactName}}/$(Package.Name)/*.zip
122123
echo "Uploaded sdist to devops feed"
123124
displayName: 'Publish package to feed: ${{parameters.DevFeedName}}'
124125
@@ -138,23 +139,23 @@ stages:
138139
deploy:
139140
steps:
140141
- checkout: self
141-
- template: /eng/pipelines/templates/steps/stage-filtered-artifacts.yml
142-
parameters:
143-
SourceFolder: ${{parameters.DocArtifact}}
144-
TargetFolder: ${{artifact.safeName}}
145-
PackageName: ${{artifact.name}}
146-
AdditionalRegex: '.zip'
142+
143+
- pwsh: |
144+
$packageDirectory = "${{artifact.name}}".Replace("_", "-")
145+
echo "##vso[task.setvariable variable=Package.Name]$packageDirectory"
146+
147147
- pwsh: |
148-
Get-ChildItem -Recurse $(Pipeline.Workspace)/${{artifact.safeName}}
148+
Get-ChildItem -Recurse $(Pipeline.Workspace)/${{parameters.DocArtifact}}/$(Package.Name)
149149
workingDirectory: $(Pipeline.Workspace)
150150
displayName: Output Visible Artifacts
151+
151152
- template: /eng/common/pipelines/templates/steps/publish-blobs.yml
152153
parameters:
153-
FolderForUpload: '$(Pipeline.Workspace)/${{artifact.safeName}}'
154+
FolderForUpload: '$(Pipeline.Workspace)/${{parameters.DocArtifact}}/$(Package.Name)'
154155
BlobSASKey: '$(azure-sdk-docs-prod-sas)'
155156
BlobName: '$(azure-sdk-docs-prod-blob-name)'
156157
TargetLanguage: 'python'
157-
ArtifactLocation: '$(Pipeline.Workspace)/${{parameters.ArtifactName}}'
158+
ArtifactLocation: '$(Pipeline.Workspace)/${{parameters.ArtifactName}}/$(Package.Name)'
158159
# we override the regular script path because we have cloned the build tools repo as a separate artifact.
159160
ScriptPath: 'eng/common/scripts/copy-docs-to-blobstorage.ps1'
160161

@@ -177,22 +178,24 @@ stages:
177178
deploy:
178179
steps:
179180
- checkout: self
180-
- template: /eng/pipelines/templates/steps/stage-filtered-artifacts.yml
181-
parameters:
182-
SourceFolder: ${{parameters.ArtifactName}}
183-
TargetFolder: ${{artifact.safeName}}
184-
PackageName: ${{artifact.name}}
181+
182+
- pwsh: |
183+
$packageDirectory = "${{artifact.name}}".Replace("_", "-")
184+
echo "##vso[task.setvariable variable=Package.Name]$packageDirectory"
185+
185186
- pwsh: |
186-
Get-ChildItem -Recurse $(Pipeline.Workspace)/${{artifact.safeName}}
187+
Get-ChildItem -Recurse $(Pipeline.Workspace)/${{parameters.ArtifactName}}/$(Package.Name)
187188
workingDirectory: $(Pipeline.Workspace)
188189
displayName: Output Visible Artifacts
190+
189191
- template: /eng/common/pipelines/templates/steps/get-pr-owners.yml
190192
parameters:
191193
TargetVariable: "OwningGHUser"
192194
ServiceDirectory: ${{parameters.ServiceDirectory}}
195+
193196
- template: /eng/common/pipelines/templates/steps/docs-metadata-release.yml
194197
parameters:
195-
ArtifactLocation: $(Pipeline.Workspace)/${{artifact.safeName}}
198+
ArtifactLocation: $(Pipeline.Workspace)/${{parameters.ArtifactName}}/$(Package.Name)
196199
PackageRepository: PyPI
197200
ReleaseSha: $(Build.SourceVersion)
198201
RepoId: Azure/azure-sdk-for-python
@@ -280,22 +283,17 @@ stages:
280283
- ${{ each artifact in parameters.Artifacts }}:
281284
- ${{if ne(artifact.skipPublishDevFeed, 'true')}}:
282285
- pwsh: |
283-
Get-ChildItem $(Pipeline.Workspace)/${{parameters.ArtifactName}}
284-
New-Item -Type Directory -Name ${{artifact.safeName}} -Path $(Pipeline.Workspace)
285-
$underscorePrefix = "${{artifact.name}}"
286-
$dashPrefix = "${{artifact.name}}".Replace("_", "-")
287-
Copy-Item $(Pipeline.Workspace)/${{parameters.ArtifactName}}/$dashPrefix-[0-9]*.[0-9]*.[0-9]*a[0-9]* $(Pipeline.Workspace)/${{artifact.safeName}}
288-
Copy-Item $(Pipeline.Workspace)/${{parameters.ArtifactName}}/$underscorePrefix-[0-9]*.[0-9]*.[0-9]*a[0-9]* $(Pipeline.Workspace)/${{artifact.safeName}}
289-
Get-ChildItem $(Pipeline.Workspace)/${{artifact.safeName}}
290-
291-
$fileCount = (Get-ChildItem $(Pipeline.Workspace)/${{artifact.safeName}} | Measure-Object).Count
286+
$packageDirectory = "${{artifact.name}}".Replace("_", "-")
287+
echo "##vso[task.setvariable variable=Package.Name]$packageDirectory"
288+
- pwsh: |
289+
$fileCount = (Get-ChildItem $(Pipeline.Workspace)/${{parameters.ArtifactName}}/$packageDirectory | Measure-Object).Count
292290
if ($fileCount -eq 0) {
293291
Write-Host "No alpha packages for ${{artifact.safeName}} to publish."
294292
exit 0
295293
}
296294
297-
twine upload --repository $(DevFeedName) --config-file $(PYPIRC_PATH) $(Pipeline.Workspace)/${{artifact.safeName}}/*a*.whl
295+
twine upload --repository $(DevFeedName) --config-file $(PYPIRC_PATH) $(Pipeline.Workspace)/${{parameters.ArtifactName}}/$(Package.Name)/*a*.whl
298296
echo "Uploaded whl to devops feed $(DevFeedName)"
299-
twine upload --repository $(DevFeedName) --config-file $(PYPIRC_PATH) $(Pipeline.Workspace)/${{artifact.safeName}}/*a*.zip
297+
twine upload --repository $(DevFeedName) --config-file $(PYPIRC_PATH) $(Pipeline.Workspace)/${{parameters.ArtifactName}}/$(Package.Name)/*a*.zip
300298
echo "Uploaded sdist to devops feed $(DevFeedName)"
301299
displayName: 'Publish ${{artifact.name}} alpha package'

eng/pipelines/templates/steps/analyze.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ steps:
8888
- task: DownloadPipelineArtifact@0
8989
condition: and(succeededOrFailed(), ne(variables['Skip.ApiStubGen'],'true'))
9090
inputs:
91-
artifactName: 'artifacts'
91+
artifactName: 'packages'
9292
targetPath: $(Build.ArtifactStagingDirectory)
9393

9494
- template: ../steps/run_apistub.yml

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

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
11
parameters:
2-
BeforePublishSteps: []
3-
TestPipeline: false
4-
BuildTargetingString: 'azure-*'
5-
ServiceDirectory: ''
6-
BuildDocs: true
2+
- name: BeforePublishSteps
3+
type: object
4+
default: []
5+
- name: TestPipeline
6+
type: boolean
7+
default: false
8+
- name: BuildTargetingString
9+
type: string
10+
default: 'azure-*'
11+
- name: ServiceDirectory
12+
type: string
13+
default: ''
14+
- name: BuildDocs
15+
type: boolean
16+
default: true
717

818
steps:
919
- ${{if eq(parameters.TestPipeline, 'true')}}:
@@ -57,8 +67,8 @@ steps:
5767
arguments: '-d "$(Build.ArtifactStagingDirectory)" "${{ parameters.BuildTargetingString }}" --service=${{parameters.ServiceDirectory}} --devbuild="$(SetDevVersion)"'
5868

5969
- script: |
60-
twine check $(Build.ArtifactStagingDirectory)/*.whl
61-
twine check $(Build.ArtifactStagingDirectory)/*.zip
70+
twine check $(Build.ArtifactStagingDirectory)/**/*.whl
71+
twine check $(Build.ArtifactStagingDirectory)/**/*.zip
6272
displayName: 'Verify Readme'
6373
6474
- task: PythonScript@0
@@ -73,17 +83,9 @@ steps:
7383
7484
- ${{ parameters.BeforePublishSteps }}
7585

76-
- task: PublishPipelineArtifact@0
77-
inputs:
78-
artifactName: 'artifacts'
79-
targetPath: $(Build.ArtifactStagingDirectory)
80-
81-
# Duplicating the task above to introduce a packages artifact for consistency
82-
# with the other pipelines. Also using the newer YAML shortcut. Once we get
83-
# past release successfully with unified pipelines we'll look at getting rid
84-
# of the duplicated "artifacts" artifact.
8586
- publish: $(Build.ArtifactStagingDirectory)
8687
artifact: packages
88+
condition: succeededOrFailed()
8789

8890
- task: PublishBuildArtifacts@1
8991
condition: and(succeededOrFailed(), ${{parameters.BuildDocs}})

eng/pipelines/templates/steps/test_regression.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ steps:
1212

1313
- task: DownloadPipelineArtifact@0
1414
inputs:
15-
artifactName: 'artifacts'
15+
artifactName: 'packages'
1616
targetPath: $(Build.ArtifactStagingDirectory)
1717

1818
- script: |

eng/tox/run_sphinx_build.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def move_output_and_zip(target_dir, package_dir, package_name):
3535
if not os.path.exists(ci_doc_dir):
3636
os.mkdir(ci_doc_dir)
3737

38-
individual_zip_location = os.path.join(ci_doc_dir, package_name)
38+
individual_zip_location = os.path.join(ci_doc_dir, package_name, package_name)
3939
shutil.make_archive(individual_zip_location, 'zip', target_dir)
4040

4141
def sphinx_build(target_dir, output_dir):

eng/tox/tox_helper_tasks.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import io
1818
import glob
1919
import zipfile
20+
import fnmatch
2021

2122
logging.getLogger().setLevel(logging.INFO)
2223

@@ -92,7 +93,13 @@ def find_sdist(dist_dir, pkg_name, pkg_version):
9293
return
9394

9495
pkg_name_format = "{0}-{1}.zip".format(pkg_name, pkg_version)
95-
packages = [os.path.basename(w) for w in glob.glob(os.path.join(dist_dir, pkg_name_format))]
96+
packages = []
97+
for root, dirnames, filenames in os.walk(dist_dir):
98+
for filename in fnmatch.filter(filenames, pkg_name_format):
99+
packages.append(os.path.join(root, filename))
100+
101+
packages = [os.path.relpath(w, dist_dir) for w in packages]
102+
96103
if not packages:
97104
logging.error("No sdist is found in directory %s with package name format %s", dist_dir, pkg_name_format)
98105
return
@@ -109,8 +116,15 @@ def find_whl(whl_dir, pkg_name, pkg_version):
109116
logging.error("Package name cannot be empty to find whl")
110117
return
111118

112-
pkg_name_format = "{0}-{1}-*.whl".format(pkg_name.replace("-", "_"), pkg_version)
113-
whls = [os.path.basename(w) for w in glob.glob(os.path.join(whl_dir, pkg_name_format))]
119+
120+
pkg_name_format = "{0}-{1}*.whl".format(pkg_name.replace("-", "_"), pkg_version)
121+
whls = []
122+
for root, dirnames, filenames in os.walk(whl_dir):
123+
for filename in fnmatch.filter(filenames, pkg_name_format):
124+
whls.append(os.path.join(root, filename))
125+
126+
whls = [os.path.relpath(w, whl_dir) for w in whls]
127+
114128
if not whls:
115129
logging.error("No whl is found in directory %s with package name format %s", whl_dir, pkg_name_format)
116130
logging.info("List of whls in directory: %s", glob.glob(os.path.join(whl_dir, "*.whl")))
@@ -136,6 +150,3 @@ def find_whl(whl_dir, pkg_name, pkg_version):
136150
return whls[0]
137151
else:
138152
return None
139-
140-
141-

scripts/devops_tasks/build_packages.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
def build_packages(targeted_packages, distribution_directory, is_dev_build=False):
2626
# run the build and distribution
2727
for package_root in targeted_packages:
28-
print(package_root)
28+
service_hierarchy = os.path.join(os.path.basename(package_root))
2929
if is_dev_build:
3030
verify_update_package_requirement(package_root)
3131
print("Generating Package Using Python {}".format(sys.version))
@@ -34,7 +34,7 @@ def build_packages(targeted_packages, distribution_directory, is_dev_build=False
3434
sys.executable,
3535
build_packing_script_location,
3636
"--dest",
37-
distribution_directory,
37+
os.path.join(distribution_directory, service_hierarchy),
3838
package_root,
3939
],
4040
root_dir,

scripts/devops_tasks/common_tasks.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import textwrap
2020
import io
2121
import re
22-
import pdb
22+
import fnmatch
2323

2424
# Assumes the presence of setuptools
2525
from pkg_resources import parse_version, parse_requirements, Requirement, WorkingSet, working_set
@@ -356,17 +356,23 @@ def find_whl(package_name, version, whl_directory):
356356
parsed_version = parse(version)
357357

358358
logging.info("Searching whl for package {0}-{1}".format(package_name, parsed_version.base_version))
359-
whl_name = "{0}-{1}*.whl".format(package_name.replace("-", "_"), parsed_version.base_version)
360-
paths = glob.glob(os.path.join(whl_directory, whl_name))
361-
if not paths:
359+
whl_name_format = "{0}-{1}*.whl".format(package_name.replace("-", "_"), parsed_version.base_version)
360+
whls = []
361+
for root, dirnames, filenames in os.walk(whl_directory):
362+
for filename in fnmatch.filter(filenames, whl_name_format):
363+
whls.append(os.path.join(root, filename))
364+
365+
whls = [os.path.relpath(w, whl_directory) for w in whls]
366+
367+
if not whls:
362368
logging.error(
363369
"whl is not found in whl directory {0} for package {1}-{2}".format(
364370
whl_directory, package_name, parsed_version.base_version
365371
)
366372
)
367373
exit(1)
368374

369-
return paths[0]
375+
return whls[0]
370376

371377
# This method installs package from a pre-built whl
372378
def install_package_from_whl(

0 commit comments

Comments
 (0)