Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"version": "0.2.0",
"configurations": [
{
"name": ".NET Core Launch (console)",
"name": "Run func cli (console)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
Expand Down
2 changes: 1 addition & 1 deletion eng/ci/consolidate-artifacts-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ variables:
- name: DisableKubernetesDeploymentDetector
value: true
- name: supportedRuntimes
value: 'linux-x64,osx-x64,osx-arm64,win-arm64,win-x64,win-x86,min.win-arm64,min.win-x86,min.win-x64'
value: 'linux-x64,linux-arm64,osx-x64,osx-arm64,win-arm64,win-x64,win-x86,min.win-arm64,min.win-x86,min.win-x64'
# Skipping arm64 builds for testing as we do not have an agent pool that supports it.
- name: supportedRuntimesForTesting
value: 'linux-x64,osx-x64,win-x64,win-x86,min.win-x64,min.win-x86'
Expand Down
2 changes: 1 addition & 1 deletion eng/ci/official-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ variables:
- name: DisableKubernetesDeploymentDetector
value: true
- name: supportedRuntimes
value: 'linux-x64,osx-x64,osx-arm64,win-arm64,win-x64,win-x86,min.win-arm64,min.win-x86,min.win-x64'
value: 'linux-x64,linux-arm64,osx-x64,osx-arm64,win-arm64,win-x64,win-x86,min.win-arm64,min.win-x86,min.win-x64'

extends:
template: v1/1ES.Official.PipelineTemplate.yml@1es
Expand Down
2 changes: 1 addition & 1 deletion eng/ci/public-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ resources:

variables:
- name: supportedRuntimes
value: 'linux-x64,osx-x64,osx-arm64,win-arm64,win-x64,win-x86,min.win-arm64,min.win-x86,min.win-x64'
value: 'linux-x64,linux-arm64,osx-x64,osx-arm64,win-arm64,win-x64,win-x86,min.win-arm64,min.win-x86,min.win-x64'

extends:
template: v1/1ES.Unofficial.PipelineTemplate.yml@1es
Expand Down
30 changes: 26 additions & 4 deletions eng/ci/templates/official/jobs/linux-deb-build-pack.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ jobs:
artifact: drop_debian

steps:
- script: |
sudo apt-get update
sudo apt-get install -y binutils-aarch64-linux-gnu
sudo apt-get install -y fakeroot
displayName: 'Install required tools'

- task: PowerShell@2
displayName: 'Read metadata from consolidated build'
inputs:
Expand Down Expand Up @@ -56,7 +62,6 @@ jobs:
pip install -r requirements.txt
pip install wget

sudo apt-get install fakeroot
major_version=$(echo "$linuxBuildNumber" | cut -d'.' -f1)
python driver.py "$linuxBuildNumber" "$consolidatedBuildId" "$major_version"
python driver.py "$linuxBuildNumber" "$consolidatedBuildId"
Expand Down Expand Up @@ -86,9 +91,26 @@ jobs:

- pwsh: |
echo $env:LinuxPackageAccountName
$majorVersion = [math]::Floor([double]$env:LinuxPackageBuildTag.Split(".")[0])
az storage blob upload -f /mnt/vss/_work/1/s/eng/tools/publish-tools/artifact/azure-functions-core-tools_$env:LinuxPackageBuildTag-1.deb -c signed -n azure-functions-core-tools_$env:LinuxPackageBuildTag-1.deb --account-name $env:LinuxPackageAccountName --account-key $env:LinuxPackageAccountKey
az storage blob upload -f /mnt/vss/_work/1/s/eng/tools/publish-tools/artifact/azure-functions-core-tools-$($majorVersion)_$env:LinuxPackageBuildTag-1.deb -c signed -n azure-functions-core-tools-$($majorVersion)_$env:LinuxPackageBuildTag-1.deb --account-name $env:LinuxPackageAccountName --account-key $env:LinuxPackageAccountKey
$buildTag = $env:LinuxPackageBuildTag
$majorVersion = [math]::Floor([double]$buildTag.Split(".")[0])

# Convert to Debian version format
if ($buildTag -like "*-*") {
$parts = $buildTag -split "-"
$debianVersion = "$($parts[0])~$($parts[1])-1"
} else {
$debianVersion = "$buildTag-1"
}

foreach ($arch in @("x64", "arm64")) {
$fileName = "azure-functions-core-tools_${debianVersion}_${arch}.deb"
$filePath = "/mnt/vss/_work/1/s/eng/tools/publish-tools/artifact/$fileName"
az storage blob upload -f $filePath -c signed -n $fileName --account-name $env:LinuxPackageAccountName --account-key $env:LinuxPackageAccountKey

$fileNameMajor = "azure-functions-core-tools-$($majorVersion)_${debianVersion}_${arch}.deb"
$filePathMajor = "/mnt/vss/_work/1/s/eng/tools/publish-tools/artifact/$fileNameMajor"
az storage blob upload -f $filePathMajor -c signed -n $fileNameMajor --account-name $env:LinuxPackageAccountName --account-key $env:LinuxPackageAccountKey
}
env:
LinuxPackageAccountName: $(LinuxPackageAccountName)
LinuxPackageAccountKey: $(LinuxPackageAccountKey)
Expand Down
3 changes: 3 additions & 0 deletions eng/ci/templates/official/jobs/merge-pipeline-artifacts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ jobs:
- input: pipelineArtifact
artifactName: func-cli-linux-x64
targetPath: $(Pipeline.Workspace)/func-cli
- input: pipelineArtifact
artifactName: func-cli-linux-arm64
targetPath: $(Pipeline.Workspace)/func-cli

- input: pipelineArtifact
artifactName: func-cli-osx-x64
Expand Down
23 changes: 19 additions & 4 deletions eng/tools/publish-tools/npm/lib/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,25 @@ if (os.platform() === 'win32') {
platform = 'osx-x64';
}
} else if (os.platform() === 'linux') {
platform = 'linux-x64';
if (os.arch() === 'arm64') {
platform = 'linux-arm64';
} else {
platform = 'linux-x64';
}
} else {
throw Error('platform ' + os.platform() + ' isn\'t supported');
}

const fileName = 'Azure.Functions.Cli.' + platform + '.' + version + '.zip';
const endpoint = 'https://cdn.functions.azure.com/public/' + consolidatedBuildId + '/' + fileName;

console.log('attempting to GET %j', endpoint);
const options = url.parse(endpoint);

// npm config preceed system environment
// https://github.com/npm/npm/blob/19397ad523434656af3d3765e80e22d7e6305f48/lib/config/reg-client.js#L7-L8
// https://github.com/request/request/blob/b12a6245d9acdb1e13c6486d427801e123fdafae/lib/getProxyFromURI.js#L66-L71

const proxy = process.env.npm_config_https_proxy ||
process.env.npm_config_proxy ||
process.env.HTTPS_PROXY ||
Expand Down Expand Up @@ -96,11 +103,19 @@ https.get(options, response => {
catch (err) {
// That's alright.
}
if (os.platform() === 'linux' || os.platform() === 'darwin') {

const platform = os.platform();
const arch = os.arch();

if (platform === 'linux' || platform === 'darwin') {
fs.chmodSync(`${installPath}/func`, 0o755);
fs.chmodSync(`${installPath}/gozip`, 0o755);
fs.chmodSync(`${installPath}/in-proc8/func`, 0o755);
fs.chmodSync(`${installPath}/in-proc6/func`, 0o755);

// inproc is not packaged in the linux-arm64 builds, so skip setting permissions for that platform
if (!(platform === 'linux' && arch === 'arm64')) {
fs.chmodSync(`${installPath}/in-proc8/func`, 0o755);
fs.chmodSync(`${installPath}/in-proc6/func`, 0o755);
}
}
});
});
Expand Down
15 changes: 10 additions & 5 deletions eng/tools/publish-tools/shared/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ def produceHashForfile(filePath, hashType, Upper = True):
return hashobj.hexdigest().lower()

