Skip to content

Commit

Permalink
Expose projects to upgrade (#92)
Browse files Browse the repository at this point in the history
* Upgrade packages. Output two new values. Update README.md and action.yml. Modernize.

* Apply suggestions from code review

Co-authored-by: Genevieve Warren <[email protected]>

---------

Co-authored-by: Genevieve Warren <[email protected]>
  • Loading branch information
IEvangelist and gewarren authored Jul 6, 2023
1 parent 5b5aefb commit fd9dd57
Show file tree
Hide file tree
Showing 26 changed files with 415 additions and 211 deletions.
139 changes: 100 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# 🎯 LTS (or current) versions
## .NET version sweeper
# 🎯 LTS (or STS) versions
## .NET version sweeper

[![build & test](https://github.com/dotnet/versionsweeper/actions/workflows/build-and-test.yml/badge.svg)](https://github.com/dotnet/versionsweeper/actions/workflows/build-and-test.yml)
[![target supported version](https://github.com/dotnet/versionsweeper/actions/workflows/dog-food.yml/badge.svg)](https://github.com/dotnet/versionsweeper/actions/workflows/dog-food.yml)
[![code-ql analysis](https://github.com/dotnet/versionsweeper/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/dotnet/versionsweeper/actions/workflows/codeql-analysis.yml)
[![GitHub Marketplace](https://img.shields.io/badge/marketplace-.NET%20version%20sweeper-green?colorA=24292e&colorB=97ca00&style=flat&longCache=true&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAM6wAADOsB5dZE0gAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAERSURBVCiRhZG/SsMxFEZPfsVJ61jbxaF0cRQRcRJ9hlYn30IHN/+9iquDCOIsblIrOjqKgy5aKoJQj4O3EEtbPwhJbr6Te28CmdSKeqzeqr0YbfVIrTBKakvtOl5dtTkK+v4HfA9PEyBFCY9AGVgCBLaBp1jPAyfAJ/AAdIEG0dNAiyP7+K1qIfMdonZic6+WJoBJvQlvuwDqcXadUuqPA1NKAlexbRTAIMvMOCjTbMwl1LtI/6KWJ5Q6rT6Ht1MA58AX8Apcqqt5r2qhrgAXQC3CZ6i1+KMd9TRu3MvA3aH/fFPnBodb6oe6HM8+lYHrGdRXW8M9bMZtPXUji69lmf5Cmamq7quNLFZXD9Rq7v0Bpc1o/tp0fisAAAAASUVORK5CYII=)](https://github.com/marketplace/actions/net-version-sweeper)
[![GitHub License](https://img.shields.io/github/license/dotnet/versionsweeper)](https://github.com/dotnet/versionsweeper/blob/main/LICENSE)
[![GitHub marketplace](https://img.shields.io/badge/marketplace-.NET%20version%20sweeper-green?colorA=24292e&colorB=97ca00&style=flat&longCache=true&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAM6wAADOsB5dZE0gAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAERSURBVCiRhZG/SsMxFEZPfsVJ61jbxaF0cRQRcRJ9hlYn30IHN/+9iquDCOIsblIrOjqKgy5aKoJQj4O3EEtbPwhJbr6Te28CmdSKeqzeqr0YbfVIrTBKakvtOl5dtTkK+v4HfA9PEyBFCY9AGVgCBLaBp1jPAyfAJ/AAdIEG0dNAiyP7+K1qIfMdonZic6+WJoBJvQlvuwDqcXadUuqPA1NKAlexbRTAIMvMOCjTbMwl1LtI/6KWJ5Q6rT6Ht1MA58AX8Apcqqt5r2qhrgAXQC3CZ6i1+KMd9TRu3MvA3aH/fFPnBodb6oe6HM8+lYHrGdRXW8M9bMZtPXUji69lmf5Cmamq7quNLFZXD9Rq7v0Bpc1o/tp0fisAAAAASUVORK5CYII=)](https://github.com/marketplace/actions/net-version-sweeper)
[![GitHub license](https://img.shields.io/github/license/dotnet/versionsweeper)](https://github.com/dotnet/versionsweeper/blob/main/LICENSE)
[![GitHub contributors](https://img.shields.io/github/contributors/dotnet/versionsweeper.svg)](https://GitHub.com/dotnet/versionsweeper/graphs/contributors/)
[![GitHub repo size](https://img.shields.io/github/repo-size/dotnet/versionsweeper)](https://github.com/dotnet/versionsweeper)
[![GitHub issues-opened](https://img.shields.io/github/issues/dotnet/versionsweeper.svg)](https://GitHub.com/dotnet/versionsweeper/issues?q=is%3Aissue+is%3Aopened)
Expand All @@ -16,7 +16,7 @@

## Get started

The .NET version sweeper is designed to alert repositories that there are projects targeting versions that are no longer supported. For example, projects targeting .NET Core 3.0, or .NET Framework 4.5.1 would trigger an issue to be created to update these non-LTS or current versions. For example issues, see [issues created in this repo based on the *non-lts* directory](https://github.com/dotnet/versionsweeper/issues?q=is%3Aopen+is%3Aissue+label%3Adotnet-target-version).
The .NET version sweeper is designed to alert repositories (by either creating issues, pull requests, or both) that there are projects targeting versions that are no longer supported (or won't be soon). For example, projects targeting .NET Core 3.0 or .NET Framework 4.5.1 could trigger an issue to be created to update these projects to supported versions, or even a pull request that upgrades it for you. For example issues, see [issues created in this repo based on the *non-lts* directory](https://github.com/dotnet/versionsweeper/issues?q=is%3Aopen+is%3Aissue+label%3Adotnet-target-version).

This is intended to be used as a GitHub action that will run as a [scheduled CRON job](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#onschedule). Ideally, once a month or as often as necessary to align with .NET version updates.

Expand All @@ -39,56 +39,103 @@ A schedule/cron job that runs on the first of every month is detailed below in t
| `-p`, `pattern` | The search pattern, defaults to `"*.csproj;*.fsproj;*.vbproj;*.xproj;project.json"`. |
| `-s`, `sdk-compliance` | Whether or not to report projects that are not using the new SDK-style project format. |

## GitHub Action outputs

| Output | Type | Details |
|:---------------------|:-----------|:-----------------------------------------------------------------------------------------------------------|
| `has-remaining-work` | `bool` | When `true`, the `upgrade-projects` array will be populated with project directories that require upgrade. |
| `upgrade-projects` | `string[]` | An array of project directories that are in need of being upgraded. |

> **Note**
> Outputs are only present when configured to run as pull request mode. For more information, see [Configure action](#configure-action).
## Example workflow

```yml
# The name used in the GitHub UI for the workflow
name: '.net version sweeper'
# This is a basic workflow to help you get started with Actions

# When to run this action:
# - Scheduled on the first of every month
# - Manually runable from the GitHub UI with a reason
name: "target supported version"

# Controls when the action will run.
on:
# Triggers the workflow on push or pull request events but only for the default branch
schedule:
- cron: '0 0 1 * *'
- cron: "0 0 1 * *"
workflow_dispatch:
inputs:
reason:
description: 'The reason for running the workflow'
description: "The reason for running the workflow"
required: true
default: "Manual run"
support:
description: "The support level to target (STS, LTS, or Preview)."
required: true
default: 'Manual run'
default: "STS"

# Run on the latest version of Ubuntu
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
version-sweep:
# The type of runner that the job will run on
runs-on: ubuntu-latest
permissions:
contents: read
issues: write
statuses: write
pull-requests: write

# Checkout the repo into the workspace within the VM
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
- uses: actions/checkout@v2

# If triggered manually, print the reason why
- name: 'Print manual run reason'
if: ${{ github.event_name == 'workflow_dispatch' }}
run: |
echo "Reason: ${{ github.event.inputs.reason }}"
# Run the .NET version sweeper
# Issues will be automatically created for any non-ignored projects that are targeting non-LTS versions
- name: .NET version sweeper
id: dotnet-version-sweeper
uses: dotnet/[email protected]
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
owner: ${{ github.repository_owner }}
name: ${{ github.repository }}
branch: ${{ github.ref }}
sdkCompliance: true
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v3

# Runs a single command using the runners shell
- name: "Print manual run reason"
if: ${{ github.event_name == 'workflow_dispatch' }}
run: |
echo 'Reason: ${{ github.event.inputs.reason }}'
# Start the .NET version sweeper, scan projects/slns for non-LTS (or currrent) versions
- name: .NET version sweeper
id: dotnet-version-sweeper
uses: dotnet/versionsweeper@main
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
owner: ${{ github.repository_owner }}
name: ${{ github.repository }}
branch: ${{ github.ref }}

- name: Create pull requests
if: steps.dotnet-version-sweeper.outputs.has-remaining-work == 'true'
run: |
upgradeProjects: ${{ steps.dotnet-version-sweeper.outputs.upgrade-projects }}
# Install .NET Upgrade Assistant global tool
dotnet tool install --global upgrade-assistant
# Iterate all upgrade projects
for projectDir in "${upgradeProjects[@]}"; do
echo "Project Directory: $projectDir"
# Create a new branch
git checkout -b upgrade/$projectDir
# Perform the upgrade using upgrade-assistant
upgrade-assistant upgrade "$projectDir" --non-interactive -t ${{ inputs.support }}
# Commit the changes
git add .
git commit -m ".NET Version Sweeper: Upgraded $projectDir"
# Push the branch to the repository
git push origin upgrade/$projectDir
# Create a pull request
gh pr create \
--base main \
--head upgrade/$projectDir \
--title "Upgraded $projectDir" \
--body "Proposed upgrade for $projectDir"
done
```
## Project and solution discovery
Expand All @@ -102,6 +149,13 @@ The .NET version sweeper currently supports reporting on all of the following ty
- Project JSON files: `project.json`
- Solution files: `*.sln`

## Dockerfile discovery

The .NET version sweeper also supports reporting _Dockerfile_ target frameworks that are out-of-support, or soon to be, for example:

- `FROM mcr.microsoft.com/dotnet/framework/aspnet:4.8`
- `COPY --from=mcr.microsoft.com/dotnet/framework/runtime:3.5-20221011-windowsservercore-ltsc2019`

## Configure action

To configure the action, you can create a file at the root of the repository named *dotnet-versionsweeper.json*. This config file contains a node, named `"ignore"` that is an array of patterns following the [globbing matcher detailed here](https://docs.microsoft.com/dotnet/api/microsoft.extensions.filesystemglobbing.matcher#remarks).
Expand All @@ -115,12 +169,19 @@ The file can also contain a value `outOfSupportWithinDays` to specify the number
"**/*ThisShouldNeverBeFlagged.csproj",
"IgnoreDir/**/*.*"
],
"outOfSupportWithinDays": 90
"outOfSupportWithinDays": 90,
"actionType": "All"
}
```

For an example config file, see [dotnet/samples/dotnet-versionsweeper.json](https://github.com/dotnet/samples/blob/master/dotnet-versionsweeper.json).

| Configuration | Type | Details |
|:--|:--|:--|
| `ignore` | `string[]` | Glob patterns to ignore. |
| `outOfSupportWithinDays` | `string[]` | The number of days in advance to monitor for. |
| `actionType` | `ActionType` <br><br> &nbsp;&nbsp; `"CreateIssue"` <br> &nbsp;&nbsp; `"PullRequest"` <br> &nbsp;&nbsp; `"All"` | The type of action to take, defaults to `CreateIssue`. |

## Label auto-generation

This tool will create a label named `dotnet-target-version` for easier tracking of issues and pull requests that it creates. The label is created with the following description and color by default, please do not change the name - as that is what is used to determine whether or not to create a new label.
Expand All @@ -140,7 +201,7 @@ This repo serves as a sample, as it contains a directory *non-lts* with projects

## Official .NET support policies

This action is intended to help determine non-LTS (or current) versions, but it is _not_ perfect. When in doubt, please refer to the [official .NET support policies](https://dotnet.microsoft.com/platform/support/policy).
This action is intended to help determine non-LTS (or STS) versions, but it _isn't_ perfect. When in doubt, please refer to the [official .NET support policies](https://dotnet.microsoft.com/platform/support/policy).

## Acknowledgements

Expand Down
8 changes: 5 additions & 3 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ inputs:
required: false
default: 'false'
outputs:
summary-message:
description: 'A detailed summary of all the projects that were flagged.'
has-remaining-work:
description: 'A boolean value indicating whether more work remains, i.e. upgrade-projects contains values.'
upgrade-projects:
description: 'An array of projects that need to be upgraded.'
runs:
using: 'docker'
image: 'Dockerfile'
Expand All @@ -43,4 +45,4 @@ runs:
- '-p'
- ${{ inputs.pattern }}
- '-s'
- ${{ inputs.sdkCompliance }}
- ${{ inputs.sdkCompliance }}
6 changes: 3 additions & 3 deletions src/DotNet.GitHub/DotNet.GitHub.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
Expand All @@ -11,8 +11,8 @@
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.0" />
<PackageReference Include="Octokit" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.1" />
<PackageReference Include="Octokit" Version="7.0.1" />
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion src/DotNet.GitHub/GitHubGraphQLClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public GitHubGraphQLClient(HttpClient httpClient, ILogger<GitHubGraphQLClient> l
}
catch (Exception ex)
{
_logger.LogWarning(ex, ex.Message);
_logger.LogWarning(ex, "⚠️ {Message}", ex.Message);

return (true, default);
}
Expand Down
4 changes: 2 additions & 2 deletions src/DotNet.GitHub/GitHubIssueService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public async ValueTask<Issue> PostIssueAsync(
IIssuesClient issuesClient = GetIssuesClient(token);
Issue issue = await issuesClient.Create(owner, name, newIssue);

_logger.LogInformation($"Issue created: {issue.HtmlUrl}");
_logger.LogInformation("Issue created: {HtmlUrl}", issue.HtmlUrl);

return issue;
}
Expand All @@ -40,7 +40,7 @@ public async ValueTask<Issue> UpdateIssueAsync(
Issue issue = await issuesClient.Update(
owner, name, unchecked((int)number), issueUpdate);

_logger.LogInformation($"Issue updated: {issue.HtmlUrl}");
_logger.LogInformation("Issue updated: {HtmlUrl}", issue.HtmlUrl);

return issue;
}
Expand Down
4 changes: 2 additions & 2 deletions src/DotNet.GitHub/ModelExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ The following project file(s) target a .NET version which is no longer supported
})));

document.AppendParagraph(
"Consider upgrading projects to either the current release, or the nearest LTS TFM version.");
"Consider upgrading projects to either the Standard Term Support (STS) or Long Term Support (LTS) versions.");

document.AppendParagraph($"""
If any of these projects listed in this issue are intentionally targeting an unsupported version,
Expand Down Expand Up @@ -122,7 +122,7 @@ The following Dockerfile(s) target a .NET version which is no longer supported.
})));

document.AppendParagraph(
"Consider upgrading Dockerfile images to either the current release, or the nearest LTS TFM version.");
"Consider upgrading Dockerfile images to either the Standard Term Support (STS) or Long Term Support (LTS) versions.");

document.AppendParagraph($"""
If any of these Dockerfile(s) listed in this issue are intentionally targeting an unsupported version,
Expand Down
10 changes: 5 additions & 5 deletions src/DotNet.GitHub/RateLimitAwareQueue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public sealed class RateLimitAwareQueue
{
const int DelayBetweenPostCalls = 1_000;

readonly HashSet<string> _unqiueNewIssueTitles = new(StringComparer.OrdinalIgnoreCase);
readonly HashSet<string> _uniqueTitles = new(StringComparer.OrdinalIgnoreCase);
readonly ConcurrentQueue<(GitHubApiArgs, NewIssue)> _newIssuesQueue = new();
readonly ConcurrentQueue<(GitHubApiArgs, IssueUpdate)> _updateIssuesQueue = new();
readonly IGitHubIssueService _gitHubIssueService;
Expand All @@ -17,7 +17,7 @@ public RateLimitAwareQueue(IGitHubIssueService gitHubIssueService) =>

public void Enqueue(GitHubApiArgs args, NewIssue issue)
{
if (_unqiueNewIssueTitles.Add(issue.Title))
if (_uniqueTitles.Add(issue.Title))
{
_newIssuesQueue.Enqueue((args, issue));
}
Expand All @@ -26,7 +26,7 @@ public void Enqueue(GitHubApiArgs args, NewIssue issue)
public void Enqueue(GitHubApiArgs args, IssueUpdate issue) =>
_updateIssuesQueue.Enqueue((args, issue));

public async IAsyncEnumerable<(string Type, Issue Issue)> ExecuteAllQueuedItemsAsync()
public async IAsyncEnumerable<(string Message, string Url)> ExecuteAllQueuedItemsAsync()
{
while (_newIssuesQueue is { IsEmpty: false }
&& _newIssuesQueue.TryDequeue(out (GitHubApiArgs, NewIssue) newItem))
Expand All @@ -35,7 +35,7 @@ public void Enqueue(GitHubApiArgs args, IssueUpdate issue) =>
Issue issue = await _gitHubIssueService.PostIssueAsync(
args.Owner, args.RepoName, args.Token, newIssue);

yield return ("Created", issue);
yield return ("Created issue", issue.HtmlUrl);

await Task.Delay(DelayBetweenPostCalls);
}
Expand All @@ -47,7 +47,7 @@ public void Enqueue(GitHubApiArgs args, IssueUpdate issue) =>
Issue issue = await _gitHubIssueService.UpdateIssueAsync(
args.Owner, args.RepoName, args.Token, args.IssueNumber, newIssue);

yield return ("Updated", issue);
yield return ("Updated issue", issue.HtmlUrl);

await Task.Delay(DelayBetweenPostCalls);
}
Expand Down
Loading

0 comments on commit fd9dd57

Please sign in to comment.