");
sb.AppendLine("
");
sb.AppendLine($"
Scope: {HtmlEncode(scopeLabel ?? scopeValue)}
");
- sb.AppendLine($"
New/updated activities: {activities.Count} since {since:yyyy-MM-dd HH:mm} UTC
");
+ sb.AppendLine($"
New activities: {activities.Count} since {since:yyyy-MM-dd HH:mm} UTC
");
sb.AppendLine(activityTypes != null && activityTypes.Count > 0
? $"
Activity types: {HtmlEncode(string.Join(", ", activityTypes))}
"
: "
Activity types: All
");
@@ -1157,7 +1155,7 @@ private static string BuildEmailBody(string userName, string scopeType, string s
sb.AppendLine("
");
sb.AppendLine("
");
sb.AppendLine($"{HtmlEncode(typeLabel)}");
- sb.AppendLine($"{GetActivityTimeLabel(item)}");
+ sb.AppendLine($"{item.CreatedOn:yyyy-MM-dd HH:mm} UTC");
sb.AppendLine("
");
sb.AppendLine($"
{HtmlEncode(item.Subject ?? "(No subject)")}
");
sb.AppendLine($"
Regarding: {HtmlEncode(item.Regarding)}
");
@@ -1176,7 +1174,7 @@ private static string BuildEmailBody(string userName, string scopeType, string s
sb.AppendLine("
");
}
- sb.AppendLine("
You only receive entries created or updated since your previous digest for this subscription.
");
+ sb.AppendLine("
You only receive entries newer than your previous digest for this subscription.
");
sb.AppendLine("
");
sb.AppendLine("
");
sb.AppendLine("You are receiving this because you subscribed to activity notifications in Dynamics Activities.
");
@@ -1398,29 +1396,6 @@ private static string GetTypeBadgeLabel(ActivityItem item)
}
}
- private static DateTime GetActivityTimestamp(ActivityItem item)
- {
- if (item == null) return DateTime.MinValue;
- if (item.ModifiedOn > DateTime.MinValue && item.ModifiedOn > item.CreatedOn) return item.ModifiedOn;
- return item.CreatedOn;
- }
-
- private static string GetActivityTimeLabel(ActivityItem item)
- {
- var timestamp = GetActivityTimestamp(item);
- if (timestamp <= DateTime.MinValue)
- {
- return String.Empty;
- }
-
- if (item?.ModifiedOn > DateTime.MinValue && item.ModifiedOn > item.CreatedOn)
- {
- return $"Updated {timestamp:yyyy-MM-dd HH:mm} UTC";
- }
-
- return $"{timestamp:yyyy-MM-dd HH:mm} UTC";
- }
-
private static string GetDynamicsUrl(string entityType, string activityId)
{
var etn = "activitypointer";
@@ -1463,7 +1438,6 @@ private sealed class ActivityItem
public string RegardingId { get; set; }
public string Regarding { get; set; }
public DateTime CreatedOn { get; set; }
- public DateTime ModifiedOn { get; set; }
}
private sealed class ScopeContext
diff --git a/DynamicsActivitiesPackage/DynamicsActivities_Summarize/DynamicsActivities_Summarize.cs b/DynamicsActivitiesPackage/DynamicsActivities_Summarize/DynamicsActivities_Summarize.cs
index 5f20587..b87759a 100644
--- a/DynamicsActivitiesPackage/DynamicsActivities_Summarize/DynamicsActivities_Summarize.cs
+++ b/DynamicsActivitiesPackage/DynamicsActivities_Summarize/DynamicsActivities_Summarize.cs
@@ -145,11 +145,11 @@ private static string BuildPrompt(SummaryRequest request)
foreach (var activity in request.Activities.Take(50))
{
var type = SafeValue(activity.Type);
- var changedOn = SafeValue(GetActivityTimelineTimestampUtc(activity));
+ var createdOn = SafeValue(activity.CreatedOnUtc);
var regarding = SafeValue(activity.Regarding);
var subject = SafeValue(activity.Subject);
var description = TrimValue(SafeValue(activity.Description), 260);
- lines.Add("- [" + changedOn + "] " + type + " | Regarding: " + regarding + " | Subject: " + subject + " | Note: " + description);
+ lines.Add("- [" + createdOn + "] " + type + " | Regarding: " + regarding + " | Subject: " + subject + " | Note: " + description);
}
return String.Join(Environment.NewLine, lines);
@@ -309,8 +309,6 @@ private static SummaryRequest ParseSummaryRequest(string payload)
request.Activities.Add(new ActivityInput
{
CreatedOnUtc = item["createdOnUtc"]?.Value(),
- ModifiedOnUtc = item["modifiedOnUtc"]?.Value(),
- ChangedOnUtc = item["changedOnUtc"]?.Value(),
Type = item["type"]?.Value(),
Subject = item["subject"]?.Value(),
Regarding = item["regarding"]?.Value(),
@@ -318,10 +316,6 @@ private static SummaryRequest ParseSummaryRequest(string payload)
});
}
- request.Activities = request.Activities
- .OrderByDescending(GetActivityTimelineTimestampSortKey)
- .ToList();
-
return request;
}
@@ -382,7 +376,7 @@ private static string BuildFallbackSummary(SummaryRequest request)
var topItems = activities
.Take(3)
- .Select(a => "[" + SafeValue(GetActivityTimelineTimestampUtc(a)) + "] " + SafeValue(a.Type) + ": " + SafeValue(a.Subject))
+ .Select(a => "[" + SafeValue(a.CreatedOnUtc) + "] " + SafeValue(a.Type) + ": " + SafeValue(a.Subject))
.ToList();
var sb = new StringBuilder();
@@ -436,15 +430,15 @@ private static string BuildSummaryHtml(string summary, SummaryRequest request)
sb.Append("'>");
foreach (var activity in topActivities)
{
- var changedOn = SafeValue(GetActivityTimelineTimestampUtc(activity));
- var hasKnownTimestamp = !String.Equals(changedOn, "-", StringComparison.Ordinal);
+ var createdOn = SafeValue(activity.CreatedOnUtc);
+ var hasKnownTimestamp = !String.Equals(createdOn, "-", StringComparison.Ordinal);
sb.Append("");
if (hasKnownTimestamp)
{
sb.Append("[");
- sb.Append(HtmlEncode(changedOn));
+ sb.Append(HtmlEncode(createdOn));
sb.Append("] ");
}
sb.Append(HtmlEncode(SafeValue(activity.Type)));
@@ -574,42 +568,6 @@ private static string TrimValue(string value, int maxLength)
return value.Substring(0, maxLength) + "...";
}
- private static string GetActivityTimelineTimestampUtc(ActivityInput activity)
- {
- if (activity == null)
- {
- return null;
- }
-
- if (!String.IsNullOrWhiteSpace(activity.ChangedOnUtc))
- {
- return activity.ChangedOnUtc;
- }
-
- if (!String.IsNullOrWhiteSpace(activity.ModifiedOnUtc))
- {
- return activity.ModifiedOnUtc;
- }
-
- return activity.CreatedOnUtc;
- }
-
- private static DateTime GetActivityTimelineTimestampSortKey(ActivityInput activity)
- {
- var raw = GetActivityTimelineTimestampUtc(activity);
- if (String.IsNullOrWhiteSpace(raw))
- {
- return DateTime.MinValue;
- }
-
- if (DateTime.TryParseExact(raw, "o", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var parsed))
- {
- return parsed;
- }
-
- return DateTime.MinValue;
- }
-
private sealed class SummaryRequest
{
[JsonProperty("scopeLabel")]
@@ -630,12 +588,6 @@ private sealed class ActivityInput
[JsonProperty("createdOnUtc")]
public string CreatedOnUtc { get; set; }
- [JsonProperty("modifiedOnUtc")]
- public string ModifiedOnUtc { get; set; }
-
- [JsonProperty("changedOnUtc")]
- public string ChangedOnUtc { get; set; }
-
[JsonProperty("type")]
public string Type { get; set; }
diff --git a/README.md b/README.md
index a314aa9..8224cda 100644
--- a/README.md
+++ b/README.md
@@ -103,7 +103,7 @@ Subscriptions are fully **DataMiner-native** in the current implementation.
Behavior to be aware of:
- The notify script has **no internal cadence gate**; each run processes subscriptions matching the requested frequency
-- Activity detection includes both new and updated activities: a record is included if `createdon > since` OR `modifiedon > since`
+- New activity detection uses `createdon > LastSentAt`
- Digest emails can include Assistant-generated HTML timeline summaries, with deterministic fallback when Assistant integration is unavailable
- Sender/from behavior is controlled by DataMiner mail / SMTP configuration
From 9c6b22de71b94f75c2b67b087f583cdeaca5598d Mon Sep 17 00:00:00 2001
From: ToonCasteele <99814254+ToonCasteele@users.noreply.github.com>
Date: Fri, 17 Jul 2026 10:46:44 +0200
Subject: [PATCH 03/10] Fix main-to-release-candidate workflow trigger (#75)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
.github/workflows/sync-main-to-release-candidate.yml | 4 ----
.../DynamicsActivitiesPackage.csproj | 4 ++--
README.md | 2 +-
3 files changed, 3 insertions(+), 7 deletions(-)
diff --git a/.github/workflows/sync-main-to-release-candidate.yml b/.github/workflows/sync-main-to-release-candidate.yml
index 0d5be09..852a2a8 100644
--- a/.github/workflows/sync-main-to-release-candidate.yml
+++ b/.github/workflows/sync-main-to-release-candidate.yml
@@ -3,9 +3,6 @@ name: Sync main to release candidate
on:
push:
branches: [main]
- pull_request:
- types: [opened, reopened, synchronize]
- branches: [release-candidate]
workflow_dispatch: {}
permissions:
@@ -19,7 +16,6 @@ concurrency:
jobs:
sync:
- if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.ref == 'main' }}
runs-on: ubuntu-latest
steps:
- name: Create or reuse promotion pull request
diff --git a/DynamicsActivitiesPackage/DynamicsActivitiesPackage/DynamicsActivitiesPackage.csproj b/DynamicsActivitiesPackage/DynamicsActivitiesPackage/DynamicsActivitiesPackage.csproj
index 2f7d1ab..0d20576 100644
--- a/DynamicsActivitiesPackage/DynamicsActivitiesPackage/DynamicsActivitiesPackage.csproj
+++ b/DynamicsActivitiesPackage/DynamicsActivitiesPackage/DynamicsActivitiesPackage.csproj
@@ -8,8 +8,8 @@
True
10.3.0.0 - 12752
- 1.8.85
- Fix sync workflow startup configuration
+ 1.8.86
+ Trigger main-to-release-candidate sync only on main updates
skyline:sdk:dataminertoken
skyline:sdk:dataminertoken
diff --git a/README.md b/README.md
index 8224cda..8f2c897 100644
--- a/README.md
+++ b/README.md
@@ -219,7 +219,7 @@ and the frontend build base path is set to `/public/DynamicsActivitiesDev/` so s
| `.github/workflows/deploy-dma-on-pr-merge.yml` | Caller workflow for production-on-merge, manual `production` from `main` only, and manual `dev` deploys |
| `.github/workflows/deploy-dmapp-reusable.yml` | Reusable build/register/deploy workflow for DMAPP packaging and Catalog deployment |
| `.github/workflows/copilot-bug-triage.yml` | Auto-comments on `bug`-labeled issues to ask `@copilot` for investigation |
-| `.github/workflows/sync-main-to-release-candidate.yml` | Opens or updates the `main` → `release-candidate` promotion PR, enables auto-merge, asks `@copilot` to resolve conflicts, and retries when the PR is updated |
+| `.github/workflows/sync-main-to-release-candidate.yml` | Opens or updates the `main` → `release-candidate` promotion PR after changes reach `main`, enables auto-merge, and asks `@copilot` to resolve conflicts |
### Release candidate deployment
From 71e0d69009dca331a573e34bb0eb407957c70014 Mon Sep 17 00:00:00 2001
From: ToonCasteele <99814254+ToonCasteele@users.noreply.github.com>
Date: Fri, 17 Jul 2026 11:39:04 +0200
Subject: [PATCH 04/10] Prevent sync workflow runs on PR updates (#76)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
.github/workflows/sync-main-to-release-candidate.yml | 4 +++-
.../DynamicsActivitiesPackage.csproj | 4 ++--
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/sync-main-to-release-candidate.yml b/.github/workflows/sync-main-to-release-candidate.yml
index 852a2a8..adfc964 100644
--- a/.github/workflows/sync-main-to-release-candidate.yml
+++ b/.github/workflows/sync-main-to-release-candidate.yml
@@ -1,7 +1,8 @@
name: Sync main to release candidate
on:
- push:
+ pull_request:
+ types: [closed]
branches: [main]
workflow_dispatch: {}
@@ -16,6 +17,7 @@ concurrency:
jobs:
sync:
+ if: github.event_name == 'workflow_dispatch' || github.event.pull_request.merged == true
runs-on: ubuntu-latest
steps:
- name: Create or reuse promotion pull request
diff --git a/DynamicsActivitiesPackage/DynamicsActivitiesPackage/DynamicsActivitiesPackage.csproj b/DynamicsActivitiesPackage/DynamicsActivitiesPackage/DynamicsActivitiesPackage.csproj
index 0d20576..5b82e95 100644
--- a/DynamicsActivitiesPackage/DynamicsActivitiesPackage/DynamicsActivitiesPackage.csproj
+++ b/DynamicsActivitiesPackage/DynamicsActivitiesPackage/DynamicsActivitiesPackage.csproj
@@ -8,8 +8,8 @@
True
10.3.0.0 - 12752
- 1.8.86
- Trigger main-to-release-candidate sync only on main updates
+ 1.8.87
+ Prevent sync workflow runs on pull request updates
skyline:sdk:dataminertoken
skyline:sdk:dataminertoken
From e30fc4fd23257f72c3c70cf82f6428f072c425e9 Mon Sep 17 00:00:00 2001
From: ToonCasteele <99814254+ToonCasteele@users.noreply.github.com>
Date: Fri, 17 Jul 2026 12:14:45 +0200
Subject: [PATCH 05/10] Fix main-to-release-candidate workflow trigger (#77)
Use the target branch workflow for merged main pull requests and keep manual sync runs on main only.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
...se-candidate.yml => promote-main-to-release-candidate.yml} | 4 ++--
.../DynamicsActivitiesPackage.csproj | 4 ++--
README.md | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
rename .github/workflows/{sync-main-to-release-candidate.yml => promote-main-to-release-candidate.yml} (93%)
diff --git a/.github/workflows/sync-main-to-release-candidate.yml b/.github/workflows/promote-main-to-release-candidate.yml
similarity index 93%
rename from .github/workflows/sync-main-to-release-candidate.yml
rename to .github/workflows/promote-main-to-release-candidate.yml
index adfc964..620f83a 100644
--- a/.github/workflows/sync-main-to-release-candidate.yml
+++ b/.github/workflows/promote-main-to-release-candidate.yml
@@ -1,7 +1,7 @@
name: Sync main to release candidate
on:
- pull_request:
+ pull_request_target:
types: [closed]
branches: [main]
workflow_dispatch: {}
@@ -17,7 +17,7 @@ concurrency:
jobs:
sync:
- if: github.event_name == 'workflow_dispatch' || github.event.pull_request.merged == true
+ if: (github.event_name == 'pull_request_target' && github.event.pull_request.merged == true) || (github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main')
runs-on: ubuntu-latest
steps:
- name: Create or reuse promotion pull request
diff --git a/DynamicsActivitiesPackage/DynamicsActivitiesPackage/DynamicsActivitiesPackage.csproj b/DynamicsActivitiesPackage/DynamicsActivitiesPackage/DynamicsActivitiesPackage.csproj
index 5b82e95..0897f2a 100644
--- a/DynamicsActivitiesPackage/DynamicsActivitiesPackage/DynamicsActivitiesPackage.csproj
+++ b/DynamicsActivitiesPackage/DynamicsActivitiesPackage/DynamicsActivitiesPackage.csproj
@@ -8,8 +8,8 @@
True
10.3.0.0 - 12752
- 1.8.87
- Prevent sync workflow runs on pull request updates
+ 1.8.88
+ Use target-branch workflow for main-to-release-candidate sync
skyline:sdk:dataminertoken
skyline:sdk:dataminertoken
diff --git a/README.md b/README.md
index 8f2c897..e171685 100644
--- a/README.md
+++ b/README.md
@@ -219,7 +219,7 @@ and the frontend build base path is set to `/public/DynamicsActivitiesDev/` so s
| `.github/workflows/deploy-dma-on-pr-merge.yml` | Caller workflow for production-on-merge, manual `production` from `main` only, and manual `dev` deploys |
| `.github/workflows/deploy-dmapp-reusable.yml` | Reusable build/register/deploy workflow for DMAPP packaging and Catalog deployment |
| `.github/workflows/copilot-bug-triage.yml` | Auto-comments on `bug`-labeled issues to ask `@copilot` for investigation |
-| `.github/workflows/sync-main-to-release-candidate.yml` | Opens or updates the `main` → `release-candidate` promotion PR after changes reach `main`, enables auto-merge, and asks `@copilot` to resolve conflicts |
+| `.github/workflows/promote-main-to-release-candidate.yml` | Opens or updates the `main` → `release-candidate` promotion PR after changes reach `main`, enables auto-merge, and asks `@copilot` to resolve conflicts |
### Release candidate deployment
From 35178ec5b5b0a55f3bf0f9a15495a343c6a2c4d6 Mon Sep 17 00:00:00 2001
From: ToonCasteele <99814254+ToonCasteele@users.noreply.github.com>
Date: Fri, 17 Jul 2026 12:18:44 +0200
Subject: [PATCH 06/10] Run promotion sync on main pushes (#78)
Trigger the promotion workflow on main pushes and keep manual dispatches restricted to main.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
.github/workflows/promote-main-to-release-candidate.yml | 5 ++---
.../DynamicsActivitiesPackage.csproj | 4 ++--
2 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/.github/workflows/promote-main-to-release-candidate.yml b/.github/workflows/promote-main-to-release-candidate.yml
index 620f83a..8384af9 100644
--- a/.github/workflows/promote-main-to-release-candidate.yml
+++ b/.github/workflows/promote-main-to-release-candidate.yml
@@ -1,8 +1,7 @@
name: Sync main to release candidate
on:
- pull_request_target:
- types: [closed]
+ push:
branches: [main]
workflow_dispatch: {}
@@ -17,7 +16,7 @@ concurrency:
jobs:
sync:
- if: (github.event_name == 'pull_request_target' && github.event.pull_request.merged == true) || (github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main')
+ if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main')
runs-on: ubuntu-latest
steps:
- name: Create or reuse promotion pull request
diff --git a/DynamicsActivitiesPackage/DynamicsActivitiesPackage/DynamicsActivitiesPackage.csproj b/DynamicsActivitiesPackage/DynamicsActivitiesPackage/DynamicsActivitiesPackage.csproj
index 0897f2a..2d7e676 100644
--- a/DynamicsActivitiesPackage/DynamicsActivitiesPackage/DynamicsActivitiesPackage.csproj
+++ b/DynamicsActivitiesPackage/DynamicsActivitiesPackage/DynamicsActivitiesPackage.csproj
@@ -8,8 +8,8 @@
True
10.3.0.0 - 12752
- 1.8.88
- Use target-branch workflow for main-to-release-candidate sync
+ 1.8.89
+ Run promotion sync on main pushes
skyline:sdk:dataminertoken
skyline:sdk:dataminertoken
From d110d82c1778ae0969d41fd5c4584ff518cdfffd Mon Sep 17 00:00:00 2001
From: ToonCasteele <99814254+ToonCasteele@users.noreply.github.com>
Date: Fri, 17 Jul 2026 13:04:10 +0200
Subject: [PATCH 07/10] Refresh promotion workflow registration (#79)
Use explicit workflow dispatch and job expressions so GitHub registers the promotion workflow correctly.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
.../promote-main-to-release-candidate.yml | 16 ++++++++--------
.../DynamicsActivitiesPackage.csproj | 4 ++--
2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/.github/workflows/promote-main-to-release-candidate.yml b/.github/workflows/promote-main-to-release-candidate.yml
index 8384af9..409f531 100644
--- a/.github/workflows/promote-main-to-release-candidate.yml
+++ b/.github/workflows/promote-main-to-release-candidate.yml
@@ -1,9 +1,9 @@
-name: Sync main to release candidate
+name: Promote main to release candidate
on:
push:
branches: [main]
- workflow_dispatch: {}
+ workflow_dispatch:
permissions:
contents: write
@@ -16,7 +16,7 @@ concurrency:
jobs:
sync:
- if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main')
+ if: ${{ github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main') }}
runs-on: ubuntu-latest
steps:
- name: Create or reuse promotion pull request
@@ -36,7 +36,7 @@ jobs:
--base release-candidate \
--head main \
--title "Sync main into release-candidate" \
- --body $'Automated promotion of the latest main branch changes into release-candidate.\n\nThis pull request is maintained by the Sync main to release candidate workflow.')"
+ --body $'Automated promotion of the latest main branch changes into release-candidate.\n\nThis pull request is maintained by the Promote main to release candidate workflow.')"
fi
echo "number=$pr_number" >> "$GITHUB_OUTPUT"
@@ -72,11 +72,11 @@ jobs:
--paginate \
--jq '.[].body' | grep -Fq "$marker"; then
gh pr comment "$PR_NUMBER" --body "$(cat <<'EOF'
-
-@copilot Please resolve the merge conflicts in this pull request between `main` and `release-candidate`.
+
+ @copilot Please resolve the merge conflicts in this pull request between `main` and `release-candidate`.
-Preserve the intended changes from both branches, run the repository's relevant checks, and push the conflict resolution to this pull request's head branch. Do not merge the pull request yourself; leave it ready for this workflow to auto-merge once it is clean.
-EOF
+ Preserve the intended changes from both branches, run the repository's relevant checks, and push the conflict resolution to this pull request's head branch. Do not merge the pull request yourself; leave it ready for this workflow to auto-merge once it is clean.
+ EOF
)"
fi
diff --git a/DynamicsActivitiesPackage/DynamicsActivitiesPackage/DynamicsActivitiesPackage.csproj b/DynamicsActivitiesPackage/DynamicsActivitiesPackage/DynamicsActivitiesPackage.csproj
index 2d7e676..1b05613 100644
--- a/DynamicsActivitiesPackage/DynamicsActivitiesPackage/DynamicsActivitiesPackage.csproj
+++ b/DynamicsActivitiesPackage/DynamicsActivitiesPackage/DynamicsActivitiesPackage.csproj
@@ -8,8 +8,8 @@
True
10.3.0.0 - 12752
- 1.8.89
- Run promotion sync on main pushes
+ 1.8.90
+ Refresh promotion workflow registration
skyline:sdk:dataminertoken
skyline:sdk:dataminertoken
From 36e2757d267de208c5d8fa6286c8635b0bf765a4 Mon Sep 17 00:00:00 2001
From: Copilot <198982749+Copilot@users.noreply.github.com>
Date: Fri, 17 Jul 2026 13:24:01 +0200
Subject: [PATCH 08/10] Fix: gh CLI fails with "not a git repository" in
promote-main-to-release-candidate workflow (#80)
* Initial plan
* Fix sync job: add GH_REPO env var so gh CLI resolves repo without checkout
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
---
.github/workflows/promote-main-to-release-candidate.yml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/.github/workflows/promote-main-to-release-candidate.yml b/.github/workflows/promote-main-to-release-candidate.yml
index 409f531..c015598 100644
--- a/.github/workflows/promote-main-to-release-candidate.yml
+++ b/.github/workflows/promote-main-to-release-candidate.yml
@@ -23,6 +23,7 @@ jobs:
id: promotion
env:
GH_TOKEN: ${{ github.token }}
+ GH_REPO: ${{ github.repository }}
run: |
pr_number="$(gh pr list \
--base release-candidate \
@@ -45,6 +46,7 @@ jobs:
id: merge
env:
GH_TOKEN: ${{ github.token }}
+ GH_REPO: ${{ github.repository }}
PR_NUMBER: ${{ steps.promotion.outputs.number }}
run: |
merge_state="$(gh pr view "$PR_NUMBER" --json mergeStateStatus --jq '.mergeStateStatus')"
@@ -60,6 +62,7 @@ jobs:
if: steps.merge.outputs.conflicting == 'true' || failure()
env:
GH_TOKEN: ${{ github.token }}
+ GH_REPO: ${{ github.repository }}
PR_NUMBER: ${{ steps.promotion.outputs.number }}
run: |
merge_state="$(gh pr view "$PR_NUMBER" --json mergeStateStatus --jq '.mergeStateStatus')"
From 3157b75b9903da34755988c78962561bd076f46f Mon Sep 17 00:00:00 2001
From: Copilot <198982749+Copilot@users.noreply.github.com>
Date: Fri, 17 Jul 2026 13:43:53 +0200
Subject: [PATCH 09/10] ci: fix sync job failing when release-candidate has no
branch protection rules (#82)
* Initial plan
* ci: fall back to direct merge when auto-merge requires branch protection
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
---
.github/workflows/promote-main-to-release-candidate.yml | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/promote-main-to-release-candidate.yml b/.github/workflows/promote-main-to-release-candidate.yml
index c015598..5e81e33 100644
--- a/.github/workflows/promote-main-to-release-candidate.yml
+++ b/.github/workflows/promote-main-to-release-candidate.yml
@@ -56,7 +56,10 @@ jobs:
exit 0
fi
- gh pr merge "$PR_NUMBER" --auto --merge
+ if ! gh pr merge "$PR_NUMBER" --auto --merge 2>/dev/null; then
+ # Auto-merge requires branch protection rules; fall back to direct merge
+ gh pr merge "$PR_NUMBER" --merge
+ fi
- name: Ask Copilot to resolve merge conflicts
if: steps.merge.outputs.conflicting == 'true' || failure()
From 2ced7497c41d6c0f049e265b2b149761a2ed6f61 Mon Sep 17 00:00:00 2001
From: Copilot <198982749+Copilot@users.noreply.github.com>
Date: Fri, 17 Jul 2026 13:59:46 +0200
Subject: [PATCH 10/10] Use dedicated branch for promotion conflict resolution
(#83)
* Use dedicated promotion branch
* Run promotion after conflict resolution
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Keep promotion branch current safely
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ToonCasteele <99814254+ToonCasteele@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
---
.../promote-main-to-release-candidate.yml | 32 +++++++++++++++----
.../DynamicsActivitiesPackage.csproj | 4 +--
README.md | 2 +-
3 files changed, 29 insertions(+), 9 deletions(-)
diff --git a/.github/workflows/promote-main-to-release-candidate.yml b/.github/workflows/promote-main-to-release-candidate.yml
index 5e81e33..7d5b39e 100644
--- a/.github/workflows/promote-main-to-release-candidate.yml
+++ b/.github/workflows/promote-main-to-release-candidate.yml
@@ -3,6 +3,9 @@ name: Promote main to release candidate
on:
push:
branches: [main]
+ pull_request_target:
+ types: [synchronize]
+ branches: [release-candidate]
workflow_dispatch:
permissions:
@@ -16,7 +19,12 @@ concurrency:
jobs:
sync:
- if: ${{ github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main') }}
+ if: >-
+ github.event_name == 'push' ||
+ (github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main') ||
+ (github.event_name == 'pull_request_target' &&
+ github.event.pull_request.head.ref == 'automation/main-to-release-candidate' &&
+ github.event.pull_request.head.repo.full_name == github.repository)
runs-on: ubuntu-latest
steps:
- name: Create or reuse promotion pull request
@@ -25,9 +33,21 @@ jobs:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
run: |
+ promotion_branch="automation/main-to-release-candidate"
+ main_sha="$(gh api "repos/${GITHUB_REPOSITORY}/git/ref/heads/main" --jq '.object.sha')"
+ if ! gh api --method POST "repos/${GITHUB_REPOSITORY}/git/refs" \
+ -f "ref=refs/heads/${promotion_branch}" \
+ -f "sha=${main_sha}"; then
+ if ! gh api --method PATCH "repos/${GITHUB_REPOSITORY}/git/refs/heads/${promotion_branch}" \
+ -f "sha=${main_sha}" \
+ -F force=false; then
+ echo "Promotion branch has diverged from main; leaving it unchanged for conflict resolution."
+ fi
+ fi
+
pr_number="$(gh pr list \
--base release-candidate \
- --head main \
+ --head "$promotion_branch" \
--state open \
--json number \
--jq '.[0].number // empty')"
@@ -35,9 +55,9 @@ jobs:
if [[ -z "$pr_number" ]]; then
pr_number="$(gh pr create \
--base release-candidate \
- --head main \
+ --head "$promotion_branch" \
--title "Sync main into release-candidate" \
- --body $'Automated promotion of the latest main branch changes into release-candidate.\n\nThis pull request is maintained by the Promote main to release candidate workflow.')"
+ --body $'Automated promotion of the latest main branch changes into release-candidate.\n\nThis pull request is maintained by the Promote main to release candidate workflow. Its dedicated branch allows Copilot to resolve conflicts without modifying the default branch.')"
fi
echo "number=$pr_number" >> "$GITHUB_OUTPUT"
@@ -79,9 +99,9 @@ jobs:
--jq '.[].body' | grep -Fq "$marker"; then
gh pr comment "$PR_NUMBER" --body "$(cat <<'EOF'
- @copilot Please resolve the merge conflicts in this pull request between `main` and `release-candidate`.
+ @copilot Please resolve the merge conflicts in this pull request. The head branch contains the latest `main` changes and the base is `release-candidate`.
- Preserve the intended changes from both branches, run the repository's relevant checks, and push the conflict resolution to this pull request's head branch. Do not merge the pull request yourself; leave it ready for this workflow to auto-merge once it is clean.
+ Preserve the intended changes from both branches, run the repository's relevant checks, and push the conflict resolution to this pull request's dedicated head branch. Do not merge the pull request yourself; leave it ready for this workflow to auto-merge once it is clean.
EOF
)"
fi
diff --git a/DynamicsActivitiesPackage/DynamicsActivitiesPackage/DynamicsActivitiesPackage.csproj b/DynamicsActivitiesPackage/DynamicsActivitiesPackage/DynamicsActivitiesPackage.csproj
index 1b05613..8a50cf2 100644
--- a/DynamicsActivitiesPackage/DynamicsActivitiesPackage/DynamicsActivitiesPackage.csproj
+++ b/DynamicsActivitiesPackage/DynamicsActivitiesPackage/DynamicsActivitiesPackage.csproj
@@ -8,8 +8,8 @@
True
10.3.0.0 - 12752
- 1.8.90
- Refresh promotion workflow registration
+ 1.8.91
+ Use a dedicated branch for promotion conflict resolution
skyline:sdk:dataminertoken
skyline:sdk:dataminertoken
diff --git a/README.md b/README.md
index e171685..0329a1f 100644
--- a/README.md
+++ b/README.md
@@ -219,7 +219,7 @@ and the frontend build base path is set to `/public/DynamicsActivitiesDev/` so s
| `.github/workflows/deploy-dma-on-pr-merge.yml` | Caller workflow for production-on-merge, manual `production` from `main` only, and manual `dev` deploys |
| `.github/workflows/deploy-dmapp-reusable.yml` | Reusable build/register/deploy workflow for DMAPP packaging and Catalog deployment |
| `.github/workflows/copilot-bug-triage.yml` | Auto-comments on `bug`-labeled issues to ask `@copilot` for investigation |
-| `.github/workflows/promote-main-to-release-candidate.yml` | Opens or updates the `main` → `release-candidate` promotion PR after changes reach `main`, enables auto-merge, and asks `@copilot` to resolve conflicts |
+| `.github/workflows/promote-main-to-release-candidate.yml` | Opens or updates the `main` → `release-candidate` promotion PR after changes reach `main`, using a dedicated branch so `@copilot` can resolve conflicts without modifying `main` |
### Release candidate deployment