Skip to content

Add test results artifact uploads to CI workflow - #75

Merged
mpaulosky merged 1 commit into
devfrom
squad/73-add-test-artifact-uploads
Apr 20, 2026
Merged

Add test results artifact uploads to CI workflow#75
mpaulosky merged 1 commit into
devfrom
squad/73-add-test-artifact-uploads

Conversation

@mpaulosky

Copy link
Copy Markdown
Owner

Summary

Adds artifact upload steps to the CI workflow to capture and display test results from all test suites.

Changes

  • Added Upload Architecture Test Results step after Architecture Tests
  • Added Upload Unit Test Results step after Unit Tests
  • Added Upload Integration Test Results step after Integration Tests
  • All uploads use if: always() to capture results even on test failures
  • Configured 30-day retention for all test artifacts

Artifacts Configured

  • architecture-test-results: Contains Architecture Tests output (test-results/architecture)
  • unit-test-results: Contains Unit Tests output (test-results/unit)
  • integration-test-results: Contains Integration Tests output (test-results/integration)

Benefits

✅ Test results are now visible in workflow run artifacts
✅ Results accessible directly from PR view for easier review
✅ All test results captured even when tests fail
✅ 30-day retention policy for artifact storage

Closes #73

@github-actions github-actions Bot added the squad Squad triage inbox — Lead will assign to a member label Apr 20, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🏗️ PR Added to Squad Triage Queue

This PR has been labeled with squad and added to the triage queue.

Next steps:

  • The squad Lead will review and assign to an appropriate team member
  • A squad:member label will be added after triage

If you know which squad member should handle this, you can add the appropriate squad:member label yourself.

@github-actions

github-actions Bot commented Apr 20, 2026

Copy link
Copy Markdown
Contributor

Summary

Summary
Generated on: 04/20/2026 - 17:45:40
Coverage date: 04/20/2026 - 17:45:05 - 04/20/2026 - 17:45:23
Parser: MultiReport (4x Cobertura)
Assemblies: 4
Classes: 51
Files: 50
Line coverage: 66.4% (556 of 837)
Covered lines: 556
Uncovered lines: 281
Coverable lines: 837
Total lines: 2525
Branch coverage: 66.5% (189 of 284)
Covered branches: 189
Total branches: 284
Method coverage: Feature is only available for sponsors
Tag: 82_24681430066

Coverage

