├── .gitignore ├── tox.ini ├── azure-pipelines.yml ├── setup.cfg ├── step--git-install.yml ├── job--pre-commit.yml ├── .pre-commit-config.yaml ├── job--go-test.yml ├── bin └── download-wheels ├── job--python-tox.yml └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /.tox 2 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | skipsdist = true 3 | envlist = py27,py36,py37,py38,pypy,pypy3,docs 4 | 5 | [testenv] 6 | commands = python --version --version 7 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | trigger: 2 | branches: 3 | include: [main, test-me-*] 4 | tags: 5 | include: ['*'] 6 | 7 | jobs: 8 | - template: job--python-tox.yml 9 | parameters: 10 | coverage: false 11 | toxenvs: [py37, py38, py39, py310, py311, py312, pypy3, docs] 12 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [mypy] 2 | check_untyped_defs = true 3 | disallow_any_generics = true 4 | disallow_incomplete_defs = true 5 | disallow_untyped_defs = true 6 | warn_redundant_casts = true 7 | warn_unused_ignores = true 8 | 9 | [mypy-testing.*] 10 | disallow_untyped_defs = false 11 | 12 | [mypy-tests.*] 13 | disallow_untyped_defs = false 14 | -------------------------------------------------------------------------------- /step--git-install.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | version: HEAD 3 | 4 | steps: 5 | - bash: | 6 | set -euxo pipefail 7 | sudo apt-get update -q 8 | sudo apt-get install -y --no-install-recommends libcurl4-openssl-dev 9 | git init /tmp/git 10 | cd /tmp/git 11 | git remote add origin https://github.com/git/git 12 | git fetch --depth 1 origin ${{ parameters.version }} 13 | git checkout FETCH_HEAD 14 | make prefix=/tmp/git NO_GETTEXT=1 NO_TCLTK=1 -j4 install 15 | echo '##vso[task.prependpath]/tmp/git/bin' 16 | displayName: install git @ ${{ parameters.version }} 17 | - script: git --version 18 | displayName: git --version 19 | -------------------------------------------------------------------------------- /job--pre-commit.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | ruby: '>= 2.4' 3 | python: '3.11' 4 | 5 | jobs: 6 | - job: precommit 7 | pool: 8 | vmImage: ubuntu-latest 9 | variables: 10 | PRE_COMMIT_HOME: $(Pipeline.Workspace)/pre-commit-cache 11 | 12 | steps: 13 | - task: UsePythonVersion@0 14 | inputs: 15 | versionSpec: ${{ parameters.python }} 16 | - task: UseRubyVersion@0 17 | inputs: 18 | versionSpec: ${{ parameters.ruby }} 19 | 20 | - script: | 21 | echo "##vso[task.setvariable variable=PY]$(python -VV)" 22 | echo "##vso[task.setvariable variable=RB]$(ruby -v)" 23 | displayName: set version variables 24 | 25 | - task: CacheBeta@0 26 | inputs: 27 | key: pre-commit | "4" | .pre-commit-config.yaml | "$(PY)" | "$(RB)" 28 | path: $(PRE_COMMIT_HOME) 29 | 30 | - script: python -m pip install --upgrade pre-commit 31 | displayName: install pre-commit 32 | - script: pre-commit run --all-files --show-diff-on-failure 33 | displayName: run pre-commit 34 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v4.4.0 4 | hooks: 5 | - id: trailing-whitespace 6 | - id: end-of-file-fixer 7 | - id: check-yaml 8 | - id: debug-statements 9 | - id: double-quote-string-fixer 10 | - id: name-tests-test 11 | - id: requirements-txt-fixer 12 | - repo: https://github.com/asottile/reorder_python_imports 13 | rev: v3.9.0 14 | hooks: 15 | - id: reorder-python-imports 16 | args: [--py37-plus, --add-import, 'from __future__ import annotations'] 17 | - repo: https://github.com/asottile/add-trailing-comma 18 | rev: v2.4.0 19 | hooks: 20 | - id: add-trailing-comma 21 | args: [--py36-plus] 22 | - repo: https://github.com/asottile/pyupgrade 23 | rev: v3.3.1 24 | hooks: 25 | - id: pyupgrade 26 | args: [--py37-plus] 27 | - repo: https://github.com/pre-commit/mirrors-autopep8 28 | rev: v2.0.1 29 | hooks: 30 | - id: autopep8 31 | - repo: https://github.com/PyCQA/flake8 32 | rev: 6.0.0 33 | hooks: 34 | - id: flake8 35 | - repo: https://github.com/pre-commit/mirrors-mypy 36 | rev: v0.991 37 | hooks: 38 | - id: mypy 39 | -------------------------------------------------------------------------------- /job--go-test.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | go_versions: [] 3 | os: linux 4 | tests: './...' 5 | pre_test: [] 6 | name_postfix: '' 7 | 8 | jobs: 9 | - job: ${{ format('go_test_{0}{1}', parameters.os, parameters.name_postfix) }} 10 | strategy: 11 | matrix: 12 | ${{ each go in parameters.go_versions }}: 13 | ${{ go }}: 14 | go: ${{ go }} 15 | 16 | pool: 17 | ${{ if eq(parameters.os, 'linux') }}: 18 | vmImage: ubuntu-latest 19 | ${{ if eq(parameters.os, 'windows') }}: 20 | vmImage: windows-latest 21 | ${{ if eq(parameters.os, 'osx') }}: 22 | vmImage: macOS-latest 23 | 24 | variables: 25 | GOPATH: '$(system.defaultWorkingDirectory)/gopath' 26 | module_path: '$(GOPATH)/src/github.com/$(build.repository.name)' 27 | 28 | steps: 29 | - task: GoTool@0 30 | inputs: 31 | version: $(go) 32 | 33 | - ${{ parameters.pre_test }} 34 | 35 | - bash: | 36 | set -euxo pipefail 37 | mkdir -p '$(module_path)' 38 | shopt -s dotglob extglob 39 | mv !(gopath) '$(module_path)' 40 | echo '##vso[task.prependpath]$(GOPATH)/bin' 41 | displayName: 'set up GOPATH' 42 | 43 | - script: go get -v -t -d ./... 44 | workingDirectory: '$(module_path)' 45 | displayName: 'go get dependencies' 46 | 47 | - script: go test -v ${{ parameters.tests }} 48 | workingDirectory: '$(module_path)' 49 | displayName: 'run tests' 50 | -------------------------------------------------------------------------------- /bin/download-wheels: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from __future__ import annotations 3 | 4 | import argparse 5 | import io 6 | import json 7 | import os.path 8 | import re 9 | import urllib.request 10 | import zipfile 11 | 12 | DEFINITION_RE = re.compile( 13 | r'https://dev.azure.com/(?P[^/]+)/(?P[^/]+)' 14 | r'/_build/latest\?definitionId=(?P\d+)', 15 | ) 16 | BUILDS = 'https://dev.azure.com/{org}/{project}/_apis/build/builds?api-version=5.0&definitions={definition}&$top=5' # noqa: E501 17 | ARTIFACTS = 'https://dev.azure.com/{org}/{project}/_apis/build/builds/{build}/artifacts?api-version=5.0' # noqa: E501 18 | 19 | 20 | def main() -> int: 21 | parser = argparse.ArgumentParser() 22 | parser.add_argument('tag') 23 | parser.add_argument('--dest', default='dist') 24 | args = parser.parse_args() 25 | 26 | with open('README.md') as f: 27 | match = DEFINITION_RE.search(f.read()) 28 | assert match 29 | 30 | builds_resp = urllib.request.urlopen(BUILDS.format(**match.groupdict())) 31 | builds_json = json.load(builds_resp) 32 | 33 | build_id = next( 34 | build['id'] for build in builds_json['value'] 35 | if build['status'] == 'completed' 36 | if build['result'] == 'succeeded' 37 | if build['sourceBranch'] == f'refs/tags/{args.tag}' 38 | ) 39 | 40 | artifacts_url = ARTIFACTS.format(build=build_id, **match.groupdict()) 41 | artifacts_resp = urllib.request.urlopen(artifacts_url) 42 | artifacts_json = json.load(artifacts_resp) 43 | 44 | os.makedirs(args.dest, exist_ok=True) 45 | for artifact in artifacts_json['value']: 46 | if artifact['name'].startswith('wheel_'): 47 | print(f'artifact: {artifact["name"]}') 48 | resp = urllib.request.urlopen(artifact['resource']['downloadUrl']) 49 | bio = io.BytesIO(resp.read()) 50 | with zipfile.ZipFile(bio) as zipf: 51 | for info in zipf.infolist(): 52 | if info.filename.endswith('.whl'): 53 | info.filename = os.path.basename(info.filename) 54 | zipf.extract(info, path=args.dest) 55 | return 0 56 | 57 | 58 | if __name__ == '__main__': 59 | raise SystemExit(main()) 60 | -------------------------------------------------------------------------------- /job--python-tox.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | toxenvs: [] 3 | os: linux 4 | architectures: [x64] 5 | coverage: true 6 | wheel_tags: false 7 | additional_variables: {} 8 | pre_test: [] 9 | name_postfix: '' 10 | 11 | jobs: 12 | - job: ${{ format('tox_{0}{1}', parameters.os, parameters.name_postfix) }} 13 | strategy: 14 | matrix: 15 | ${{ each env in parameters.toxenvs }}: 16 | ${{ each arch in parameters.architectures }}: 17 | ${{ format('{0}_{1}', env, arch) }}: 18 | TOXENV: ${{ env }} 19 | arch: ${{ arch }} 20 | ${{ if or(eq(env, 'py37'), startsWith(env, 'py37-')) }}: 21 | py: '3.7' 22 | ${{ if or(eq(env, 'py38'), startsWith(env, 'py38-')) }}: 23 | py: '3.8' 24 | ${{ if or(eq(env, 'py39'), startsWith(env, 'py39-')) }}: 25 | py: '3.9' 26 | ${{ if or(eq(env, 'py310'), startsWith(env, 'py310-')) }}: 27 | py: '3.10' 28 | ${{ if or(eq(env, 'py311'), startsWith(env, 'py311-')) }}: 29 | py: '3.11' 30 | ${{ if or(eq(env, 'pypy3'), startsWith(env, 'pypy3-')) }}: 31 | py: 'pypy3' 32 | # we'll run tox using this python 33 | ${{ if or(eq(env, 'py312'), startsWith(env, 'py312-')) }}: 34 | py: '3.11' 35 | ispynext: true 36 | # default python for toxenvs which don't start with `py` 37 | ${{ if not(startsWith(env, 'py')) }}: 38 | py: '3.11' 39 | 40 | pool: 41 | ${{ if eq(parameters.os, 'linux') }}: 42 | vmImage: ubuntu-latest 43 | ${{ if eq(parameters.os, 'windows') }}: 44 | vmImage: windows-latest 45 | ${{ if eq(parameters.os, 'macos') }}: 46 | vmImage: macOS-latest 47 | 48 | variables: 49 | ${{ if eq(parameters.os, 'windows') }}: 50 | bindir: Scripts 51 | ${{ if ne(parameters.os, 'windows') }}: 52 | bindir: bin 53 | ${{ insert }}: ${{ parameters.additional_variables }} 54 | 55 | steps: 56 | - task: UsePythonVersion@0 57 | inputs: 58 | versionSpec: $(py) 59 | architecture: $(arch) 60 | 61 | - script: | 62 | sudo add-apt-repository ppa:deadsnakes/nightly 63 | sudo apt-get update 64 | sudo apt-get install -y --no-install-recommends python3.12-dev 65 | condition: variables.ispynext 66 | displayName: install python 3.12 67 | 68 | - ${{ parameters.pre_test }} 69 | 70 | - script: python -m pip install --upgrade tox setuptools virtualenv 71 | displayName: install tox 72 | - script: tox 73 | displayName: run tox 74 | 75 | - ${{ if eq(parameters.coverage, true) }}: 76 | - bash: .tox/$(TOXENV)/$(bindir)/coverage xml -o coverage.xml 77 | displayName: generate coverage xml 78 | - task: PublishCodeCoverageResults@1 79 | inputs: 80 | codeCoverageTool: cobertura 81 | summaryFileLocation: coverage.xml 82 | displayName: publish coverage artifact 83 | 84 | - ${{ if eq(parameters.wheel_tags, true) }}: 85 | - bash: .tox/$(TOXENV)/$(bindir)/pip wheel --no-deps . -w wheels 86 | displayName: build wheel 87 | condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/') 88 | - ${{ if eq(parameters.os, 'macos') }}: 89 | - bash: | 90 | .tox/$(TOXENV)/$(bindir)/pip install 'delocate>=0.10.3' 91 | .tox/$(TOXENV)/$(bindir)/delocate-wheel wheels/*.whl 92 | condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/') 93 | displayName: delocate 94 | - task: PublishBuildArtifacts@1 95 | condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/') 96 | inputs: 97 | pathToPublish: wheels 98 | artifactName: wheel_${{ parameters.os }}_$(TOXENV)${{ parameters.name_postfix }} 99 | displayName: publish wheel artifact 100 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DEPRECATED 2 | 3 | I moved my stuff to github actions using https://github.com/asottile/workflows 4 | 5 | ___ 6 | 7 | [![Build Status](https://dev.azure.com/asottile/asottile/_apis/build/status/asottile.azure-pipeline-templates?branchName=main)](https://dev.azure.com/asottile/asottile/_build/latest?definitionId=7&branchName=main) 8 | [![pre-commit.ci status](https://results.pre-commit.ci/badge/github/asottile/azure-pipeline-templates/main.svg)](https://results.pre-commit.ci/latest/github/asottile/azure-pipeline-templates/main) 9 | 10 | azure-pipeline-templates 11 | ======================== 12 | 13 | ## usage 14 | 15 | **First configure a github service connection** 16 | 17 | It is suggested to use a generic name, such as `github` so forks can also 18 | configure the same. 19 | 20 | You can find this in `Project Settings` => `Service connections` in the 21 | Azure Devops dashboard for your project. Project settings is located in the 22 | bottom left corner of the UI as of 2019-03-07. 23 | 24 | Below I'm using the endpoint name **`github`** 25 | 26 | **Next add this to the beginning of your `azure-pipelines.yml`** 27 | 28 | ```yaml 29 | resources: 30 | repositories: 31 | - repository: asottile 32 | type: github 33 | endpoint: github 34 | name: asottile/azure-pipeline-templates 35 | ref: refs/tags/v2.5.2 36 | ``` 37 | 38 | this will make the templates in this repository available in the `asottile` 39 | namespace. 40 | 41 | ## job templates 42 | 43 | ### `job--python-tox.yml` 44 | 45 | _new in v0.0.1_ 46 | 47 | This job template will install python and invoke tox. 48 | 49 | #### parameters 50 | 51 | - `toxenvs`: the list of `tox` environment names to run 52 | - `os`: choices (`linux`, `windows`, `osx`) 53 | - `architectures`: _new in v2.0.0_ list with choices (`x64`, `x86`), 54 | default `[x64]` (only affects windows) 55 | - `coverage`: _new in v0.0.7_ after the run publish coverage to azure 56 | pipelines, default `true` 57 | - `wheel_tags`: _new in v0.0.10_ after a run of a tag, build a wheel and 58 | publish it as an artifact, default `false`. the artifacts can be downloaded 59 | using the `bin/download-wheels` script included in this repository. 60 | - `additional_variables`: _new in v0.0.13_ additional pipeline `variables` 61 | - `pre_test`: _new in v0.0.5_ `steps` to run before running `tox`, such as 62 | installing tools, etc. default: `[]` 63 | - `name_postfix`: _new in v0.0.5_ string to be appended to job name if you need 64 | to make it unique, default: `''` 65 | 66 | The tox environments must either: 67 | - be equal to: `py37`, `py38`, `py39`, `py310`, `py311`, `py312`, `pypy3` 68 | - start with: `py37-`, `py38-`, `py39-`, `py310-`, `py311-`, `py312-`, `pypy3-` 69 | 70 | for now, python3.12 is only available on linux -- it is installed from 71 | [deadsnakes](https://github.com/deadsnakes) 72 | 73 | coverage information can be displayed using a 74 | [shields.io badge](https://shields.io/category/coverage) 75 | 76 | #### example 77 | 78 | ```yaml 79 | - template: job--python-tox.yml@asottile 80 | parameters: 81 | toxenvs: [py27, py37] 82 | os: windows 83 | ``` 84 | 85 | - [example using this template: asottile/pyupgrade](https://github.com/asottile/pyupgrade/blob/8701d8b7/azure-pipelines.yml#L14-L21) 86 | 87 | ### `job--pre-commit.yml` 88 | 89 | _new in v0.0.2_ 90 | 91 | This job template will invoke [pre-commit](https://pre-commit.com) against all 92 | files. 93 | 94 | #### parameters 95 | 96 | - `ruby`: the version of ruby to install to the system (used by some hooks), 97 | defaults to `'>= 2.4'` 98 | - `python`: the python version to run pre-commit with, defaults to `'3.7'` 99 | 100 | #### example 101 | 102 | ```yaml 103 | - template: job--pre-commit.yml@asottile 104 | ``` 105 | 106 | - [example using this template: pre-commit/pygrep-hooks](https://github.com/pre-commit/pygrep-hooks/blob/2968c93e/azure-pipelines.yml#L9-L10) 107 | 108 | ### `job--go-test.yml` 109 | 110 | _new in v0.0.6_ 111 | 112 | This job checks out a go project, runs `go get` and then `go test` 113 | 114 | #### parameters 115 | 116 | - `go_versions`: list of go versions to test against 117 | - `os`: choices (`linux`, `windows`, `macos`) 118 | - `tests`: what to `go test ...`, default `./...` 119 | - `pre_test`: `steps` to run before running `tox`, such as installing tools, 120 | etc. default: `[]` 121 | - `name_postfix`: string to be appended to job name if you need to make it 122 | unique, default: `''` 123 | 124 | #### example 125 | 126 | ```yaml 127 | - template: job--go-test.yml@asottile 128 | parameters: 129 | go_versions: ['1.11.5', '1.12'] 130 | os: 'linux' 131 | ``` 132 | 133 | - [example using this template: asottile/dockerfile](https://github.com/asottile/dockerfile/blob/2bd942dc/azure-pipelines.yml#L16-L21) 134 | 135 | ## step templates 136 | 137 | When referring to a step template as part of `pre_test`, omit the `@asottile` 138 | repository selector (as the template is included *after* job templating). 139 | 140 | ### `step--git-install.yml` 141 | 142 | _new in v0.0.8_ 143 | 144 | This step template will install `git` from source and put it on the `PATH`. 145 | This step is currently only supported on `linux`. 146 | 147 | #### parameters 148 | 149 | - `versions`: ref to install at, default `HEAD` 150 | 151 | #### example 152 | 153 | ```yaml 154 | - template: step--install-git.yml 155 | ``` 156 | --------------------------------------------------------------------------------