This commit is contained in:
Rolf Bjarne Kvinge 2022-10-06 14:01:27 +02:00
Родитель d8b991e0e6 273c2fa51a
Коммит fb97063227
23 изменённых файлов: 517 добавлений и 306 удалений

4
.github/workflows/autoformat2.yml поставляемый
Просмотреть файл

@ -20,7 +20,7 @@ jobs:
uses: actions/github-script@v6.3.1 uses: actions/github-script@v6.3.1
with: with:
script: | script: |
var artifacts = await github.actions.listWorkflowRunArtifacts({ var artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner, owner: context.repo.owner,
repo: context.repo.repo, repo: context.repo.repo,
run_id: ${{github.event.workflow_run.id }}, run_id: ${{github.event.workflow_run.id }},
@ -28,7 +28,7 @@ jobs:
var matchArtifact = artifacts.data.artifacts.filter((artifact) => { var matchArtifact = artifacts.data.artifacts.filter((artifact) => {
return artifact.name == "autoformat" return artifact.name == "autoformat"
})[0]; })[0];
var download = await github.actions.downloadArtifact({ var download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner, owner: context.repo.owner,
repo: context.repo.repo, repo: context.repo.repo,
artifact_id: matchArtifact.id, artifact_id: matchArtifact.id,

28
.github/workflows/update-single-platform-branches.yml поставляемый Normal file
Просмотреть файл

@ -0,0 +1,28 @@
name: Update single-platform release tests branches
on:
# allow triggering this action manually
workflow_dispatch:
# run every saturday (at noon UTC), so the builds occur during the weekend during lower CI load
schedule:
- cron: '0 12 * * 6'
jobs:
updateSinglePlatformBranches:
name: Merge main into single-platform release test branches
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: 'Update branches'
run: |
set -ex
for platform in iOS tvOS MacCatalyst macOS; do
git checkout -b release/release-test-only-dotnet-$platform origin/release/release-test-only-dotnet-$platform
git merge origin/main
git push
done

Просмотреть файл

@ -110,9 +110,11 @@ package release:
$(Q) $(MAKE) -C $(TOP)/release release $(Q) $(MAKE) -C $(TOP)/release release
# copy .pkg, .zip and *updateinfo to the packages directory to be uploaded to storage # copy .pkg, .zip and *updateinfo to the packages directory to be uploaded to storage
$(Q) mkdir -p ../package $(Q) mkdir -p ../package
$(Q) $(CP) $(TOP)/release/*.pkg ../package $(Q) echo "Output from 'make release':"
$(Q) $(CP) $(TOP)/release/*.zip ../package $(Q) ls -la $(TOP)/release | sed 's/^/ /'
$(Q) $(CP) $(TOP)/release/*updateinfo ../package $(Q) if test -n "$$(shopt -s nullglob; echo $(TOP)/release/*.pkg)"; then $(CP) $(TOP)/release/*.pkg ../package; fi
$(Q) if test -n "$$(shopt -s nullglob; echo $(TOP)/release/*.zip)"; then $(CP) $(TOP)/release/*.zip ../package; fi
$(Q) if test -n "$$(shopt -s nullglob; echo $(TOP)/release/*updateinfo)"; then $(CP) $(TOP)/release/*updateinfo ../package; fi
$(Q) echo "Packages:" $(Q) echo "Packages:"
$(Q) ls -la ../package | sed 's/^/ /' $(Q) ls -la ../package | sed 's/^/ /'

Просмотреть файл

@ -10,6 +10,12 @@
<clear /> <clear />
<!--Begin: Package sources managed by Dependency Flow automation. Do not edit the sources below.--> <!--Begin: Package sources managed by Dependency Flow automation. Do not edit the sources below.-->
<!-- Begin: Package sources from dotnet-emsdk --> <!-- Begin: Package sources from dotnet-emsdk -->
<add key="darc-pub-dotnet-emsdk-c3fc739" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/darc-pub-dotnet-emsdk-c3fc739c/nuget/v3/index.json" />
<add key="darc-pub-dotnet-emsdk-c3fc739-5" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/darc-pub-dotnet-emsdk-c3fc739c-5/nuget/v3/index.json" />
<add key="darc-pub-dotnet-emsdk-c3fc739-4" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/darc-pub-dotnet-emsdk-c3fc739c-4/nuget/v3/index.json" />
<add key="darc-pub-dotnet-emsdk-c3fc739-3" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/darc-pub-dotnet-emsdk-c3fc739c-3/nuget/v3/index.json" />
<add key="darc-pub-dotnet-emsdk-c3fc739-2" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/darc-pub-dotnet-emsdk-c3fc739c-2/nuget/v3/index.json" />
<add key="darc-pub-dotnet-emsdk-c3fc739-1" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/darc-pub-dotnet-emsdk-c3fc739c-1/nuget/v3/index.json" />
<!-- End: Package sources from dotnet-emsdk --> <!-- End: Package sources from dotnet-emsdk -->
<!-- Begin: Package sources from dotnet-aspnetcore --> <!-- Begin: Package sources from dotnet-aspnetcore -->
<!-- End: Package sources from dotnet-aspnetcore --> <!-- End: Package sources from dotnet-aspnetcore -->

Просмотреть файл

@ -2726,5 +2726,14 @@ namespace Xamarin.Localization.MSBuild {
return ResourceManager.GetString("W7100", resourceCulture); return ResourceManager.GetString("W7100", resourceCulture);
} }
} }
/// <summary>
/// Looks up a localized string similar to Unexpected extension &apos;{0}&apos; for native reference &apos;{1}&apos; in manifest &apos;{2}&apos;..
/// </summary>
public static string W7105 {
get {
return ResourceManager.GetString("W7105", resourceCulture);
}
}
} }
} }

Просмотреть файл

@ -1450,4 +1450,13 @@
* 'Remove', 'Boolean', 'String', 'StringArray' * 'Remove', 'Boolean', 'String', 'StringArray'
</comment> </comment>
</data> </data>
<data name="W7105" xml:space="preserve">
<value>Unexpected extension '{0}' for native reference '{1}' in manifest '{2}'.</value>
<comment>
{0}: file extension
{1}: path to a file
{2}: path to a file
</comment>
</data>
</root> </root>

Просмотреть файл

@ -167,7 +167,12 @@ namespace Xamarin.MacDev.Tasks {
t = new TaskItem (Path.Combine (resources, name)); t = new TaskItem (Path.Combine (resources, name));
t.SetMetadata ("Kind", "Dynamic"); t.SetMetadata ("Kind", "Dynamic");
break; break;
case ".a": // static library
t = new TaskItem (Path.Combine (resources, name));
t.SetMetadata ("Kind", "Static");
break;
default: default:
Log.LogWarning (MSBStrings.W7105 /* Unexpected extension '{0}' for native reference '{1}' in manifest '{2}'. */, Path.GetExtension (name), name, manifest);
t = r; t = r;
break; break;
} }

Просмотреть файл

@ -37,7 +37,7 @@ using NativeHandle = System.IntPtr;
namespace Foundation { namespace Foundation {
public partial class NSArray { public partial class NSArray : IEnumerable<NSObject> {
// //
// Creates an array with the elements; If the value passed is null, it // Creates an array with the elements; If the value passed is null, it
@ -429,5 +429,28 @@ namespace Foundation {
return null; return null;
} }
} }
public TKey[] ToArray<TKey> () where TKey: class, INativeObject
{
var rv = new TKey [GetCount (Handle)];
for (var i = 0; i < rv.Length; i++)
rv [i] = GetItem<TKey> ((nuint) i);
return rv;
}
public NSObject[] ToArray ()
{
return ToArray<NSObject> ();
}
IEnumerator<NSObject> IEnumerable<NSObject>.GetEnumerator ()
{
return new NSFastEnumerator<NSObject> (this);
}
IEnumerator IEnumerable.GetEnumerator ()
{
return new NSFastEnumerator<NSObject> (this);
}
} }
} }