AppHost - 0%
Name Line Branch
AppHost 0% ****
Program 0%
Domain - 87.2%
Name Line Branch
Domain 87.2% 91.6%
Domain.Abstractions.Result 95% 50%
Domain.Abstractions.Result`1 75% 50%
MyBlog.Domain.Behaviors.ValidationBehavior`2 100% 100%
MyBlog.Domain.Entities.BlogPost 100%
MyBlog.Domain.Features.BlogPosts.Commands.CreateBlogPost.CreateBlogPostComm
and
100%
MyBlog.Domain.Features.BlogPosts.Commands.CreateBlogPost.CreateBlogPostComm
andHandler
100%
MyBlog.Domain.Features.BlogPosts.Commands.CreateBlogPost.CreateBlogPostComm
andValidator
0%
MyBlog.Domain.Features.BlogPosts.Commands.DeleteBlogPost.DeleteBlogPostComm
and
100%
MyBlog.Domain.Features.BlogPosts.Commands.DeleteBlogPost.DeleteBlogPostComm
andHandler
100%
MyBlog.Domain.Features.BlogPosts.Commands.DeleteBlogPost.DeleteBlogPostComm
andValidator
0%
MyBlog.Domain.Features.BlogPosts.Commands.UpdateBlogPost.UpdateBlogPostComm
and
100%
MyBlog.Domain.Features.BlogPosts.Commands.UpdateBlogPost.UpdateBlogPostComm
andHandler
100% 100%
MyBlog.Domain.Features.BlogPosts.Commands.UpdateBlogPost.UpdateBlogPostComm
andValidator
0%
MyBlog.Domain.Features.BlogPosts.Queries.GetAllBlogPosts.GetAllBlogPostsQue
ryHandler
100%
MyBlog.Domain.Features.BlogPosts.Queries.GetBlogPostById.GetBlogPostByIdQue
ry
100%
MyBlog.Domain.Features.BlogPosts.Queries.GetBlogPostById.GetBlogPostByIdQue
ryHandler
100% 100%
ServiceDefaults - 0%
Name Line Branch
ServiceDefaults 0% 0%
Microsoft.Extensions.Hosting.Extensions 0% 0%
Web - 68.7%
Name Line Branch
Web 68.7% 69%
MyBlog.Web.Components.Layout.MainLayout 100%
MyBlog.Web.Components.Layout.NavMenu 82.8% 71.4%
MyBlog.Web.Components.Pages.Error 100% 75%
MyBlog.Web.Components.Routes 0% 0%
MyBlog.Web.Components.Shared.RedirectToLogin 100%
MyBlog.Web.Data.BlogDbContext 100%
MyBlog.Web.Data.BlogPostDto 100%
MyBlog.Web.Data.BlogPostMappings 100%
MyBlog.Web.Data.MongoDbBlogPostRepository 100% 100%
MyBlog.Web.Features.BlogPosts.Create.Create 75% 50%
MyBlog.Web.Features.BlogPosts.Create.CreateBlogPostCommand 100%
MyBlog.Web.Features.BlogPosts.Create.CreateBlogPostCommandValidator 100%
MyBlog.Web.Features.BlogPosts.Create.CreateBlogPostHandler 100%
MyBlog.Web.Features.BlogPosts.Delete.ConfirmDeleteDialog 100% 100%
MyBlog.Web.Features.BlogPosts.Delete.DeleteBlogPostCommand 100%
MyBlog.Web.Features.BlogPosts.Delete.DeleteBlogPostCommandValidator 100%
MyBlog.Web.Features.BlogPosts.Delete.DeleteBlogPostHandler 100%
MyBlog.Web.Features.BlogPosts.Edit.Edit 88% 75%
MyBlog.Web.Features.BlogPosts.Edit.EditBlogPostCommand 100%
MyBlog.Web.Features.BlogPosts.Edit.EditBlogPostCommandValidator 100%
MyBlog.Web.Features.BlogPosts.Edit.EditBlogPostHandler 84% 90%
MyBlog.Web.Features.BlogPosts.Edit.GetBlogPostByIdQuery 100%
MyBlog.Web.Features.BlogPosts.List.GetBlogPostsHandler 100% 100%
MyBlog.Web.Features.BlogPosts.List.Index 86.8% 84.6%
MyBlog.Web.Features.UserManagement.AssignRoleCommand 100%
MyBlog.Web.Features.UserManagement.ManageRoles 90.4% 75%
MyBlog.Web.Features.UserManagement.Profile 97.2% 82%
MyBlog.Web.Features.UserManagement.RemoveRoleCommand 100%
MyBlog.Web.Features.UserManagement.RoleDto 100%
MyBlog.Web.Features.UserManagement.UserManagementHandler 0% 0%
MyBlog.Web.Features.UserManagement.UserWithRolesDto 100%
MyBlog.Web.Security.RoleClaimsHelper 91.8% 91.1%
Program 0% 0%

@mpaulosky
mpaulosky marked this pull request as ready for review April 20, 2026 17:12
Copilot AI review requested due to automatic review settings April 20, 2026 17:12

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR aims to improve CI observability by uploading per-suite test result artifacts so test outputs remain available even when a test step fails.

Changes:

  • Added actions/upload-artifact steps to upload Architecture/Unit/Integration test results directories in .github/workflows/ci.yml.
  • Added a vendored dotnet-install.sh script to the repo root.
  • Added local build output/log files under docs/build-log.txt and build-output.log (plus a minor global.json formatting change).

Reviewed changes

