Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4/26 release: Up with --repo/--browse, exec (ssh) command, replica commands, log streaming commands #72

Merged
merged 168 commits into from
Apr 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
168 commits
Select commit Hold shift + click to select a range
0bfdddd
Skeleton code
calvinsID Feb 3, 2022
16afa69
az containerapp env show
calvinsID Feb 3, 2022
2323591
List kube/managed environments
calvinsID Feb 3, 2022
9397d54
Create kube environment, wait doesn't work yet
calvinsID Feb 4, 2022
4fa3771
Update containerapp stubs (check if it is supported now)
calvinsID Feb 4, 2022
0d7ce56
Containerapp env delete, polling not working yet
calvinsID Feb 4, 2022
055907f
Added polling for create and delete
calvinsID Feb 4, 2022
31b2415
Use Microsoft.App RP for show, list, delete command
calvinsID Feb 5, 2022
232512f
Create containerapp env using Microsoft.App RP
calvinsID Feb 6, 2022
baf19b4
Add optional containerapp env create arguments
calvinsID Feb 8, 2022
76f62ba
Remove old kube environment code, naming fixes
calvinsID Feb 8, 2022
12524a7
Containerapp create almost done
calvinsID Feb 11, 2022
99a3d38
Done containerapp create, except for --yaml. Need to test
calvinsID Feb 11, 2022
1c74c2e
Containerapp show, list
calvinsID Feb 11, 2022
3c0c501
Fix helptext
calvinsID Feb 11, 2022
958facf
Containerapp delete
calvinsID Feb 11, 2022
2a230f0
Containerapp update. Needs secrets api to be implemented, and testing
calvinsID Feb 14, 2022
c65b264
Add scale command
calvinsID Feb 14, 2022
2901b61
Various validations, small fixes
calvinsID Feb 15, 2022
02cf535
listSecrets API for updates, autogen log analytics for env
calvinsID Feb 18, 2022
fbd6407
Use space delimiter for secrets and env variables
calvinsID Feb 24, 2022
6513981
Verify sub is registered to Microsoft.ContainerRegistration if creati…
calvinsID Feb 25, 2022
bacf864
Containerapp create --yaml
calvinsID Feb 23, 2022
9777c5f
Fix updating registry to do create or update
calvinsID Feb 23, 2022
71e9c9b
Fix containerapp update command. Add image-name parameter to support …
calvinsID Feb 23, 2022
5e3888a
started update with --yaml. Need to do create or update for when an a…
calvinsID Feb 23, 2022
b419f8d
use space delimiter for startup_command and args, instead of comma de…
calvinsID Feb 24, 2022
84c56b5
Traffic weights
calvinsID Mar 1, 2022
07cae9d
List and show revisions
calvinsID Feb 24, 2022
7df8730
az containerapp revision restart, activate, deactivate
calvinsID Feb 24, 2022
43897cc
Add ability for users to clear args/command in az containerapp update
calvinsID Mar 3, 2022
7a380e3
Various fixes, traffic weights fixes
calvinsID Mar 3, 2022
983af7c
Verify subnet subscription is registered to Microsoft.ContainerServices
calvinsID Mar 4, 2022
328683b
GitHub Actions Update (#17)
runefa Mar 8, 2022
0f582e0
Remove --location since location must be same as managed env
calvinsID Mar 8, 2022
d4272d8
Add options for flag names: --env-vars and --registry-srever
calvinsID Mar 8, 2022
42519dc
Empty string to clear env_vars
calvinsID Mar 8, 2022
8caebc7
Default revisions_mode to single
calvinsID Mar 8, 2022
11e7fe0
Infer acr credentials if it is acr and credentials are not provided
calvinsID Mar 8, 2022
85fd0f5
fix help msg
calvinsID Mar 8, 2022
6bf5a56
if image is hosted on acr, and no registry server is supplied, infer …
calvinsID Mar 9, 2022
25e1250
Added subgroups (Ingress, Registry, Secret) and updated revisions (#18)
runefa Mar 11, 2022
22e428c
More p0 fixes (#20)
calvinsID Mar 11, 2022
e12b19c
Update help text (#21)
anthonychu Mar 14, 2022
abece41
New 1.0.1 version
calvinsID Mar 14, 2022
7d8b9ba
Added identity commands + --assign-identity flag to containerapp crea…
runefa Mar 14, 2022
bc8c58b
Dapr Commands (#23)
runefa Mar 14, 2022
869c11b
Rename --image-name to --container-name
calvinsID Mar 14, 2022
0857b6b
Remove allowInsecure since it was messing with the api parsing
calvinsID Mar 14, 2022
a0acb01
Fix for env var being empty string
calvinsID Mar 14, 2022
0f4f385
Rename to --dapr-instrumentation-key, only infer ACR credentials if -…
calvinsID Mar 14, 2022
144ce57
Remove az containerapp scale
calvinsID Mar 14, 2022
3b01ec6
Fix delete containerapp errors
calvinsID Mar 14, 2022
b671af3
Remove ingress, dapr flags from az containerapp update/revision copy
calvinsID Mar 14, 2022
df1ae0b
Fix revision list -o table
calvinsID Mar 14, 2022
9962e29
Help text fix
calvinsID Mar 14, 2022
ef031f4
Bump extension to 0.1.2
calvinsID Mar 14, 2022
a26df8c
Update managed identities and Dapr help text (#25)
anthonychu Mar 15, 2022
ea45ec8
Env var options + various bug fixes (#26)
runefa Mar 16, 2022
43acd4b
Fixed style issues, various bug fixes (#27)
runefa Mar 18, 2022
a607ed9
Update src/containerapp/azext_containerapp/tests/latest/test_containe…
runefa Mar 18, 2022
9652f3e
Specific Error Types + Bugfixes (Help, remove app-subnet-resource-id,…
runefa Mar 21, 2022
46b5a94
Reset to 0.1.0 version, remove unneeded options-list
calvinsID Mar 21, 2022
a8e75ba
Update min cli core version
calvinsID Mar 21, 2022
c1288b7
Fixed style issues. (#30)
runefa Mar 21, 2022
d4fbdae
Fix linter issues
calvinsID Mar 21, 2022
48f2eb9
Use custom-show-command
calvinsID Mar 21, 2022
f19323f
Removed --ids from revision, secret, registry list.
Mar 21, 2022
0f402d8
Add linter exclusions
calvinsID Mar 21, 2022
8f006f1
Fix polling on delete containerapp
calvinsID Mar 21, 2022
f259b6f
Fix error handling
calvinsID Mar 21, 2022
c96f1e5
Add Container App Service
calvinsID Mar 21, 2022
3b823cf
Fix flake linter
calvinsID Mar 21, 2022
0e5552d
Fix help text
calvinsID Mar 22, 2022
51c540b
Mark extension as preview
calvinsID Mar 22, 2022
ff2ba40
Add python 3.9 and 3.10 as supported
calvinsID Mar 22, 2022
c45cbd0
Remove registries and secrets from az containerapp update, in favor o…
calvinsID Mar 22, 2022
126878c
Fix YAML not working
calvinsID Mar 22, 2022
e64cbef
Move import to inside deserialize function
calvinsID Mar 22, 2022
40d112c
Dapr moved from Template to Configuration
calvinsID Mar 22, 2022
bade2b1
Use aka.ms link for containerapps yaml
calvinsID Mar 22, 2022
0922c68
Updated dapr enable/disable to current spec.
Mar 22, 2022
2badc74
Fixed oversight.
Mar 22, 2022
2bf3686
Remove revisions-mode from containerapp update
calvinsID Mar 23, 2022
eec4e1a
Fixed dapr enable property names. (#47)
runefa Mar 23, 2022
c43d1ca
Fix exceptions with using --yaml in containerapp create/update
calvinsID Mar 23, 2022
a0e7ca1
Rename history msg
calvinsID Mar 24, 2022
5f68333
Include fqdn in containerapp table output
calvinsID Mar 24, 2022
0b6fb6f
Added ingress messages.
Mar 23, 2022
2f07b6e
Revert history msg
calvinsID Mar 24, 2022
ad6ff27
Add basic test case
calvinsID Mar 24, 2022
a4d1ec2
Remove managed-identity support for first release of CLI
calvinsID Mar 24, 2022
b0aab4f
Need to investigate test flakiness
calvinsID Mar 24, 2022
5d0bef3
Update _help.py
panchagnula Mar 25, 2022
03ed09a
Added prototype of container up.
Mar 29, 2022
5797a89
Fixed deploy from acr registry image infer credentials issue.
Mar 29, 2022
9910366
Tried to add source.
Mar 30, 2022
c8e460e
Added acr build.
Mar 31, 2022
52abab9
Finished acr build functionality.
Mar 31, 2022
4a71bb8
Added acr create functionality and pull registry from existing contai…
Mar 31, 2022
bcb1954
Fixed bugs.
Apr 1, 2022
7dae662
Check if rg exists and create one with name if it doesn't.
Apr 1, 2022
cddad94
initial containerapp ssh implementation
StrawnSC Apr 4, 2022
b2f8909
Merge branch 'main' into containerapp-ssh
StrawnSC Apr 4, 2022
3d9c67a
fix interactive commands (vim); handle ctrl + c instead of exiting
StrawnSC Apr 4, 2022
c8130a4
fix style and linter issues
StrawnSC Apr 5, 2022
d94a36d
Added disable verbose. Moved utils into utils.py.
Apr 5, 2022
581d629
fix for ssh for windows clients
StrawnSC Apr 5, 2022
2ca69cd
fix for unix
StrawnSC Apr 5, 2022
dadc702
Disable verbose now uses sdk poller so it gives running animation.
Apr 5, 2022
a7c880a
Added helps for params. Added error handling for non acr registry pas…
Apr 6, 2022
9eea137
Updated disable_warnings ignore. Removed disable_warnings from update…
Apr 6, 2022
5bc365d
add terminal resizing
StrawnSC Apr 6, 2022
d0271f7
reorganize code; implement terminal resizing, add startup command par…
StrawnSC Apr 6, 2022
19d91bb
organize code, remove token from warning output
StrawnSC Apr 6, 2022
06088cd
add validations, add replica commands
StrawnSC Apr 7, 2022
668082b
use the correct API for fetching default container; remove is_preview
StrawnSC Apr 7, 2022
5b2b3c6
Renamed silent to quiet.
Apr 7, 2022
bba0599
Fixed style issues.
Apr 7, 2022
99fb00f
add log streaming, bump version number and add to HISTORY.rst
StrawnSC Apr 7, 2022
5a6e739
add basic ssh test
StrawnSC Apr 8, 2022
b8315bc
Added workspace name and fqdn to dry_run_str. Added indicators of if …
Apr 8, 2022
45faea7
fix ssh test for windows
StrawnSC Apr 8, 2022
0329a53
Check RP for location when not provided. Open Dockerfile and use EXPO…
Apr 8, 2022
dc8953f
fix windows arrow keys after exit
StrawnSC Apr 8, 2022
fe28fce
fix typo, add logstream test, remove token from logstream output
StrawnSC Apr 8, 2022
51a868f
Removed print statement.
Apr 11, 2022
429fbaa
Updated dockerfile expose automatic ingress feature.
Apr 11, 2022
402f6df
Removed dry run str, added dry run obj instead.
Apr 11, 2022
337a454
use bearer auth; fix --command bug
StrawnSC Apr 12, 2022
74fe23b
add handling for smooth transition to new URL path
StrawnSC Apr 12, 2022
6021037
Merge branch 'main' into containerapp-ssh
StrawnSC Apr 12, 2022
8e81c93
Merged main.
Apr 12, 2022
f53be71
Fixed merge conflict.
Apr 12, 2022
f114468
fix merge conflicts
StrawnSC Apr 12, 2022
2f3e8b3
Create env if name passed and it doesn't exist.
Apr 13, 2022
45dd7f8
Added missing import from merge.
Apr 13, 2022
dd38d8d
Merge pull request #2 from haroonf/demo
StrawnSC Apr 13, 2022
3380c63
Added prototype for new environment workflow.
Apr 13, 2022
8fbf360
Finished environment logic.
Apr 14, 2022
c65196f
Minor updates before demo.
Apr 15, 2022
67d6858
add 'az containerapp github up' (wip)
StrawnSC Apr 17, 2022
43fb1a4
merge calvinsid/main and resolve conflicts
StrawnSC Apr 17, 2022
4f04ac9
various fixes for demo
StrawnSC Apr 17, 2022
125d56f
rearrange github up code
StrawnSC Apr 19, 2022
78f1bf0
merge haroonf/containerappup
StrawnSC Apr 19, 2022
0e86947
merge haroonf/containerappup
StrawnSC Apr 19, 2022
ac98e1c
finish merge
StrawnSC Apr 19, 2022
6b03b8f
Merge branch 'calmain' into github-up-demo
StrawnSC Apr 19, 2022
3e1dca2
start up refactor
StrawnSC Apr 20, 2022
3526d67
add --repo to up and refactor up
StrawnSC Apr 20, 2022
057bdc1
reorganize code more; fix various bugs
StrawnSC Apr 21, 2022
4a16e17
fix linter issues, fix lingering exec/tail improvements
StrawnSC Apr 21, 2022
1e80127
update history
StrawnSC Apr 21, 2022
dd84735
update output
StrawnSC Apr 21, 2022
e8c3c34
bug fixes for --repo
StrawnSC Apr 21, 2022
16bf2b8
fix --source bug
StrawnSC Apr 21, 2022
a877444
fix --source
StrawnSC Apr 21, 2022
0f49ce0
minor bug fixes
StrawnSC Apr 21, 2022
e886ea4
Added API change.
Apr 21, 2022
bfcace8
Finished API change, added helloworld image auto ingress, checked pro…
Apr 21, 2022
b3aae19
fixes for sisira's comments
StrawnSC Apr 21, 2022
78b1c50
fix minor typo
StrawnSC Apr 21, 2022
0ba7185
bug fix where commands fail if providing registry creds
StrawnSC Apr 22, 2022
39dad3d
Merged.
Apr 22, 2022
b0061f3
Merge pull request #4 from haroonf/APIChanges
runefa Apr 22, 2022
c7e07db
Fixed style issues.
Apr 22, 2022
ba1d01e
Updated help and version text.
Apr 22, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/containerapp/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
Release History
===============

0.3.2
++++++
* Added 'az containerapp up' to create or update a container app and all associated resources (container app environment, ACR, Github Actions, resource group, etc.)
* Open an ssh-like shell in a Container App with 'az containerapp exec'
* Support for log streaming with 'az containerapp logs show'
* Replica show and list commands

0.3.1
++++++
* Update "az containerapp github-action add" parameters: replace --docker-file-path with --context-path, add --image.
Expand Down
4 changes: 4 additions & 0 deletions src/containerapp/azext_containerapp/.flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[flake8]
ignore =
panchagnula marked this conversation as resolved.
Show resolved Hide resolved
W503 # line break before binary operator, not compliant with PEP 8
E203 # whitespace before ':', not compliant with PEP 8
112 changes: 112 additions & 0 deletions src/containerapp/azext_containerapp/_acr_run_polling.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
# pylint: disable=line-too-long, consider-using-f-string

import time

from msrest import Deserializer
from msrestazure.azure_exceptions import CloudError
from azure.cli.core.profiles import ResourceType
from azure.cli.command_modules.acr._constants import get_acr_task_models
from azure.core.polling import PollingMethod, LROPoller


def get_run_with_polling(cmd,
client,
run_id,
registry_name,
resource_group_name):
deserializer = Deserializer(
{k: v for k, v in get_acr_task_models(cmd).__dict__.items() if isinstance(v, type)})

def deserialize_run(response):
return deserializer('Run', response)

return LROPoller(
client=client,
initial_response=client.get(
resource_group_name, registry_name, run_id, cls=lambda x, y, z: x),
deserialization_callback=deserialize_run,
polling_method=RunPolling(
cmd=cmd,
registry_name=registry_name,
run_id=run_id
))


class RunPolling(PollingMethod): # pylint: disable=too-many-instance-attributes

def __init__(self, cmd, registry_name, run_id, timeout=30):
self._cmd = cmd
self._registry_name = registry_name
self._run_id = run_id
self._timeout = timeout
self._client = None
self._response = None # Will hold latest received response
self._url = None # The URL used to get the run
self._deserialize = None # The deserializer for Run
self.operation_status = ""
self.operation_result = None

def initialize(self, client, initial_response, deserialization_callback):
self._client = client._client # pylint: disable=protected-access
self._response = initial_response
self._url = initial_response.http_request.url
self._deserialize = deserialization_callback

self._set_operation_status(initial_response)

def run(self):
while not self.finished():
time.sleep(self._timeout)
self._update_status()

if self.operation_status not in get_succeeded_run_status(self._cmd):
from knack.util import CLIError
raise CLIError("The run with ID '{}' finished with unsuccessful status '{}'. "
"Show run details by 'az acr task show-run -r {} --run-id {}'. "
"Show run logs by 'az acr task logs -r {} --run-id {}'.".format(
self._run_id,
self.operation_status,
self._registry_name,
self._run_id,
self._registry_name,
self._run_id
))

def status(self):
return self.operation_status

def finished(self):
return self.operation_status in get_finished_run_status(self._cmd)

def resource(self):
return self.operation_result

def _set_operation_status(self, response):
if response.http_response.status_code == 200:
self.operation_result = self._deserialize(response)
self.operation_status = self.operation_result.status
return
raise CloudError(response)

def _update_status(self):
self._response = self._client._pipeline.run( # pylint: disable=protected-access
self._client.get(self._url), stream=False)
self._set_operation_status(self._response)


def get_succeeded_run_status(cmd):
RunStatus = cmd.get_models('RunStatus', resource_type=ResourceType.MGMT_CONTAINERREGISTRY, operation_group='task_runs')
return [RunStatus.succeeded.value]


def get_finished_run_status(cmd):
RunStatus = cmd.get_models('RunStatus', resource_type=ResourceType.MGMT_CONTAINERREGISTRY, operation_group='task_runs')
return [RunStatus.succeeded.value,
RunStatus.failed.value,
RunStatus.canceled.value,
RunStatus.error.value,
RunStatus.timeout.value]
243 changes: 243 additions & 0 deletions src/containerapp/azext_containerapp/_archive_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
# --------------------------------------------------------------------------------------------
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious with the name of the file archive?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't add this. @haroonf is this from your branch?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if these methods are used - please rename the file, to reflect what this utils is for?

# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
# pylint: disable=consider-using-f-string, consider-using-with, no-member

import tarfile
import os
import re
import codecs
from io import open
import requests
from knack.log import get_logger
from msrestazure.azure_exceptions import CloudError
from azure.cli.core.azclierror import (CLIInternalError)
from azure.cli.core.profiles import ResourceType, get_sdk
from azure.cli.command_modules.acr._azure_utils import get_blob_info
from azure.cli.command_modules.acr._constants import TASK_VALID_VSTS_URLS

logger = get_logger(__name__)


def upload_source_code(cmd, client,
registry_name,
resource_group_name,
source_location,
tar_file_path,
docker_file_path,
docker_file_in_tar):
_pack_source_code(source_location,
tar_file_path,
docker_file_path,
docker_file_in_tar)

size = os.path.getsize(tar_file_path)
unit = 'GiB'
for S in ['Bytes', 'KiB', 'MiB', 'GiB']:
if size < 1024:
unit = S
break
size = size / 1024.0

logger.info("Uploading archived source code from '%s'...", tar_file_path)
upload_url = None
relative_path = None
try:
source_upload_location = client.get_build_source_upload_url(
resource_group_name, registry_name)
upload_url = source_upload_location.upload_url
relative_path = source_upload_location.relative_path
except (AttributeError, CloudError) as e:
raise CLIInternalError("Failed to get a SAS URL to upload context. Error: {}".format(e.message)) from e

if not upload_url:
raise CLIInternalError("Failed to get a SAS URL to upload context.")

account_name, endpoint_suffix, container_name, blob_name, sas_token = get_blob_info(upload_url)
BlockBlobService = get_sdk(cmd.cli_ctx, ResourceType.DATA_STORAGE, 'blob#BlockBlobService')
BlockBlobService(account_name=account_name,
sas_token=sas_token,
endpoint_suffix=endpoint_suffix,
# Increase socket timeout from default of 20s for clients with slow network connection.
socket_timeout=300).create_blob_from_path(
container_name=container_name,
blob_name=blob_name,
file_path=tar_file_path)
logger.info("Sending context ({0:.3f} {1}) to registry: {2}...".format(
size, unit, registry_name))
return relative_path


def _pack_source_code(source_location, tar_file_path, docker_file_path, docker_file_in_tar):
logger.info("Packing source code into tar to upload...")

original_docker_file_name = os.path.basename(docker_file_path.replace("\\", os.sep))
ignore_list, ignore_list_size = _load_dockerignore_file(source_location, original_docker_file_name)
common_vcs_ignore_list = {'.git', '.gitignore', '.bzr', 'bzrignore', '.hg', '.hgignore', '.svn'}

def _ignore_check(tarinfo, parent_ignored, parent_matching_rule_index):
# ignore common vcs dir or file
if tarinfo.name in common_vcs_ignore_list:
logger.info("Excluding '%s' based on default ignore rules", tarinfo.name)
return True, parent_matching_rule_index

if ignore_list is None:
# if .dockerignore doesn't exists, inherit from parent
# eg, it will ignore the files under .git folder.
return parent_ignored, parent_matching_rule_index

for index, item in enumerate(ignore_list):
# stop checking the remaining rules whose priorities are lower than the parent matching rule
# at this point, current item should just inherit from parent
if index >= parent_matching_rule_index:
break
if re.match(item.pattern, tarinfo.name):
logger.debug(".dockerignore: rule '%s' matches '%s'.",
item.rule, tarinfo.name)
return item.ignore, index

logger.debug(".dockerignore: no rule for '%s'. parent ignore '%s'",
tarinfo.name, parent_ignored)
# inherit from parent
return parent_ignored, parent_matching_rule_index

with tarfile.open(tar_file_path, "w:gz") as tar:
# need to set arcname to empty string as the archive root path
_archive_file_recursively(tar,
source_location,
arcname="",
parent_ignored=False,
parent_matching_rule_index=ignore_list_size,
ignore_check=_ignore_check)

# Add the Dockerfile if it's specified.
# In the case of run, there will be no Dockerfile.
if docker_file_path:
docker_file_tarinfo = tar.gettarinfo(
docker_file_path, docker_file_in_tar)
with open(docker_file_path, "rb") as f:
tar.addfile(docker_file_tarinfo, f)


class IgnoreRule: # pylint: disable=too-few-public-methods
def __init__(self, rule):

self.rule = rule
self.ignore = True
# ! makes exceptions to exclusions
if rule.startswith('!'):
self.ignore = False
rule = rule[1:] # remove !
# load path without leading slash in linux and windows
# environments (interferes with dockerignore file)
if rule.startswith('/'):
rule = rule[1:] # remove beginning '/'

self.pattern = "^"
tokens = rule.split('/')
token_length = len(tokens)
for index, token in enumerate(tokens, 1):
# ** matches any number of directories
if token == "**":
self.pattern += ".*" # treat **/ as **
else:
# * matches any sequence of non-seperator characters
# ? matches any single non-seperator character
# . matches dot character
self.pattern += token.replace(
"*", "[^/]*").replace("?", "[^/]").replace(".", "\\.")
if index < token_length:
self.pattern += "/" # add back / if it's not the last
self.pattern += "$"


def _load_dockerignore_file(source_location, original_docker_file_name):
# reference: https://docs.docker.com/engine/reference/builder/#dockerignore-file
docker_ignore_file = os.path.join(source_location, ".dockerignore")
docker_ignore_file_override = None
if original_docker_file_name != "Dockerfile":
docker_ignore_file_override = os.path.join(
source_location, "{}.dockerignore".format(original_docker_file_name))
if os.path.exists(docker_ignore_file_override):
logger.info("Overriding .dockerignore with %s", docker_ignore_file_override)
docker_ignore_file = docker_ignore_file_override

if not os.path.exists(docker_ignore_file):
return None, 0

encoding = "utf-8"
header = open(docker_ignore_file, "rb").read(len(codecs.BOM_UTF8))
if header.startswith(codecs.BOM_UTF8):
encoding = "utf-8-sig"

ignore_list = []
if docker_ignore_file == docker_ignore_file_override:
ignore_list.append(IgnoreRule(".dockerignore"))

for line in open(docker_ignore_file, 'r', encoding=encoding).readlines():
rule = line.rstrip()

# skip empty line and comment
if not rule or rule.startswith('#'):
continue

# the ignore rule at the end has higher priority
ignore_list = [IgnoreRule(rule)] + ignore_list

return ignore_list, len(ignore_list)


def _archive_file_recursively(tar, name, arcname, parent_ignored, parent_matching_rule_index, ignore_check):
# create a TarInfo object from the file
tarinfo = tar.gettarinfo(name, arcname)

if tarinfo is None:
raise CLIInternalError("tarfile: unsupported type {}".format(name))

# check if the file/dir is ignored
ignored, matching_rule_index = ignore_check(
tarinfo, parent_ignored, parent_matching_rule_index)

if not ignored:
# append the tar header and data to the archive
if tarinfo.isreg():
with open(name, "rb") as f:
tar.addfile(tarinfo, f)
else:
tar.addfile(tarinfo)

# even the dir is ignored, its child items can still be included, so continue to scan
if tarinfo.isdir():
for f in os.listdir(name):
_archive_file_recursively(tar, os.path.join(name, f), os.path.join(arcname, f),
parent_ignored=ignored, parent_matching_rule_index=matching_rule_index,
ignore_check=ignore_check)


def check_remote_source_code(source_location):
lower_source_location = source_location.lower()

# git
if lower_source_location.startswith("git@") or lower_source_location.startswith("git://"):
return source_location

# http
if lower_source_location.startswith("https://") or lower_source_location.startswith("http://") \
or lower_source_location.startswith("github.com/"):
isVSTS = any(url in lower_source_location for url in TASK_VALID_VSTS_URLS)
if isVSTS or re.search(r"\.git(?:#.+)?$", lower_source_location):
# git url must contain ".git" or be from VSTS/Azure DevOps.
# This is because Azure DevOps doesn't follow the standard git server convention of putting
# .git at the end of their URLs, so we have to special case them.
return source_location
if not lower_source_location.startswith("github.com/"):
# Others are tarball
if requests.head(source_location).status_code < 400:
return source_location
raise CLIInternalError("'{}' doesn't exist.".format(source_location))

# oci
if lower_source_location.startswith("oci://"):
return source_location
raise CLIInternalError("'{}' doesn't exist.".format(source_location))
Loading