Просмотреть файл

@ -89,5 +89,10 @@ namespace Foundation {
return GetItem<TKey> ((nuint)idx); return GetItem<TKey> ((nuint)idx);
} }
} }
public new TKey[] ToArray ()
{
return base.ToArray<TKey> ();
}
} }
} }

Просмотреть файл

@ -8,6 +8,7 @@
// //
using System; using System;
using System.Linq;
using Foundation; using Foundation;
using ObjCRuntime; using ObjCRuntime;
using Security; using Security;
@ -123,5 +124,37 @@ namespace MonoTouchFixtures.Foundation {
Assert.That (a.Handle, Is.Not.EqualTo (IntPtr.Zero), "Handle"); Assert.That (a.Handle, Is.Not.EqualTo (IntPtr.Zero), "Handle");
} }
} }
[Test]
public void ToArray ()
{
using (var a = NSArray.FromStrings (new string [1] { "abc" })) {
var arr = a.ToArray ();
Assert.AreEqual (1, arr.Length, "Length");
Assert.AreEqual ("abc", arr [0].ToString (), "Value");
}
}
[Test]
public void ToArray_T ()
{
using (var a = NSArray.FromStrings (new string [1] { "abc" })) {
var arr = a.ToArray<NSString> ();
Assert.AreEqual (1, arr.Length, "Length");
Assert.AreEqual ("abc", arr [0].ToString (), "Value");
}
}
[Test]
public void Enumerator ()
{
using (var a = NSArray.FromStrings (new string [1] { "abc" })) {
foreach (var item in a)
Assert.AreEqual ("abc", item.ToString (), "Value");
var list = a.ToList ();
Assert.AreEqual (1, list.Count (), "Length");
Assert.AreEqual ("abc", list [0].ToString (), "Value");
}
}
} }
} }

Просмотреть файл

@ -93,5 +93,29 @@ namespace MonoTouchFixtures.Foundation {
Assert.AreSame (str3, arr [2], "NSArray indexer"); Assert.AreSame (str3, arr [2], "NSArray indexer");
} }
} }
[Test]
public void ToArray ()
{
using (var a = NSArray<NSString>.FromNSObjects ((NSString) "abc")) {
var arr = a.ToArray ();
NSString element = arr [0];
Assert.AreEqual (1, arr.Length, "Length");
Assert.AreEqual ("abc", arr [0].ToString (), "Value");
Assert.AreEqual ("abc", (string) element, "Value element");
}
}
[Test]
public void ToArray_T ()
{
using (var a = NSArray<NSString>.FromNSObjects ((NSString) "abc")) {
var arr = a.ToArray ();
NSString element = arr [0];
Assert.AreEqual (1, arr.Length, "Length");
Assert.AreEqual ("abc", arr [0].ToString (), "Value");
Assert.AreEqual ("abc", (string) element, "Value element");
}
}
} }
} }

Просмотреть файл

@ -85,7 +85,7 @@ namespace Extrospection {
case "TWAIN": case "TWAIN":
case "Virtualization": case "Virtualization":
case "vmnet": case "vmnet":
// other non-supported frameworks // other non-supported frameworks
case "GSS": // iOS and macOS case "GSS": // iOS and macOS
case "vecLib": // all case "vecLib": // all
return true; return true;

Просмотреть файл

@ -38,7 +38,7 @@ namespace u2ignore {
} }
} }
var header = new string [] { "", $"# Initial result from new rule { id }" }; var header = new string [] { "", $"# Initial result from new rule {id}" };
foreach (var kvp in dict) { foreach (var kvp in dict) {
var framework = kvp.Key; var framework = kvp.Key;
var entries = kvp.Value; var entries = kvp.Value;
@ -47,7 +47,7 @@ namespace u2ignore {
var failure = kvp2.Key; var failure = kvp2.Key;
var platforms = kvp2.Value; var platforms = kvp2.Value;
string[] files; string [] files;
if (platforms.Count == 4) { if (platforms.Count == 4) {
// same failure in all platforms, the result goes into the common file. // same failure in all platforms, the result goes into the common file.
files = new string [] { "common" }; files = new string [] { "common" };
@ -61,7 +61,7 @@ namespace u2ignore {
File.AppendAllLines (path, new string [] { "" }); File.AppendAllLines (path, new string [] { "" });
File.AppendAllLines (path, header); File.AppendAllLines (path, header);
} }
File.AppendAllLines (path, new string [] { failure } ); File.AppendAllLines (path, new string [] { failure });
} }
} }
} }