Copilot reviewed 3 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
.github/workflows/ci.yml Uploads per-suite test result artifacts with 30-day retention and if: always().
global.json Minor formatting-only change.
dotnet-install.sh Adds a full vendored .NET installer script (currently appears unused by CI).
docs/build-log.txt Adds a machine-specific build/test log (includes absolute paths).
build-output.log Adds machine-specific build output log (includes absolute paths).

Comment thread .github/workflows/ci.yml
Comment on lines +90 to +96
- name: Upload Architecture Test Results
uses: actions/upload-artifact@v7
if: always()
with:
name: architecture-test-results
path: test-results/architecture
retention-days: 30

Copilot AI Apr 20, 2026

Copy link

Choose a reason for hiding this comment

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

The PR description/issue scope is about adding CI artifact uploads, but this workflow change comes alongside other unrelated additions in the PR (e.g., dotnet-install.sh and build log files). Please either remove the unrelated files from this PR or update the PR description to explain why they’re needed as part of #73.

Copilot uses AI. Check for mistakes.
Comment thread dotnet-install.sh
Comment on lines +2 to +137
# Copyright (c) .NET Foundation and contributors. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for full license information.
#

# Stop script on NZEC
set -e
# Stop script if unbound variable found (use ${var:-} if intentional)
set -u
# By default cmd1 | cmd2 returns exit code of cmd2 regardless of cmd1 success
# This is causing it to fail
set -o pipefail

# Use in the the functions: eval $invocation
invocation='say_verbose "Calling: ${yellow:-}${FUNCNAME[0]} ${green:-}$*${normal:-}"'

# standard output may be used as a return value in the functions
# we need a way to write text on the screen in the functions so that
# it won't interfere with the return value.
# Exposing stream 3 as a pipe to standard output of the script itself
exec 3>&1

# Setup some colors to use. These need to work in fairly limited shells, like the Ubuntu Docker container where there are only 8 colors.
# See if stdout is a terminal
if [ -t 1 ] && command -v tput > /dev/null; then
# see if it supports colors
ncolors=$(tput colors || echo 0)
if [ -n "$ncolors" ] && [ $ncolors -ge 8 ]; then
bold="$(tput bold || echo)"
normal="$(tput sgr0 || echo)"
black="$(tput setaf 0 || echo)"
red="$(tput setaf 1 || echo)"
green="$(tput setaf 2 || echo)"
yellow="$(tput setaf 3 || echo)"
blue="$(tput setaf 4 || echo)"
magenta="$(tput setaf 5 || echo)"
cyan="$(tput setaf 6 || echo)"
white="$(tput setaf 7 || echo)"
fi
fi

say_warning() {
printf "%b\n" "${yellow:-}dotnet_install: Warning: $1${normal:-}" >&3
}

say_err() {
printf "%b\n" "${red:-}dotnet_install: Error: $1${normal:-}" >&2
}

say() {
# using stream 3 (defined in the beginning) to not interfere with stdout of functions
# which may be used as return value
printf "%b\n" "${cyan:-}dotnet-install:${normal:-} $1" >&3
}

say_verbose() {
if [ "$verbose" = true ]; then
say "$1"
fi
}

# This platform list is finite - if the SDK/Runtime has supported Linux distribution-specific assets,
# then and only then should the Linux distribution appear in this list.
# Adding a Linux distribution to this list does not imply distribution-specific support.
get_legacy_os_name_from_platform() {
eval $invocation

platform="$1"
case "$platform" in
"centos.7")
echo "centos"
return 0
;;
"debian.8")
echo "debian"
return 0
;;
"debian.9")
echo "debian.9"
return 0
;;
"fedora.23")
echo "fedora.23"
return 0
;;
"fedora.24")
echo "fedora.24"
return 0
;;
"fedora.27")
echo "fedora.27"
return 0
;;
"fedora.28")
echo "fedora.28"
return 0
;;
"opensuse.13.2")
echo "opensuse.13.2"
return 0
;;
"opensuse.42.1")
echo "opensuse.42.1"
return 0
;;
"opensuse.42.3")
echo "opensuse.42.3"
return 0
;;
"rhel.7"*)
echo "rhel"
return 0
;;
"ubuntu.14.04")
echo "ubuntu"
return 0
;;
"ubuntu.16.04")
echo "ubuntu.16.04"
return 0
;;
"ubuntu.16.10")
echo "ubuntu.16.10"
return 0
;;
"ubuntu.18.04")
echo "ubuntu.18.04"
return 0
;;
"alpine.3.4.3")
echo "alpine"
return 0
;;
esac
return 1
}

