fix(scheduler): added better error messages and regular expression for numerical paths
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful

This commit is contained in:
D. Moonfire 2023-01-18 23:51:37 -06:00
parent 185980b5c4
commit 070cf2bfb8
3 changed files with 84 additions and 8 deletions

View file

@ -21,7 +21,7 @@ public partial class NumericalPathSchedule : ISchedule
{ {
public NumericalPathSchedule() public NumericalPathSchedule()
{ {
this.PathRegex = @"^.*(\d+)"; this.PathRegex = @"^.*?(\d+)[^\d]*$";
this.GetPath = entity => entity.Get<UPath>().ToString(); this.GetPath = entity => entity.Get<UPath>().ToString();
this.CaptureGroup = 1; this.CaptureGroup = 1;
this.CaptureOffset = -1; this.CaptureOffset = -1;
@ -61,13 +61,17 @@ public partial class NumericalPathSchedule : ISchedule
/// <summary> /// <summary>
/// Gets or sets the schedule period as a TimeSpan object. This is converted /// Gets or sets the schedule period as a TimeSpan object. This is converted
/// from SchedulePeriod using https://github.com/pengowray/TimeSpanParser. /// from SchedulePeriod using https://github.com/pengowray/TimeSpanParser.
/// If the value is null, then this will be instant (TimeSpan.Zero). /// If the value is null or blank or "immediate", then this will be instant
/// (TimeSpan.Zero).
/// </summary> /// </summary>
public virtual TimeSpan SchedulePeriodTimeSpan public virtual TimeSpan SchedulePeriodTimeSpan
{ {
get => this.SchedulePeriod == null get => string.IsNullOrWhiteSpace(this.SchedulePeriod)
? TimeSpan.Zero || this.SchedulePeriod.Equals(
: TimeSpanParser.Parse(this.SchedulePeriod); "immediate",
StringComparison.InvariantCultureIgnoreCase)
? TimeSpan.Zero
: TimeSpanParser.Parse(this.SchedulePeriod);
set => this.SchedulePeriod = value.ToString(); set => this.SchedulePeriod = value.ToString();
} }
@ -95,9 +99,24 @@ public partial class NumericalPathSchedule : ISchedule
return entity; return entity;
} }
if (match.Groups.Count < 2)
{
throw new InvalidOperationException(
"There must be at least one capture group in '"
+ this.PathRegex
+ "'.");
}
// Figure out the index/number of this entry. // Figure out the index/number of this entry.
int number = int.Parse(match.Groups[this.CaptureGroup].Value) string numberValue = match.Groups[this.CaptureGroup].Value;
+ this.CaptureOffset;
if (!int.TryParse(numberValue, out int number))
{
throw new FormatException(
path + ": Cannot parse '" + numberValue + "' as integer.");
}
number += this.CaptureOffset;
// Figure out the time from the start. // Figure out the time from the start.
DateTime start = this.ScheduleStart DateTime start = this.ScheduleStart

View file

@ -103,7 +103,7 @@ chapter will be set to 2023-01-08, and the third at 2023-01-15.
- Defaults to `entity.Get<UPath>().ToString()` - Defaults to `entity.Get<UPath>().ToString()`
- `Regex PathRegex` - `Regex PathRegex`
- The regular expression that retrieves the number. - The regular expression that retrieves the number.
- Defaults to `^.*(\d+)` which grabs the last number found. - Defaults to `^.*?(\d+)[^\d]*$` which grabs the last number found.
- `DateTime ScheduleStart` - `DateTime ScheduleStart`
- The date that the schedule starts. - The date that the schedule starts.
- No default. - No default.

View file

@ -49,6 +49,7 @@ public class NumericalPathScheduleTests : TemporalSchedulesTestBase
"schedules:", "schedules:",
" - pathRegex: chapter-(\\d+)", " - pathRegex: chapter-(\\d+)",
" scheduleStart: 2023-01-01", " scheduleStart: 2023-01-01",
" schedulePeriod: 1 week",
" access: public", " access: public",
"")); ""));
List<TestSchedule>? schedules = model.Schedules!; List<TestSchedule>? schedules = model.Schedules!;
@ -141,6 +142,62 @@ public class NumericalPathScheduleTests : TemporalSchedulesTestBase
TestHelper.CompareObjects(expected, actual); TestHelper.CompareObjects(expected, actual);
} }
[Fact]
public void ScheduleOffsetWorks()
{
using TemporalSchedulesTestContext context = this.CreateContext();
// Create a numerical series of entities.
var input = new List<Entity>
{
new Entity().SetAll((UPath)"/chapter-11.md", new TestModel()),
new Entity().SetAll((UPath)"/chapter-12.md", new TestModel()),
new Entity().SetAll((UPath)"/chapter-13.md", new TestModel()),
};
var schedules = new List<TestSchedule>
{
new()
{
ScheduleStart = DateTime.Parse("2023-01-01"),
CaptureOffset = -11,
Access = "public",
},
};
// Create the operation and run it, but treat it as being set after the
// second but before the third item.
Timekeeper time = context.Resolve<Timekeeper>();
ApplySchedules op = context.Resolve<ApplySchedules>()
.WithGetSchedules(_ => schedules);
var now = Instant.FromUtc(2023, 1, 9, 0, 0);
time.Clock = new FakeClock(now);
var actual = op
.Run(input)
.Select(
a => string.Format(
"{0} -- {1} -- {2}",
a.Get<UPath>().ToString(),
a.Has<Instant>()
? time
.ToDateTime(a.Get<Instant>())
.ToString("yyyy-MM-dd")
: "none",
a.Get<TestModel>().Access))
.ToList();
var expected = new List<string>
{
"/chapter-11.md -- 2023-01-01 -- public",
"/chapter-12.md -- 2023-01-08 -- public",
"/chapter-13.md -- none -- private",
};
TestHelper.CompareObjects(expected, actual);
}
[Fact] [Fact]
public void SequencedScheduleWorks() public void SequencedScheduleWorks()
{ {