@restoreDirectory
def linuxOutput(buildFolder):
def linuxOutput(buildFolder, arch):
os.chdir(constants.DRIVERROOTDIR)

# ubuntu dropped 64, fedora supports both
fileName = f"Azure.Functions.Cli.linux-x64.{constants.VERSION}.zip"
fileName = f"Azure.Functions.Cli.linux-{arch}.{constants.VERSION}.zip"
url = f'https://cdn.functions.azure.com/public/4.0.{constants.CONSOLIDATED_BUILD_ID}/{fileName}'

# download the zip
Expand Down Expand Up @@ -88,18 +88,23 @@ def linuxOutput(buildFolder):
exeFullPath = os.path.abspath("func")

os.chdir(buildFolder)

# strip sharedobjects
import glob

sharedObjects = glob.glob("**/*.so", recursive=True)
stripBinary = "strip"
if arch == "arm64":
stripBinary = "aarch64-linux-gnu-strip"

# obj files inside the workers should not be removed as workers like "python"
# come with objects necessary for the worker to work.
sharedObjects = glob.glob("**/*.so", recursive=True)
sharedObjects = [obj for obj in sharedObjects if "workers" not in obj]
printReturnOutput(["strip", "--strip-unneeded"] + sharedObjects)

chmodFolderAndFiles(os.path.join(buildFolder, "usr"))
printReturnOutput([stripBinary, "--strip-unneeded"] + sharedObjects)