Copilot AI Apr 20, 2026

Copy link

Choose a reason for hiding this comment

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

This adds the full upstream dotnet-install.sh script (~1.8k lines) at repo root, but the CI workflow already uses actions/setup-dotnet with global.json and there are no references to this script in the repo. Keeping a vendored installer script increases maintenance burden and repo size; consider removing it, or moving it under a dedicated scripts/eng folder with a clear update policy/version pin and documented usage.

Suggested change
# Copyright (c) .NET Foundation and contributors. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for full license information.
#
# Stop script on NZEC
set -e
# Stop script if unbound variable found (use ${var:-} if intentional)
set -u
# By default cmd1 | cmd2 returns exit code of cmd2 regardless of cmd1 success
# This is causing it to fail
set -o pipefail
# Use in the the functions: eval $invocation
invocation='say_verbose "Calling: ${yellow:-}${FUNCNAME[0]} ${green:-}$*${normal:-}"'
# standard output may be used as a return value in the functions
# we need a way to write text on the screen in the functions so that
# it won't interfere with the return value.
# Exposing stream 3 as a pipe to standard output of the script itself
exec 3>&1
# Setup some colors to use. These need to work in fairly limited shells, like the Ubuntu Docker container where there are only 8 colors.
# See if stdout is a terminal
if [ -t 1 ] && command -v tput > /dev/null; then
# see if it supports colors
ncolors=$(tput colors || echo 0)
if [ -n "$ncolors" ] && [ $ncolors -ge 8 ]; then
bold="$(tput bold || echo)"
normal="$(tput sgr0 || echo)"
black="$(tput setaf 0 || echo)"
red="$(tput setaf 1 || echo)"
green="$(tput setaf 2 || echo)"
yellow="$(tput setaf 3 || echo)"
blue="$(tput setaf 4 || echo)"
magenta="$(tput setaf 5 || echo)"
cyan="$(tput setaf 6 || echo)"
white="$(tput setaf 7 || echo)"
fi
fi
say_warning() {
printf "%b\n" "${yellow:-}dotnet_install: Warning: $1${normal:-}" >&3
}
say_err() {
printf "%b\n" "${red:-}dotnet_install: Error: $1${normal:-}" >&2
}
say() {
# using stream 3 (defined in the beginning) to not interfere with stdout of functions
# which may be used as return value
printf "%b\n" "${cyan:-}dotnet-install:${normal:-} $1" >&3
}
say_verbose() {
if [ "$verbose" = true ]; then
say "$1"
fi
}
# This platform list is finite - if the SDK/Runtime has supported Linux distribution-specific assets,
# then and only then should the Linux distribution appear in this list.
# Adding a Linux distribution to this list does not imply distribution-specific support.
get_legacy_os_name_from_platform() {
eval $invocation
platform="$1"
case "$platform" in
"centos.7")
echo "centos"
return 0
;;
"debian.8")
echo "debian"
return 0
;;
"debian.9")
echo "debian.9"
return 0
;;
"fedora.23")
echo "fedora.23"
return 0
;;
"fedora.24")
echo "fedora.24"
return 0
;;
"fedora.27")
echo "fedora.27"
return 0
;;
"fedora.28")
echo "fedora.28"
return 0
;;
"opensuse.13.2")
echo "opensuse.13.2"
return 0
;;
"opensuse.42.1")
echo "opensuse.42.1"
return 0
;;
"opensuse.42.3")
echo "opensuse.42.3"
return 0
;;
"rhel.7"*)
echo "rhel"
return 0
;;
"ubuntu.14.04")
echo "ubuntu"
return 0
;;
"ubuntu.16.04")
echo "ubuntu.16.04"
return 0
;;
"ubuntu.16.10")
echo "ubuntu.16.10"
return 0
;;
"ubuntu.18.04")
echo "ubuntu.18.04"
return 0
;;
"alpine.3.4.3")
echo "alpine"
return 0
;;
esac
return 1
}
#
# This repository does not use a vendored copy of the upstream dotnet-install.sh
# script as part of its supported build or CI flow. CI resolves the .NET SDK via
# actions/setup-dotnet and the version pinned in global.json.
#
# If a script-based installation flow is needed in the future, add it under a
# dedicated engineering/scripts location with a documented update policy and
# explicit version pinning instead of restoring a full upstream installer here.
set -eu
printf '%s\n' \
'This repository does not support using ./dotnet-install.sh from the repo root.' \
'Use the documented toolchain setup for this project (actions/setup-dotnet with global.json).' \
'If script-based installation is required, add a maintained wrapper under scripts/eng with documentation.' \
>&2
exit 1