Просмотреть файл

@ -3,7 +3,7 @@ using System.IO;
using Extrospection; using Extrospection;
class Program { class Program {
static void Main (string[] args) static void Main (string [] args)
{ {
var dir = args.Length == 0 ? "." : args [0]; var dir = args.Length == 0 ? "." : args [0];
foreach (var file in Directory.GetFiles (dir, "*.unclassified")) { foreach (var file in Directory.GetFiles (dir, "*.unclassified")) {

Просмотреть файл

@ -17,7 +17,7 @@ namespace Extrospection {
bool data = false; bool data = false;
// merge the shared and specialized ignore data into a single html page // merge the shared and specialized ignore data into a single html page
List<string> ignore = new List<string> (); List<string> ignore = new List<string> ();
ignore.Add ($"<h1>{framework}</h1>"); ignore.Add ($"<h1>{framework}</h1>");
var filename = Path.Combine (InputDirectory, $"common-{framework}.ignore"); var filename = Path.Combine (InputDirectory, $"common-{framework}.ignore");
if (File.Exists (filename)) { if (File.Exists (filename)) {
data = true; data = true;
@ -56,7 +56,7 @@ namespace Extrospection {
html.Add ($"<html><head><title>{name}</title></head>"); html.Add ($"<html><head><title>{name}</title></head>");
html.Add ($"<body><h1>{name}</h1><xmp>"); html.Add ($"<body><h1>{name}</h1><xmp>");
foreach (var line in File.ReadAllLines (filename)) { foreach (var line in File.ReadAllLines (filename)) {
html.Add (line); html.Add (line);
if ((line.Length > 0) && (line [0] == '!')) if ((line.Length > 0) && (line [0] == '!'))
count++; count++;
} }
@ -70,7 +70,7 @@ namespace Extrospection {
var filename = Path.GetFileNameWithoutExtension (file); var filename = Path.GetFileNameWithoutExtension (file);
var fx = filename.Substring (filename.IndexOf ('-') + 1); var fx = filename.Substring (filename.IndexOf ('-') + 1);
if (!Frameworks.Contains (fx)) if (!Frameworks.Contains (fx))
Frameworks.Add (fx); Frameworks.Add (fx);
} }
public static int Main (string [] args) public static int Main (string [] args)
@ -98,9 +98,9 @@ namespace Extrospection {
log.WriteLine ("<tr>"); log.WriteLine ("<tr>");
log.WriteLine ("<td rowspan='3' bgcolor='lightgrey'>Frameworks</td>"); log.WriteLine ("<td rowspan='3' bgcolor='lightgrey'>Frameworks</td>");
if (full) if (full)
log.WriteLine ($"<td align='center' bgcolor='green' colspan='{Platforms.Length + 1}'>REVIEWED (ignored)</td>"); log.WriteLine ($"<td align='center' bgcolor='green' colspan='{Platforms.Length + 1}'>REVIEWED (ignored)</td>");
log.WriteLine ($"<td align='center' bgcolor='red' colspan='{Platforms.Length}'>FIXME (unclassified)</td>"); log.WriteLine ($"<td align='center' bgcolor='red' colspan='{Platforms.Length}'>FIXME (unclassified)</td>");
log.WriteLine ($"<td align='center' bgcolor='orange' colspan='{Platforms.Length}'>TODO (milestone)</td>"); log.WriteLine ($"<td align='center' bgcolor='orange' colspan='{Platforms.Length}'>TODO (milestone)</td>");
log.WriteLine ("</tr>"); log.WriteLine ("</tr>");
log.WriteLine ("<tr>"); log.WriteLine ("<tr>");

Просмотреть файл

@ -155,7 +155,7 @@ namespace Extrospection {
foreach (var file in Directory.GetFiles (directory, "*.todo")) { foreach (var file in Directory.GetFiles (directory, "*.todo")) {
if (!IsIncluded (file)) if (!IsIncluded (file))
continue; continue;
if (!(File.ReadLines(file).Count() > 0)) { if (!(File.ReadLines (file).Count () > 0)) {
Log ($"?empty-todo? File '{Path.GetFileName (file)}' is empty. Empty todo files should be removed."); Log ($"?empty-todo? File '{Path.GetFileName (file)}' is empty. Empty todo files should be removed.");
} }
} }
@ -178,10 +178,10 @@ namespace Extrospection {
// cache stuff // cache stuff
foreach (var file in Directory.GetFiles (directory, "common-*.ignore")) { foreach (var file in Directory.GetFiles (directory, "common-*.ignore")) {
var path = Path.GetFileName (file); var path = Path.GetFileName (file);
var fx = path.Substring (7, path.Length - 14); var fx = path.Substring (7, path.Length - 14);
var common = new List<string> (File.ReadAllLines (file)); var common = new List<string> (File.ReadAllLines (file));
commons.Add (fx, common); commons.Add (fx, common);
} }
// *.ignore validations // *.ignore validations
@ -226,8 +226,8 @@ namespace Extrospection {
var common = kvp.Value; var common = kvp.Value;
//ExistingCommonEntries (common, $"common-{fx}.ignore"); //ExistingCommonEntries (common, $"common-{fx}.ignore");
List<string> [] raws = new List<string> [Platforms.Count]; List<string> [] raws = new List<string> [Platforms.Count];
for (int i=0; i < raws.Length; i++) { for (int i = 0; i < raws.Length; i++) {
var fname = Path.Combine (directory, $"{Platforms[i]}-{fx}.raw"); var fname = Path.Combine (directory, $"{Platforms [i]}-{fx}.raw");
if (File.Exists (fname)) if (File.Exists (fname))
raws [i] = new List<string> (File.ReadAllLines (fname)); raws [i] = new List<string> (File.ReadAllLines (fname));
else else
@ -305,7 +305,7 @@ namespace Extrospection {
var sanitizedOrSkippedSanity = var sanitizedOrSkippedSanity =
!string.IsNullOrEmpty (Environment.GetEnvironmentVariable ("XTRO_SANITY_SKIP")) !string.IsNullOrEmpty (Environment.GetEnvironmentVariable ("XTRO_SANITY_SKIP"))
|| !string.IsNullOrEmpty (Environment.GetEnvironmentVariable ("AUTO_SANITIZE")); || !string.IsNullOrEmpty (Environment.GetEnvironmentVariable ("AUTO_SANITIZE"));
return sanitizedOrSkippedSanity ? 0 : count; return sanitizedOrSkippedSanity ? 0 : count;
} }
} }
} }

Просмотреть файл

@ -17,6 +17,11 @@ dotnet format whitespace "$SRC_DIR/msbuild/Xamarin.MacDev.Tasks/Xamarin.MacDev.T
dotnet format whitespace "$SRC_DIR/msbuild/Xamarin.iOS.Tasks.Windows/Xamarin.iOS.Tasks.Windows.csproj" dotnet format whitespace "$SRC_DIR/msbuild/Xamarin.iOS.Tasks.Windows/Xamarin.iOS.Tasks.Windows.csproj"
dotnet format whitespace "$SRC_DIR/msbuild/Xamarin.iOS.Tasks/Xamarin.iOS.Tasks.csproj" dotnet format whitespace "$SRC_DIR/msbuild/Xamarin.iOS.Tasks/Xamarin.iOS.Tasks.csproj"
dotnet format whitespace "$SRC_DIR/tools/dotnet-linker/dotnet-linker.csproj" dotnet format whitespace "$SRC_DIR/tools/dotnet-linker/dotnet-linker.csproj"
dotnet format whitespace "$SRC_DIR/tests/xtro-sharpie/xtro-sharpie.csproj"
dotnet format whitespace "$SRC_DIR/tests/xtro-sharpie/u2ignore/u2ignore.csproj"
dotnet format whitespace "$SRC_DIR/tests/xtro-sharpie/u2todo/u2todo.csproj"
dotnet format whitespace "$SRC_DIR/tests/xtro-sharpie/xtro-report/xtro-report.csproj"
dotnet format whitespace "$SRC_DIR/tests/xtro-sharpie/xtro-sanity/xtro-sanity.csproj"
# dotnet format "$SRC_DIR/[...]" # dotnet format "$SRC_DIR/[...]"
# add more projects here... # add more projects here...

Просмотреть файл

@ -92,6 +92,59 @@ parameters:
type: stepList type: stepList
default: [] default: []
- name: packages
type: object
default: [
{
job: prepare_packages,
displayName: 'Prepare packages',
packages: [
{
job: 'microsoft_ios_sign_notarize',
name: 'Microsoft.iOS',
pattern: 'Microsoft.iOS.Bundle*.pkg',
conditionVariable: "INCLUDE_DOTNET_IOS",
},
{
job: 'microsoft_tvos_sign_notarize',
name: 'Microsoft.tvOS',
pattern: 'Microsoft.tvOS.Bundle*.pkg',
conditionVariable: "INCLUDE_DOTNET_TVOS",
},
{
job: 'microsoft_mac_sign_notarize',
name: 'Microsoft.macOS',
pattern: 'Microsoft.macOS.Bundle*.pkg',
conditionVariable: "INCLUDE_DOTNET_MACOS",
},
{
job: 'microsoft_maccatalyst_sign_notarize',
name: 'Microsoft.MacCatalyst',
pattern: 'Microsoft.MacCatalyst.Bundle*.pkg',
conditionVariable: "INCLUDE_DOTNET_MACCATALYST",
},
],
},
{
job: prepare_packages_legacy,
displayName: 'Prepare legacy packages',
packages: [
{
job: 'xamarin_ios_sign_notarize',
name: 'Xamarin.iOS',
pattern: 'xamarin.ios-*',
conditionVariable: "INCLUDE_LEGACY_IOS",
},
{
job: 'xamarin_mac_sing_notarie',
name: 'Xamarin.Mac',
pattern: 'xamarin.mac-*',
conditionVariable: "INCLUDE_LEGACY_MAC",
},
],
}
]
stages: stages:
- ${{ if eq(parameters.runGovernanceTests, true) }}: - ${{ if eq(parameters.runGovernanceTests, true) }}:
@ -150,18 +203,56 @@ stages:
skipESRP: ${{ parameters.skipESRP }} skipESRP: ${{ parameters.skipESRP }}
pool: ${{ parameters.pool }} pool: ${{ parameters.pool }}
- stage: prepare_packages - ${{ each pkg_obj in parameters.packages }}:
displayName: 'Prepare packages' - stage: ${{ pkg_obj.job }}
displayName: ${{ pkg_obj.displayName }}
dependsOn:
- build_packages
jobs:
- template: ./sign-and-notarized/prepare-pkg-stage.yml
parameters:
isPR: ${{ parameters.isPR }}
signingSetupSteps: ${{ parameters.signingSetupSteps }}
keyringPass: $(pass--lab--mac--builder--keychain)
enableDotnet: ${{ parameters.enableDotnet }}
skipESRP: ${{ parameters.skipESRP }}
packages: ${{ pkg_obj.packages }}
- ${{ if eq(parameters.enableDotnet, true) }}:
- stage: sign_notarize_dotnet
displayName: 'Sign & Notarize Dotnet'
dependsOn:
- build_packages
jobs:
- template: ./sign-and-notarized/dotnet-signing.yml
parameters:
isPR: ${{ parameters.isPR }}
# .NET Release Prep and VS Insertion Stages, only execute them when the build comes from an official branch and is not a schedule build from OneLoc
# setting the stage at this level makes the graph of the UI look better, else the lines overlap and is not clear.
- ${{ if and(ne(variables['Build.Reason'], 'Schedule'), or(eq(variables['Build.SourceBranch'], 'refs/heads/main'), startsWith(variables['Build.SourceBranch'], 'refs/heads/release/'), eq(variables['Build.SourceBranch'], 'refs/heads/net7.0'), eq(parameters.forceInsertion, true))) }}:
- template: ./release/vs-insertion-prep.yml
parameters:
dependsOn:
- sign_notarize_dotnet
isPR: ${{ parameters.isPR }}
- stage: funnel
displayName: 'Collect signed artifacts'
dependsOn: dependsOn:
- build_packages - build_packages
- ${{ if eq(parameters.enableDotnet, true) }}:
- sign_notarize_dotnet
- ${{ each pkg_obj in parameters.packages }}:
- ${{ pkg_obj.job }}
jobs: jobs:
- template: ./sign-and-notarized/prepare-pkg-stage.yml - template: ./sign-and-notarized/funnel.yml
parameters: parameters:
isPR: ${{ parameters.isPR }} isPR: ${{ parameters.isPR }}
signingSetupSteps: ${{ parameters.signingSetupSteps }} packages: # flatten the pkgs for the parameter
keyringPass: $(pass--lab--mac--builder--keychain) - ${{ each pkg_obj in parameters.packages }}:
enableDotnet: ${{ parameters.enableDotnet }} - ${{ each pkg in pkg_obj.packages }}:
skipESRP: ${{ parameters.skipESRP }} - ${{ pkg }}
- ${{ if eq(parameters.enableAPIDiff, true) }}: - ${{ if eq(parameters.enableAPIDiff, true) }}:
- stage: generate_api_diff - stage: generate_api_diff
@ -179,12 +270,6 @@ stages:
enableDotnet: ${{ parameters.enableDotnet }} enableDotnet: ${{ parameters.enableDotnet }}
pool: ${{ parameters.pool }} pool: ${{ parameters.pool }}
# .NET Release Prep and VS Insertion Stages, only execute them when the build comes from an official branch and is not a schedule build from OneLoc
- ${{ if and(ne(variables['Build.Reason'], 'Schedule'), or(eq(variables['Build.SourceBranch'], 'refs/heads/main'), startsWith(variables['Build.SourceBranch'], 'refs/heads/release/'), eq(variables['Build.SourceBranch'], 'refs/heads/net7.0'), eq(parameters.forceInsertion, true))) }}:
- template: ./release/vs-insertion-prep.yml
parameters:
isPR: ${{ parameters.isPR }}
# Test stages # Test stages
# always run simulator tests # always run simulator tests

Просмотреть файл

@ -4,8 +4,8 @@ parameters:
default: true default: true
- name: dependsOn - name: dependsOn
type: string type: object
default: prepare_packages default: []
- name: isPR - name: isPR
type: boolean type: boolean
@ -14,13 +14,13 @@ stages:
- stage: prepare_release - stage: prepare_release
displayName: Prepare Release displayName: Prepare Release
dependsOn: ${{ parameters.dependsOn }} dependsOn: ${{ parameters.dependsOn }}
condition: and(or(eq(dependencies.${{ parameters.dependsOn }}.result, 'Succeeded'), eq(dependencies.${{ parameters.dependsOn }}.result, 'SucceededWithIssues')), eq(${{ parameters.isPR }}, false), eq(${{ parameters.enableDotnet }}, true)) condition: and(eq(${{ parameters.isPR }}, false), eq(${{ parameters.enableDotnet }}, true))
jobs: jobs:
# Check - "xamarin-macios (Prepare Release Sign NuGets)" # Check - "xamarin-macios (Prepare Release Sign NuGets)"
- template: sign-artifacts/jobs/v2.yml@templates - template: sign-artifacts/jobs/v2.yml@templates
parameters: parameters:
artifactName: package artifactName: dotnet-signed
signType: Real signType: Real
usePipelineArtifactTasks: true usePipelineArtifactTasks: true
@ -30,7 +30,7 @@ stages:
yamlResourceName: templates yamlResourceName: templates
dependsOn: signing dependsOn: signing
artifactName: nuget-signed artifactName: nuget-signed
propsArtifactName: package propsArtifactName: dotnet-signed
signType: Real signType: Real
useDateTimeVersion: true useDateTimeVersion: true

Просмотреть файл

@ -7,35 +7,93 @@ parameters:
- name: isPR - name: isPR
type: boolean type: boolean
steps: jobs:
- job: configure
displayName: 'Configure build'
pool:
vmImage: windows-latest
- template: setup.yml steps:
parameters: - template: ../common/configure.yml
isPR: ${{ parameters.isPR }}
- task: DownloadPipelineArtifact@2 - job: sign_notarize_dotnet
displayName: Download not notaraized build dependsOn:
inputs: - configure
artifact: 'not-signed-package' displayName: 'Sign & Notarize Dotnet'
patterns: '!*.pkg' timeoutInMinutes: 1000
allowFailedBuilds: true pool:
path: $(Build.SourcesDirectory)/package vmImage: internal-macos-11
workspace:
clean: all
- ${{ if eq(parameters.isPR, false) }}: steps:
- pwsh : |
# Get the list of files to sign
$msiFiles = Get-ChildItem -Path $(Build.SourcesDirectory)/package/ -Filter "*.msi"
# Add those files to an array - template: setup.yml
$SignFiles = @() parameters:
foreach($msi in $msiFiles) { isPR: ${{ parameters.isPR }}
Write-Host "$($msi.FullName)"
$SignFiles += @{ "SrcPath"="$($msi.FullName)"} - task: DownloadPipelineArtifact@2
displayName: Download not notaraized build
inputs:
artifact: 'not-signed-package'
patterns: '!*.pkg'
allowFailedBuilds: true
path: $(Build.SourcesDirectory)/package
- ${{ if eq(parameters.isPR, false) }}:
- pwsh : |
# Get the list of files to sign
$msiFiles = Get-ChildItem -Path $(Build.SourcesDirectory)/package/ -Filter "*.msi"
# Add those files to an array
$SignFiles = @()
foreach($msi in $msiFiles) {
Write-Host "$($msi.FullName)"
$SignFiles += @{ "SrcPath"="$($msi.FullName)"}
}
Write-Host "$msiFiles"
# array of dicts
$SignFileRecord = @(
@{
"Certs" = "400";
"SignFileList" = $SignFiles;
}
)
$SignFileList = @{
"SignFileRecordList" = $SignFileRecord
}
# Write the json to a file
ConvertTo-Json -InputObject $SignFileList -Depth 5 | Out-File -FilePath $(Build.ArtifactStagingDirectory)/MsiFiles2Notarize.json -Force
dotnet $Env:MBSIGN_APPFOLDER/ddsignfiles.dll /filelist:$(Build.ArtifactStagingDirectory)/MsiFiles2Notarize.json
displayName: 'Sign .msi'
condition: ${{ parameters.condition }}
- pwsh: |
mv $(Build.SourcesDirectory)/package/bundle.zip $(Build.ArtifactStagingDirectory)/not-signed-bundle.zip
$bundlePath = "$(Build.ArtifactStagingDirectory)/bundle"
unzip $(Build.ArtifactStagingDirectory)/not-signed-bundle.zip -d $bundlePath
$patterns = @(
"*.iOS.dll",
"*.tvOS.dll",
"*.Mac.dll", "*.macOS.dll", "*XamMac.dll",
"*.MacCatalyst.dll",
"*.WatchOS.dll"
)
$files = @()
foreach ($p in $patterns) {
$files += Get-ChildItem -Path $bundlePath -Recurse -Filter $p
} }
Write-Host "$msiFiles" $SignFiles = @()
foreach($f in $files) {
Write-Host "$($f.FullName)"
$SignFiles += @{ "SrcPath"="$($f.FullName)"}
}
# array of dicts
$SignFileRecord = @( $SignFileRecord = @(
@{ @{
"Certs" = "400"; "Certs" = "400";
@ -48,61 +106,22 @@ steps:
} }
# Write the json to a file # Write the json to a file
ConvertTo-Json -InputObject $SignFileList -Depth 5 | Out-File -FilePath $(Build.ArtifactStagingDirectory)/MsiFiles2Notarize.json -Force ConvertTo-Json -InputObject $SignFileList -Depth 100 | Out-File -FilePath $(Build.ArtifactStagingDirectory)/bundle.json -Force
dotnet $Env:MBSIGN_APPFOLDER/ddsignfiles.dll /filelist:$(Build.ArtifactStagingDirectory)/MsiFiles2Notarize.json dotnet $Env:MBSIGN_APPFOLDER/ddsignfiles.dll /filelist:$(Build.ArtifactStagingDirectory)/bundle.json
displayName: 'Sign .msi' # rezip and move back
condition: ${{ parameters.condition }} ditto -c -k --sequesterRsrc $bundlePath bundle.zip
mv bundle.zip $(Build.SourcesDirectory)/package/bundle.zip
displayName: 'Sign bundle.zip'
workingDirectory: $(Build.ArtifactStagingDirectory)
- pwsh: | - template: publish-nugets.yml
mv $(Build.SourcesDirectory)/package/bundle.zip $(Build.ArtifactStagingDirectory)/not-signed-bundle.zip parameters:
$bundlePath = "$(Build.ArtifactStagingDirectory)/bundle" isPR: ${{ parameters.isPR }}
unzip $(Build.ArtifactStagingDirectory)/not-signed-bundle.zip -d $bundlePath
$patterns = @(
"*.iOS.dll",
"*.tvOS.dll",
"*.Mac.dll", "*.macOS.dll", "*XamMac.dll",
"*.MacCatalyst.dll",
"*.WatchOS.dll"
)
$files = @()
foreach ($p in $patterns) {
$files += Get-ChildItem -Path $bundlePath -Recurse -Filter $p
}
$SignFiles = @() # always upload no matter what, since if we are not signing we need the artifact in the pipeline
foreach($f in $files) { - task: PublishPipelineArtifact@1
Write-Host "$($f.FullName)" displayName: 'Publish Notarized Dotnet Artifacts'
$SignFiles += @{ "SrcPath"="$($f.FullName)"} inputs:
} targetPath: $(Build.SourcesDirectory)/package
artifactName: dotnet-signed
$SignFileRecord = @( continueOnError: true
@{
"Certs" = "400";
"SignFileList" = $SignFiles;
}
)
$SignFileList = @{
"SignFileRecordList" = $SignFileRecord
}
# Write the json to a file
ConvertTo-Json -InputObject $SignFileList -Depth 100 | Out-File -FilePath $(Build.ArtifactStagingDirectory)/bundle.json -Force
dotnet $Env:MBSIGN_APPFOLDER/ddsignfiles.dll /filelist:$(Build.ArtifactStagingDirectory)/bundle.json
# rezip and move back
ditto -c -k --sequesterRsrc $bundlePath bundle.zip
mv bundle.zip $(Build.SourcesDirectory)/package/bundle.zip
displayName: 'Sign bundle.zip'
workingDirectory: $(Build.ArtifactStagingDirectory)
- template: publish-nugets.yml
parameters:
isPR: ${{ parameters.isPR }}
# always upload no matter what, since if we are not signing we need the artifact in the pipeline
- task: PublishPipelineArtifact@1
displayName: 'Publish Notarized Dotnet Artifacts'
inputs:
targetPath: $(Build.SourcesDirectory)/package
artifactName: dotnet-signed
continueOnError: true

Просмотреть файл

@ -3,78 +3,160 @@ parameters:
- name: packages - name: packages
type: object type: object
steps: - name: enableDotnet
type: boolean
default: true
# DO NOT USE THE checkout.yml template. The reason is that the template changes the hash which results in a problem with the artifacts scripts - name: isPR
- checkout: self # https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=azure-devops&tabs=schema#checkout type: boolean
clean: true # Executes: git clean -ffdx && git reset --hard HEAD
submodules: recursive
path: s/xamarin-macios
- checkout: maccore
clean: true
persistCredentials: true # hugely important, else there are some scripts that check a single file from maccore that will fail
- checkout: templates jobs:
clean: true - job: configure
displayName: 'Configure build'
pool:
vmImage: windows-latest
- checkout: release-scripts variables:
clean: true isMain: $[eq(variables['Build.SourceBranch'], 'refs/heads/main')]
isScheduled: $[eq(variables['Build.Reason'], 'Schedule')]
- bash: | steps:
mkdir -p $(Build.SourcesDirectory)/package/notarized - template: ../common/configure.yml
displayName: 'Create target directories.'
- task: DownloadPipelineArtifact@2 - job: funnel_job
displayName: Download notarized build dotnet dependsOn:
inputs: - configure
artifact: 'dotnet-signed' displayName: 'Collect signed artifacts'
allowFailedBuilds: true condition: and(not(failed()), not(canceled())) # default is succeded(), but that fails if there are any skipped jobs, so change the condition to !failed && !cancelled
path: $(Build.SourcesDirectory)/package timeoutInMinutes: 1000
pool:
vmImage: internal-macos-11
workspace:
clean: all
variables:
${{ each pkg in parameters.packages }}:
${{ pkg.conditionVariable }}: $[ dependencies.configure.outputs['configure_platforms.${{ pkg.conditionVariable }}'] ]
- ${{ each pkg in parameters.packages }}: steps:
- task: DownloadPipelineArtifact@2
displayName: Download notarized build ${{ pkg.name }} # DO NOT USE THE checkout.yml template. The reason is that the template changes the hash which results in a problem with the artifacts scripts
condition: ne('', variables['${{ pkg.conditionVariable }}']) - checkout: self # https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=azure-devops&tabs=schema#checkout
inputs: clean: true # Executes: git clean -ffdx && git reset --hard HEAD
artifact: 'classic-${{ pkg.name }}-signed' submodules: recursive
allowFailedBuilds: true path: s/xamarin-macios
path: '$(Build.ArtifactStagingDirectory)/classic-${{ pkg.name }}-signed'
- checkout: maccore
clean: true
persistCredentials: true # hugely important, else there are some scripts that check a single file from maccore that will fail
- checkout: templates
clean: true
- checkout: release-scripts
clean: true
- bash: | - bash: |
set -x mkdir -p $(Build.SourcesDirectory)/package/notarized
set -e displayName: 'Create target directories.'
FULL_PATH="$(Build.ArtifactStagingDirectory)/classic-${{ pkg.name }}-signed" - task: DownloadPipelineArtifact@2
ls -lR $FULL_PATH displayName: Download notarized build dotnet
cp -a "$FULL_PATH/." "$(Build.SourcesDirectory)/package" inputs:
displayName: 'Move pkg ${{ pkg.name }} to its final destination' artifact: 'dotnet-signed'
condition: ne('', variables['${{ pkg.conditionVariable }}']) allowFailedBuilds: true
path: $(Build.SourcesDirectory)/package
- template: generate-workspace-info.yml@templates - ${{ each pkg in parameters.packages }}:
parameters: - task: DownloadPipelineArtifact@2
GitHubToken: $(GitHub.Token) displayName: Download notarized build ${{ pkg.name }}
ArtifactDirectory: $(Build.SourcesDirectory)/package-internal condition: ne('', variables['${{ pkg.conditionVariable }}'])
inputs:
artifact: 'classic-${{ pkg.name }}-signed'
allowFailedBuilds: true
path: '$(Build.ArtifactStagingDirectory)/classic-${{ pkg.name }}-signed'
# download workload json and add it to out package internal dir, this allows the rest of jobs - bash: |
# not to need several artifacts but just package-internal set -x
- task: DownloadPipelineArtifact@2 set -e
displayName: Download WorkloadRollback.json
inputs:
patterns: '**/WorkloadRollback.json'
allowFailedBuilds: true
path: $(Build.SourcesDirectory)/package-internal
- task: PublishPipelineArtifact@1 FULL_PATH="$(Build.ArtifactStagingDirectory)/classic-${{ pkg.name }}-signed"
displayName: 'Publish Build Internal Artifacts' ls -lR $FULL_PATH
inputs: cp -a "$FULL_PATH/." "$(Build.SourcesDirectory)/package"
targetPath: $(Build.SourcesDirectory)/package-internal displayName: 'Move pkg ${{ pkg.name }} to its final destination'
artifactName: package-internal condition: ne('', variables['${{ pkg.conditionVariable }}'])
continueOnError: true
- task: PublishPipelineArtifact@1 - template: generate-workspace-info.yml@templates
displayName: 'Publish Build Artifacts (notarized)' parameters:
inputs: GitHubToken: $(GitHub.Token)
targetPath: $(Build.SourcesDirectory)/package ArtifactDirectory: $(Build.SourcesDirectory)/package-internal
artifactName: package
continueOnError: true # download workload json and add it to out package internal dir, this allows the rest of jobs
# not to need several artifacts but just package-internal
- task: DownloadPipelineArtifact@2
displayName: Download WorkloadRollback.json
inputs:
patterns: '**/WorkloadRollback.json'
allowFailedBuilds: true
path: $(Build.SourcesDirectory)/package-internal
- task: PublishPipelineArtifact@1
displayName: 'Publish Build Internal Artifacts'
inputs:
targetPath: $(Build.SourcesDirectory)/package-internal
artifactName: package-internal
continueOnError: true
- task: PublishPipelineArtifact@1
displayName: 'Publish Build Artifacts (notarized)'
inputs:
targetPath: $(Build.SourcesDirectory)/package
artifactName: package
continueOnError: true
# This job uploads the pkgs generated by the build step in the azure blob storage. This has to be done in a different job
# because the azure blob storate tools DO NOT work on mac OS meaning that we need a bot running Windows. build uploads the contents
# to the pipeline artefacts and we download and upload to azure in this job.
- job: upload_azure_blob
displayName: 'Upload packages to Azure & SBOM'
timeoutInMinutes: 1000
dependsOn:
- funnel_job
condition: and(not(failed()), not(canceled())) # default is succeded(), but that fails if there are any skipped jobs, so change the condition to !failed && !cancelled
variables:
Parameters.outputStorageUri: ''
NUGETS_PUBLISHED: $[ stageDependencies.sign_notarize_dotnet.sign_notarize_dotnet.outputs['nugetPublishing.NUGETS_PUBLISHED'] ] # not a typo, stage and job have the same name
SKIP_NUGETS: $[ dependencies.configure.outputs['labels.skip-nugets'] ]
pool:
vmImage: 'windows-latest'
workspace:
clean: all
steps:
- template: upload-azure.yml
parameters:
enableDotnet: ${{ parameters.enableDotnet }}
sbomFilter: '*.nupkg;*.pkg;*.msi'
# Job that runs on a vm that downloads the artifacts information and adds a github comment pointing to the results of the build.
- job: artifacts_github_comment
displayName: 'Publish GitHub Comment - Artifacts'
timeoutInMinutes: 1000
dependsOn:
- configure
- upload_azure_blob
condition: succeededOrFailed()
variables:
PR_ID: $[ dependencies.configure.outputs['labels.pr-number'] ]
BUILD_PACKAGE: $[ dependencies.configure.outputs['labels.build-package'] ]
TESTS_BOT: $[ stageDependencies.build_packages.build.outputs['build.TESTS_BOT'] ] # we build in a diff bot than the ones used for the comments
GIT_HASH: $[ stageDependencies.build_packages.build.outputs['fix_commit.GIT_HASH'] ]
pool:
vmImage: 'windows-latest'
workspace:
clean: all
steps:
- template: artifact-github-comment.yml
parameters:
isPR: ${{ parameters.isPR }}

Просмотреть файл

@ -20,44 +20,7 @@ parameters:
- name: packages - name: packages
type: object type: object
default: [ default: []
{
job: 'xamarin_ios_sign_notarize',
name: 'Xamarin.iOS',
pattern: 'xamarin.ios-*',
conditionVariable: "INCLUDE_LEGACY_IOS",
},
{
job: 'xamarin_mac_sing_notarie',
name: 'Xamarin.Mac',
pattern: 'xamarin.mac-*',
conditionVariable: "INCLUDE_LEGACY_MAC",
},
{
job: 'microsoft_ios_sign_notarize',
name: 'Microsoft.iOS',
pattern: 'Microsoft.iOS.Bundle*.pkg',
conditionVariable: "INCLUDE_DOTNET_IOS",
},
{
job: 'microsoft_tvos_sign_notarize',
name: 'Microsoft.tvOS',
pattern: 'Microsoft.tvOS.Bundle*.pkg',
conditionVariable: "INCLUDE_DOTNET_TVOS",
},
{
job: 'microsoft_mac_sign_notarize',
name: 'Microsoft.macOS',
pattern: 'Microsoft.macOS.Bundle*.pkg',
conditionVariable: "INCLUDE_DOTNET_MACOS",
},
{
job: 'microsoft_maccatalyst_sign_notarize',
name: 'Microsoft.MacCatalyst',
pattern: 'Microsoft.MacCatalyst.Bundle*.pkg',
conditionVariable: "INCLUDE_DOTNET_MACCATALYST",
},
]
jobs: jobs:
- job: configure - job: configure
@ -93,90 +56,3 @@ jobs:
skipESRP: ${{ parameters.skipESRP }} skipESRP: ${{ parameters.skipESRP }}
packageName: ${{ pkg.name }} packageName: ${{ pkg.name }}
packagePattern: ${{ pkg.pattern }} packagePattern: ${{ pkg.pattern }}
- ${{ if eq(parameters.enableDotnet, true) }}:
- job: sign_notarize_dotnet
dependsOn:
- configure
displayName: 'Sign & Notarize Dotnet'
timeoutInMinutes: 1000
pool:
vmImage: internal-macos-11
workspace:
clean: all
steps:
- template: dotnet-signing.yml
parameters:
isPR: ${{ parameters.isPR }}
- job: funnel_job
dependsOn:
- configure
- ${{ if eq(parameters.enableDotnet, true) }}:
- sign_notarize_dotnet
- ${{ each pkg in parameters.packages }}:
- ${{ pkg.job }}
displayName: 'Collect signed artifacts'
condition: and(not(failed()), not(canceled())) # default is succeded(), but that fails if there are any skipped jobs, so change the condition to !failed && !cancelled
timeoutInMinutes: 1000
pool:
vmImage: internal-macos-11
workspace:
clean: all
variables:
${{ each pkg in parameters.packages }}:
${{ pkg.conditionVariable }}: $[ dependencies.configure.outputs['configure_platforms.${{ pkg.conditionVariable }}'] ]
steps:
- template: funnel.yml
parameters:
packages: ${{ parameters.packages }}
# This job uploads the pkgs generated by the build step in the azure blob storage. This has to be done in a different job
# because the azure blob storate tools DO NOT work on mac OS meaning that we need a bot running Windows. build uploads the contents
# to the pipeline artefacts and we download and upload to azure in this job.
- job: upload_azure_blob
displayName: 'Upload packages to Azure & SBOM'
timeoutInMinutes: 1000
dependsOn:
- funnel_job
condition: and(not(failed()), not(canceled())) # default is succeded(), but that fails if there are any skipped jobs, so change the condition to !failed && !cancelled
variables:
Parameters.outputStorageUri: ''
NUGETS_PUBLISHED: $[ dependencies.sign_notarize.outputs['nugetPublishing.NUGETS_PUBLISHED'] ]
SKIP_NUGETS: $[ dependencies.configure.outputs['labels.skip-nugets'] ]
pool:
vmImage: 'windows-latest'
workspace:
clean: all
steps:
- template: upload-azure.yml
parameters:
enableDotnet: ${{ parameters.enableDotnet }}
sbomFilter: '*.nupkg;*.pkg;*.msi'
# Job that runs on a vm that downloads the artifacts information and adds a github comment pointing to the results of the build.
- job: artifacts_github_comment
displayName: 'Publish GitHub Comment - Artifacts'
timeoutInMinutes: 1000
dependsOn:
- configure
- upload_azure_blob
condition: succeededOrFailed()
variables:
PR_ID: $[ dependencies.configure.outputs['labels.pr-number'] ]
BUILD_PACKAGE: $[ dependencies.configure.outputs['labels.build-package'] ]
TESTS_BOT: $[ stageDependencies.build_packages.build.outputs['build.TESTS_BOT'] ] # we build in a diff bot than the ones used for the comments
GIT_HASH: $[ stageDependencies.build_packages.build.outputs['fix_commit.GIT_HASH'] ]
pool:
vmImage: 'windows-latest'
workspace:
clean: all
steps:
- template: artifact-github-comment.yml
parameters:
isPR: ${{ parameters.isPR }}

Просмотреть файл

@ -32,7 +32,7 @@ steps:
- ${{ each step in parameters.signingSetupSteps }}: - ${{ each step in parameters.signingSetupSteps }}:
- ${{ each pair in step }}: - ${{ each pair in step }}:
${{ pair.key }}: ${{ pair.value }} ${{ pair.key }}: ${{ pair.value }}
- task: DownloadPipelineArtifact@2 - task: DownloadPipelineArtifact@2
displayName: Download not notarized build displayName: Download not notarized build