print(f"change bin/func permission to 755")
chmodFolderAndFiles(os.path.join(buildFolder, "usr"))
# octal
os.chmod(exeFullPath, 0o755)

Expand Down
24 changes: 17 additions & 7 deletions eng/tools/publish-tools/ubuntu/buildDEB.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,26 @@ def returnDebVersion(version):
@helper.restoreDirectory
def preparePackage():
"""
Prepares and builds a Debian package.
This includes setting up directories, copying necessary files,
generating SHA256 hashes, and building the final .deb package.
Prepares and builds a Debian package for each supported architecture.
"""
os.chdir(constants.DRIVERROOTDIR)

debianVersion = returnDebVersion(constants.VERSION)
packageFolder = f"{constants.PACKAGENAME}_{debianVersion}"
buildFolder = os.path.join(os.getcwd(), constants.BUILDFOLDER, packageFolder)
helper.linuxOutput(buildFolder)
print(f"debianVersion: {debianVersion}")

for arch in ["x64", "arm64"]:
print(f"\nBuilding package for linux-{arch}...\n")
preparePackageForArch(arch, debianVersion)

def preparePackageForArch(arch, debianVersion):
"""
Prepares and builds a Debian package.
This includes setting up directories, copying necessary files,
generating SHA256 hashes, and building the final .deb package.
"""
packageFolderName = f"{constants.PACKAGENAME}_{debianVersion}_{arch}"
buildFolder = os.path.join(os.getcwd(), constants.BUILDFOLDER, packageFolderName)
helper.linuxOutput(buildFolder, arch)

os.chdir(buildFolder)
document = os.path.join("usr", "share", "doc", constants.PACKAGENAME)
Expand Down Expand Up @@ -107,5 +117,5 @@ def preparePackage():
# Build the Debian package using dpkg-deb
os.chdir(constants.DRIVERROOTDIR)
output = helper.printReturnOutput(["fakeroot", "dpkg-deb", "--build", "-Zxz",
os.path.join(constants.BUILDFOLDER, packageFolder), os.path.join(constants.ARTIFACTFOLDER, packageFolder+".deb")])
os.path.join(constants.BUILDFOLDER, packageFolderName), os.path.join(constants.ARTIFACTFOLDER, packageFolderName+".deb")])
assert(f"building package '{constants.PACKAGENAME}'" in output)
4 changes: 3 additions & 1 deletion release_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@