Copilot uses AI. Check for mistakes.
Comment thread docs/build-log.txt

STEP 1: LOCATE SOLUTION
------------------------
✅ Found: MyBlog.slnx in /home/mpaulosky/Repos/MyBlog.worktrees/copilot-worktree-2026-04-20T15-34-36

Copilot AI Apr 20, 2026

Copy link

Choose a reason for hiding this comment

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

This log file includes an absolute local filesystem path with a username (e.g., /home/mpaulosky/...). Committing machine-specific paths can leak personal/workstation info and makes the doc noisy/non-reproducible; please remove this log from the repo (and, if needed, add it to .gitignore) or replace it with a sanitized, path-independent documentation summary.

Suggested change
✅ Found: MyBlog.slnx in /home/mpaulosky/Repos/MyBlog.worktrees/copilot-worktree-2026-04-20T15-34-36
✅ Found: MyBlog.slnx in repository worktree

Copilot uses AI. Check for mistakes.
@mpaulosky

Copy link
Copy Markdown
Owner Author

DevOps Review: CI workflow artifact uploads are operationally sound. All three steps correctly use actions/upload-artifact@v7 with if: always() for reliable capture on test success and failure. 30-day retention is cost-appropriate for CI artifacts. Paths correctly target generated test-results directories. Ready for merge from infrastructure perspective.

… tests (#73)

- Add Upload Architecture Test Results step after architecture tests
- Add Upload Unit Test Results step after unit tests
- Add Upload Integration Test Results step after integration tests
- All uploads use actions/upload-artifact@v7 with if: always() and retention-days: 30
- Artifacts named: architecture-test-results, unit-test-results, integration-test-results

Closes #73

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@mpaulosky
mpaulosky force-pushed the squad/73-add-test-artifact-uploads branch from 662ca7e to 1a8ab0f Compare April 20, 2026 17:44
@github-actions

Copy link
Copy Markdown
Contributor

Code Coverage

Package Line Rate Branch Rate Complexity Health
Domain 0% 0% 77
Web 0% 0% 337
ServiceDefaults 0% 0% 18
Domain 0% 0% 77
Web 0% 0% 337
ServiceDefaults 0% 0% 18
AppHost 0% 100% 1
Domain 20% 0% 77
Web 5% 1% 337
ServiceDefaults 0% 0% 18
AppHost 0% 100% 1
Domain 20% 0% 77
Web 5% 1% 337
ServiceDefaults 0% 0% 18
Domain 87% 92% 77
Web 64% 65% 337
ServiceDefaults 0% 0% 18
Domain 87% 92% 77
Web 64% 65% 337
ServiceDefaults 0% 0% 18
Summary 23% (1164 / 4982) 22% (382 / 1776) 2594

@mpaulosky
mpaulosky merged commit 39ce610 into dev Apr 20, 2026
8 checks passed
@mpaulosky
mpaulosky deleted the squad/73-add-test-artifact-uploads branch April 20, 2026 17:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

squad Squad triage inbox — Lead will assign to a member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add test results artifact upload to workflows

2 participants