Skip to content

Commit

Permalink
Merge 9f2b96b into df8778a
Browse files Browse the repository at this point in the history
  • Loading branch information
retailcoder authored Jun 21, 2023
2 parents df8778a + 9f2b96b commit 0f02196
Show file tree
Hide file tree
Showing 16 changed files with 952 additions and 77 deletions.
62 changes: 39 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,40 +1,34 @@
<!-- ![banner](https://user-images.githubusercontent.com/5751684/113501222-8edfe880-94f1-11eb-99a9-64583e413ef3.png) -->
[**Installing**](https://github.com/rubberduck-vba/Rubberduck/wiki/Installing)[Contributing](https://github.com/rubberduck-vba/Rubberduck/blob/next/CONTRIBUTING.md)[Attributions](https://github.com/rubberduck-vba/Rubberduck/blob/next/docs/Attributions.md)[Blog](https://rubberduckvba.blog)[Wiki](https://github.com/rubberduck-vba/Rubberduck/wiki)[rubberduckvba.com](https://rubberduckvba.com)

<a href='https://ko-fi.com/N4N2IWEIG' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://storage.ko-fi.com/cdn/kofi1.png?v=3' border='0' alt='Support us on ko-fi.com' /></a>
## Links

- [**Installing**](https://github.com/rubberduck-vba/Rubberduck/wiki/Installing)
- [Contributing](https://github.com/rubberduck-vba/Rubberduck/blob/next/CONTRIBUTING.md)
- [Attributions](https://github.com/rubberduck-vba/Rubberduck/blob/next/docs/Attributions.md)
- [Wiki](https://github.com/rubberduck-vba/Rubberduck/wiki)
- [Website](https://rubberduckvba.com)
- [Blog](https://rubberduckvba.blog)
- [Shop](https://ko-fi.com/rubberduckvba/shop)

## Build Status
<a href='https://ko-fi.com/N4N2IWEIG' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://storage.ko-fi.com/cdn/kofi1.png?v=3' border='0' alt='Support us on ko-fi.com' /></a>

|Branch | Build Status | Release notes &amp; Download Links |
|------------|--------------|-|
| **main** | ![main branch build status][mainBuildStatus] | [latest release](https://github.com/rubberduck-vba/Rubberduck/releases/latest) |
| **next** | ![next branch build status][nextBuildStatus] | [pre-releases](https://github.com/rubberduck-vba/Rubberduck/releases) |
## Releases

[nextBuildStatus]:https://ci.appveyor.com/api/projects/status/we3pdnkeebo4nlck/branch/next?svg=true
[mainBuildStatus]:https://ci.appveyor.com/api/projects/status/we3pdnkeebo4nlck/branch/main?svg=true
- The [latest release](https://github.com/rubberduck-vba/Rubberduck/releases/latest)
- See [all releases](https://github.com/rubberduck-vba/Rubberduck/releases) including pre-release tags

---

## [License (GPLv3)](https://github.com/rubberduck-vba/Rubberduck/blob/next/LICENSE)

Copyright &copy; 2014-2021 Rubberduck project contributors.
Copyright &copy; 2014-2023 Rubberduck project contributors.

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the [GNU General Public License](https://www.gnu.org/licenses/gpl-3.0.en.html) for more details.

---

## [JetBrains](https://www.jetbrains.com) | [ReSharper](https://www.jetbrains.com/resharper/)

[![JetBrains ReSharper logo](https://cloud.githubusercontent.com/assets/5751684/20271309/616bb740-aa58-11e6-91c9-65287b740985.png)](https://www.jetbrains.com/resharper/)

Since the project's early days, JetBrains' Open-Source team has been supporting Rubberduck with free OSS licenses for all core contributors - and we deeply thank them for that. ReSharper has been not only a tool we couldn't do without; it's been an inspiration, the ultimate level of polished perfection to strive for in our own IDE add-in project. So just like you're missing out if you write VBA and you're not using Rubberduck, you're missing out if you write C# and aren't using ReSharper.

<sub>Note: Rubberduck is not a JetBrains product. JetBrains does not contribute and is not affiliated to the Rubberduck project in any way.</sub>

---

## What is Rubberduck?

The Visual Basic Editor (VBE) has stood still for over 20 years, and there is no chance a first-party update to the legacy IDE ever brings it up to speed with modern-day tooling. Rubberduck aims to bring the VBE into this century by doing exactly that.
Expand All @@ -43,11 +37,11 @@ Read more about contributing here:

[![contribute!](https://user-images.githubusercontent.com/5751684/113513709-071dcc80-9539-11eb-833d-d21532065306.png)](https://github.com/rubberduck-vba/Rubberduck/blob/next/CONTRIBUTING.md)

The add-in has *many* features - below is a quick overview.
The add-in has *many* features - below is a quick overview. See https://rubberduckvba.com/features for more details.

### Enhanced Navigation

The Rubberduck *command bar* displays docstring for the current member
The Rubberduck *command bar* displays docstring for the current member.

![command bar](https://user-images.githubusercontent.com/5751684/113501975-25fb6f00-94f7-11eb-9189-fcf2a0dd98da.png)

Expand Down Expand Up @@ -77,7 +71,7 @@ Special comments that become a game changer with Rubberduck processing them: org

### More?

Of course there's more! There's tooling to help synchronizing the project with files in a folder (for source/version control), some auto-completion features like self-closing parentheses and quotes; there's a regular expression assistant, a replacement for the VBE's *add/remove references* dialog, and so many other things to discover, and yet even more to implement.
Of course there's more! There's tooling to help synchronizing the project with files in a folder (useful for source/version control!), some auto-completion features like self-closing parentheses and quotes; there's a regular expression assistant, a replacement for the VBE's *add/remove references* dialog, and so many other things to discover, and yet even more to implement.

---

Expand All @@ -93,3 +87,25 @@ Rubberduck isn't a lightweight add-in and consumes a large amount of memory. So
Join us on our [Discord server](https://discord.gg/5Nbb8j6R) for support, questions, contributions, or just to come and say hi!

For more information please see [Getting Started](https://github.com/rubberduck-vba/Rubberduck/blob/next/docs/GettingStarted.md) in the project's wiki, and follow the project's blog for project updates and advanced VBA OOP reading material.

---

## Roadmap

After over two years without an "official" new release, Rubberduck version jumped from 2.5.2 to 2.5.9, adding minor but interesting features to an already impressive array.

### The road ahead

Rubberduck 2.x is now planned to end at 2.5.9.x, perhaps with a number of small revisions and bug fixes, but nothing major should be expected, as the developers' attention is shifting to the 3.0 project:

- Parsing and understanding VBA code is moving to a language (LSP) server
- We're making a new editor _inside_ (for now) the Visual Basic Editor that will be the LSP client
- Baseline server-side feature set for 3.0 is everything 2.5.9 does
- Baseline client-side feature set for 3.0 is the 2.5.x UI (perhaps tweaked a bit/lot) hosted in the Rubberduck Editor

Fully controlling the editor opens Rubberduck to everything we ever dreamed of:

- In-editor syntax and static code analysis reporting and quick-fixing
- Full editor theming, custom syntax highlighting

See the [Rubberduck3](https://github.com/rubberduck-vba/Rubberduck3) repository for more information.
1 change: 1 addition & 0 deletions Rubberduck.Core/Rubberduck.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
<PackageReference Include="NLog.Schema">
<Version>4.5.10</Version>
</PackageReference>
<PackageReference Include="Octokit" Version="6.0.0" />
<PackageReference Include="System.IO.Abstractions" Version="12.2.1" />
<PackageReference Include="System.ValueTuple">
<Version>4.5.0</Version>
Expand Down
4 changes: 2 additions & 2 deletions Rubberduck.Core/UI/About/AboutControl.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<ResourceDictionary Source="../Styles/DefaultStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>

<BitmapImage x:Key="RD" UriSource="pack://application:,,,/Rubberduck.Resources;component/Rubberduck.png" />
<BitmapImage x:Key="RD" UriSource="pack://application:,,,/Rubberduck.Resources;component/Rubberduck_Banner.png" />
<Style x:Key="NormalLabel" TargetType="TextBlock">
<Style.Setters>
<Setter Property="FontFamily" Value="Segoe UI" />
Expand Down Expand Up @@ -76,7 +76,7 @@
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>

<Border Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" Margin="10">
<Border Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" Margin="10" BorderThickness="0,1" BorderBrush="Black">
<Image Source="{StaticResource RD}" Stretch="Uniform" />
</Border>
<Border Grid.Row="1" Grid.Column="0" Style="{StaticResource SectionBorder}">
Expand Down
12 changes: 10 additions & 2 deletions Rubberduck.Core/UI/Command/VersionCheckCommand.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
using System;
using System.Diagnostics;
using System.Reflection;
using Rubberduck.Interaction;
using Rubberduck.VersionCheck;
using Rubberduck.Resources;
using Rubberduck.SettingsProvider;
using Rubberduck.Settings;
using System.Threading;

namespace Rubberduck.UI.Command
{
Expand Down Expand Up @@ -45,10 +45,18 @@ protected override async void OnExecute(object parameter)
{
var settings = _config.Read().UserSettings.GeneralSettings;
Logger.Info("Executing version check...");

var tokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(5));
await _versionCheck
.GetLatestVersionAsync(settings)
.GetLatestVersionAsync(settings, tokenSource.Token)
.ContinueWith(t =>
{
if (t.IsFaulted)
{
Logger.Warn(t.Exception);
return;
}

if (_versionCheck.CurrentVersion < t.Result)
{
var proceed = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -775,7 +775,7 @@ public bool CanDisableInspection
}
}

private static readonly Uri _inspectionsHomeUrl = new Uri("https://rubberduckvba.com/inspections");
private static readonly Uri _inspectionsHomeUrl = new Uri("https://rubberduckvba.com/features/summary?name=inspections");

public Uri InspectionDetailsUrl => _selectedInspection == null
? _inspectionsHomeUrl
Expand Down
179 changes: 179 additions & 0 deletions Rubberduck.Core/VersionCheck/ApiClientBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
using Newtonsoft.Json;
using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Rubberduck.Client.Abstract
{
public abstract class ApiClientBase : IDisposable
{
protected static readonly string UserAgentName = "Rubberduck";
protected static readonly string BaseUrl = "https://api.rubberduckvba.com/api/v1/";
protected static readonly string ContentTypeApplicationJson = "application/json";
protected static readonly int MaxAttempts = 3;
protected static readonly TimeSpan RetryCooldownDelay = TimeSpan.FromSeconds(1);

protected readonly Lazy<HttpClient> _client;

protected ApiClientBase()
{
_client = new Lazy<HttpClient>(() => GetClient());
}

protected HttpClient GetClient()
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var client = new HttpClient();
return ConfigureClient(client);
}

protected virtual HttpClient ConfigureClient(HttpClient client)
{
var userAgentVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(3);
var userAgentHeader = new ProductInfoHeaderValue(UserAgentName, userAgentVersion);

client.DefaultRequestHeaders.UserAgent.Add(userAgentHeader);
return client;
}

protected virtual async Task<TResult> GetResponse<TResult>(string route, CancellationToken? cancellationToken = null)
{
var uri = new Uri($"{BaseUrl}{route}");

var attempt = 0;
var token = cancellationToken ?? CancellationToken.None;

while (!token.IsCancellationRequested && attempt <= MaxAttempts)
{
attempt++;
var delay = attempt == 0 ? TimeSpan.Zero : RetryCooldownDelay;

var (success, result) = await TryGetResponse<TResult>(uri, delay, token);
if (success)
{
return result;
}
}

token.ThrowIfCancellationRequested();
throw new InvalidOperationException($"API call failed to return a result after {attempt} attempts.");
}

private async Task<(bool, TResult)> TryGetResponse<TResult>(Uri uri, TimeSpan delay, CancellationToken token)
{
if (delay != TimeSpan.Zero)
{
await Task.Delay(delay);
}

token.ThrowIfCancellationRequested();

try
{
using (var client = GetClient())
{
using (var response = await client.GetAsync(uri))
{
response.EnsureSuccessStatusCode();
token.ThrowIfCancellationRequested();

var content = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<TResult>(content);

return (true, result);
}
}
}
catch (OperationCanceledException)
{
throw;
}
catch
{
return default;
}
}

protected virtual async Task<T> Post<T>(string route, T args, CancellationToken? cancellationToken = null) => await Post<T, T>(route, args, cancellationToken ?? CancellationToken.None);

protected virtual async Task<TResult> Post<TArgs, TResult>(string route, TArgs args, CancellationToken? cancellationToken = null)
{
var uri = new Uri($"{BaseUrl}{route}");
string json;
try
{
json = JsonConvert.SerializeObject(args);
}
catch (Exception exception)
{
throw new ArgumentException("The specified arguments could not be serialized.", exception);
}

var attempt = 0;
var token = cancellationToken ?? CancellationToken.None;

while (!token.IsCancellationRequested && attempt <= MaxAttempts)
{
attempt++;
var delay = attempt == 0 ? TimeSpan.Zero : RetryCooldownDelay;

var (success, result) = await TryPost<TResult>(uri, json, delay, token);
if (success)
{
return result;
}
}

token.ThrowIfCancellationRequested();
throw new InvalidOperationException($"API call failed to return a result after {attempt} attempts.");
}

private async Task<(bool, TResult)> TryPost<TResult>(Uri uri, string body, TimeSpan delay, CancellationToken token)
{
if (delay != TimeSpan.Zero)
{
await Task.Delay(delay);
}

token.ThrowIfCancellationRequested();

try
{
using (var client = GetClient())
{
var content = new StringContent(body, Encoding.UTF8, ContentTypeApplicationJson);
using (var response = await client.PostAsync(uri, content, token))
{
response.EnsureSuccessStatusCode();
token.ThrowIfCancellationRequested();

var jsonResult = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<TResult>(jsonResult);

return (true, result);
}
}
}
catch (OperationCanceledException)
{
throw;
}
catch
{
return default;
}
}

public void Dispose()
{
if (_client.IsValueCreated)
{
_client.Value.Dispose();
}
}
}
}
19 changes: 19 additions & 0 deletions Rubberduck.Core/VersionCheck/PublicApiClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Rubberduck.Client.Abstract;

namespace Rubberduck.VersionCheck
{
public class PublicApiClient : ApiClientBase
{
private static readonly string PublicTagsEndPoint = "public/tags";

public async Task<IEnumerable<Tag>> GetLatestTagsAsync(CancellationToken token)
{
return await GetResponse<Tag[]>(PublicTagsEndPoint, token);
}
}
}
16 changes: 16 additions & 0 deletions Rubberduck.Core/VersionCheck/Tag.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;

namespace Rubberduck.VersionCheck
{
public class Tag
{
public string Name { get; set; }
public DateTime DateCreated { get; set; }
public string InstallerDownloadUrl { get; set; }
public int InstallerDownloads { get; set; }
public bool IsPreRelease { get; set; }

public virtual ICollection<TagAsset> TagAssets { get; set; } = new List<TagAsset>();
}
}
9 changes: 9 additions & 0 deletions Rubberduck.Core/VersionCheck/TagAsset.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Rubberduck.VersionCheck
{
public class TagAsset
{
public int TagId { get; set; }
public string Name { get; set; }
public string DownloadUrl { get; set; }
}
}
Loading

0 comments on commit 0f02196

Please sign in to comment.