- Log the resolved worker runtime and `local.settings.json` location, if found.
- Add `func pack` basic functionality (#4600)
- Add `func pack` basic functionality (#4600)
- Clean up HelpAction and add `func pack` to help menu (#4639)
- Add comprehensive pack validations for all Azure Functions runtimes (#4625)
- Enhanced user experience with real-time validation status (PASSED/FAILED/WARNING)
- Runtime-specific validations for .NET, Python, Node.js, PowerShell, and Custom Handlers
- Actionable error messages to help developers resolve issues during packaging
- Validates folder structure, required files, programming models, and runtime-specific configurations
- Validates folder structure, required files, programming models, and runtime-specific configurations
- Add support for linux-arm64 (#4655)
15 changes: 8 additions & 7 deletions src/ArtifactAssembler/ArtifactAssembler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,16 @@ internal sealed partial class ArtifactAssembler
/// </summary>
private readonly string[] _cliArtifacts =
[
"Azure.Functions.Cli.min.win-arm64",
"Azure.Functions.Cli.min.win-x86",
"Azure.Functions.Cli.min.win-x64",
"Azure.Functions.Cli.linux-x64",
"Azure.Functions.Cli.osx-x64",
"Azure.Functions.Cli.osx-arm64",
"Azure.Functions.Cli.min.win-arm64",
"Azure.Functions.Cli.win-x86",
"Azure.Functions.Cli.win-x64",
"Azure.Functions.Cli.win-arm64"
"Azure.Functions.Cli.win-arm64",
"Azure.Functions.Cli.linux-x64",
"Azure.Functions.Cli.linux-arm64",
"Azure.Functions.Cli.osx-x64",
"Azure.Functions.Cli.osx-arm64"
];

private readonly string _inProcArtifactDirectoryName;
Expand Down Expand Up @@ -338,8 +339,8 @@ private void CreateCliCoreTools()
FileUtilities.CopyDirectory(outOfProcArtifactDirPath, consolidatedArtifactDirPath);
Directory.Delete(outOfProcArtifactDirPath, true);

// If we are currently on the minified version of the artifacts, we do not want the inproc6/inproc8 subfolders
if (artifactName.Contains("min.win"))
// If we are currently on the minified version of the artifacts (or if its linux arm64), we do not want the inproc6/inproc8 subfolders
if (artifactName.Contains("min.win") || artifactName.Contains("linux-arm64"))
{
Console.WriteLine($"Finished assembling {consolidatedArtifactDirPath}\n");
continue;
Expand Down
1 change: 1 addition & 0 deletions src/Cli/func/Actions/HelpAction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ private void DisplayGeneralHelp()
.Where(c => c != Context.None)
.Distinct()
.OrderBy(c => c.ToLowerCaseString());
Utilities.WarnIfPreviewVersion();
Utilities.PrintVersion();
ColoredConsole
.WriteLine("Usage: func [context] <action> [-/--options]")
Expand Down
11 changes: 11 additions & 0 deletions src/Cli/func/Actions/HostActions/StartHostAction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,10 @@ public override async Task RunAsync()
return;
}

Utilities.WarnIfPreviewVersion();

Utilities.PrintSupportInformation();

if (isVerbose || EnvironmentHelper.GetEnvironmentVariableAsBool(Constants.DisplayLogo))
{
Utilities.PrintLogo();
Expand Down Expand Up @@ -483,6 +487,13 @@ public override async Task RunAsync()

private async Task<bool> TryHandleInProcDotNetLaunchAsync()
{
// On ARM64 Linux, we do not support in-proc .NET host. We always launch out-of-process host.
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
{
ColoredConsole.WriteLine(VerboseColor($".NET in-process is not supported on linux-arm64. Selected out-of-proc host."));
return false;
}

// If --runtime param is set, handle runtime param logic; otherwise we infer the host to launch on startup
if (HostRuntime is not null)
{
Expand Down
3 changes: 3 additions & 0 deletions src/Cli/func/Actions/LocalActions/InitAction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,9 @@ public override ICommandLineParserResult ParseArgs(string[] args)

public override async Task RunAsync()
{
Utilities.WarnIfPreviewVersion();
Utilities.PrintSupportInformation();

if (SourceControl != SourceControl.Git)
{
throw new Exception("Only Git is supported right now for vsc");
Expand Down
2 changes: 1 addition & 1 deletion src/Cli/func/Azure.Functions.Cli.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<TargetFramework>net8.0</TargetFramework>
<OutputType>Exe</OutputType>
<AssemblyName>func</AssemblyName>
<RuntimeIdentifiers>win-x64;win-x86;win-arm64;linux-x64;osx-x64;osx-arm64</RuntimeIdentifiers>
<RuntimeIdentifiers>win-x64;win-x86;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64</RuntimeIdentifiers>
<Nullable>disable</Nullable>
<DisableImplicitNamespaceImports>true</DisableImplicitNamespaceImports>
</PropertyGroup>
Expand Down
4 changes: 3 additions & 1 deletion src/Cli/func/Common/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,13 @@ internal static partial class Constants
public const string Dotnet = "dotnet";
public const string InProcDotNet8EnabledSetting = "FUNCTIONS_INPROC_NET8_ENABLED";
public const string AzureDevSessionsRemoteHostName = "AzureDevSessionsRemoteHostName";

// forwardedHttpUrl sample format: https://n12abc3t-<port>.asse.devtunnels.ms/
public const string AzureDevSessionsPortSuffixPlaceholder = "<port>";
public const string GitHubReleaseApiUrl = "https://api.github.com/repos/Azure/azure-functions-core-tools/releases/latest";
public const string PythonScriptFileName = "PYTHON_SCRIPT_FILE_NAME";
public const string PreviewVersionSuffixLabel = "preview";

// Sample format https://n12abc3t-<port>.asse.devtunnels.ms/
public static readonly Dictionary<WorkerRuntime, IEnumerable<string>> WorkerRuntimeImages = new Dictionary<WorkerRuntime, IEnumerable<string>>
{
{ WorkerRuntime.Dotnet, new[] { "mcr.microsoft.com/azure-functions/dotnet", "microsoft/azure-functions-dotnet-core2.0", "mcr.microsoft.com/azure-functions/base", "microsoft/azure-functions-base" } },
Expand Down
1 change: 1 addition & 0 deletions src/Cli/func/Common/DotnetConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ internal static class DotnetConstants
public const string InProcFunctionsSdk = "Microsoft.NET.Sdk.Functions";
public const string InProcFunctionsMinSdkVersion = "4.5.0";
public const string InProcFunctionsDocsLink = "https://aka.ms/functions-core-tools-in-proc-sdk-requirement";
public const string DotnetIsolatedMigrationDocLink = "https://aka.ms/af-dotnet-isolated-migration";

public static readonly string[] ValidRuntimeValues = [InProc8HostRuntime, InProc6HostRuntime, "default"];
}
Expand Down
32 changes: 32 additions & 0 deletions src/Cli/func/Common/Utilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,38 @@ internal static void PrintVersion()
.WriteLine($"Function Runtime Version: {ScriptHost.Version}\n".DarkGray());
}

internal static void WarnIfPreviewVersion()
{
if (!Constants.CliVersion.Contains(Constants.PreviewVersionSuffixLabel, StringComparison.OrdinalIgnoreCase))
{
return;
}

ColoredConsole
.WriteLine("You are running a preview version of Azure Functions Core Tools.".DarkYellow());

ColoredConsole.WriteLine();
}

internal static void PrintSupportInformation()
{
Architecture arch = RuntimeInformation.ProcessArchitecture;

if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && arch == Architecture.Arm64)
{
ColoredConsole
.WriteLine($"Azure Functions Core Tool does not support linux-arm64 with .NET applications using the in-process model. For more information, please visit {DotnetConstants.DotnetIsolatedMigrationDocLink}".DarkYellow());
}

if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && arch == Architecture.Arm64)
{
ColoredConsole
.WriteLine("The Azure Functions Python worker does not support windows-arm64.".DarkYellow());
}

ColoredConsole.WriteLine();
}

private static RichString AlternateLogoColor(string str, int firstColorCount = -1)
{
if (str.Length == 1)
Expand Down
2 changes: 1 addition & 1 deletion src/Cli/func/Directory.Version.props
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project>

<PropertyGroup>
<VersionPrefix>4.2.3</VersionPrefix>
<VersionPrefix>4.3.0</VersionPrefix>
<VersionSuffix></VersionSuffix>
<UpdateBuildNumber>true</UpdateBuildNumber>
</PropertyGroup>
Expand Down
Loading
Loading