diff --git a/src/sync/sync_common.nim b/src/sync/sync_common.nim index 4caef63d..d1a4361f 100644 --- a/src/sync/sync_common.nim +++ b/src/sync/sync_common.nim @@ -327,9 +327,9 @@ func keyOrderForFmt(e: ConceptExerciseConfig | if e.test_runner.isSome() and not e.test_runner.get(): result.add eckTestRunner result.add eckBlurb - if e.source.len > 0: + if e.source.isSome(): result.add eckSource - if e.source_url.len > 0: + if e.source_url.isSome(): result.add eckSourceUrl if e.custom.isSome() and e.custom.get().len > 0: result.add eckCustom @@ -387,9 +387,11 @@ proc pretty*(e: ConceptExerciseConfig | PracticeExerciseConfig, of eckBlurb: result.addString("blurb", e.blurb) of eckSource: - result.addString("source", e.source) + if e.source.isSome(): + result.addString("source", e.source.get()) of eckSourceUrl: - result.addString("source_url", e.source_url) + if e.source_url.isSome(): + result.addString("source_url", e.source_url.get()) of eckCustom: addValOrNull(custom, addObject) result.removeComma() diff --git a/src/sync/sync_metadata.nim b/src/sync/sync_metadata.nim index 9b5ea8e5..c6b0a01d 100644 --- a/src/sync/sync_metadata.nim +++ b/src/sync/sync_metadata.nim @@ -1,4 +1,4 @@ -import std/[os, strformat, strutils] +import std/[options, os, strformat, strutils] import pkg/parsetoml import ".."/[cli, logger, types_exercise_config, types_track_config] import "."/sync_common @@ -9,8 +9,8 @@ import "."/sync_common type UpstreamMetadata = object blurb: string - source: string - source_url: string + source: Option[string] + source_url: Option[string] PathAndUpdatedConfig = object path: string @@ -23,9 +23,12 @@ proc parseMetadataToml(path: string): UpstreamMetadata = ## returns an object containing the `blurb`, `source`, and `source_url` values. let t = parsetoml.parseFile(path) result = UpstreamMetadata( - blurb: if t.hasKey("blurb"): t["blurb"].getStr() else: "", - source: if t.hasKey("source"): t["source"].getStr() else: "", - source_url: if t.hasKey("source_url"): t["source_url"].getStr() else: "" + blurb: + if t.hasKey("blurb"): t["blurb"].getStr() else: "", + source: + if t.hasKey("source"): t["source"].getStr().some() else: none(string), + source_url: + if t.hasKey("source_url"): t["source_url"].getStr().some() else: none(string) ) func metadataAreUpToDate(p: PracticeExerciseConfig; @@ -45,9 +48,9 @@ func update(p: var PracticeExerciseConfig; p.source_url = upstreamMetadata.source_url if upstreamMetadata.blurb.len > 0 and eckBlurb notin p.originalKeyOrder: p.originalKeyOrder.add eckBlurb - if upstreamMetadata.source.len > 0 and eckSource notin p.originalKeyOrder: + if upstreamMetadata.source.isSome() and eckSource notin p.originalKeyOrder: p.originalKeyOrder.add eckSource - if upstreamMetadata.source_url.len > 0 and eckSourceUrl notin p.originalKeyOrder: + if upstreamMetadata.source_url.isSome() and eckSourceUrl notin p.originalKeyOrder: p.originalKeyOrder.add eckSourceUrl proc addUnsynced(configPairs: var seq[PathAndUpdatedConfig]; diff --git a/src/types_exercise_config.nim b/src/types_exercise_config.nim index f5a4802b..13b06c70 100644 --- a/src/types_exercise_config.nim +++ b/src/types_exercise_config.nim @@ -99,8 +99,8 @@ type forked_from*: Option[seq[string]] ## Allowed only for a Concept Exercise. icon*: string ## Allowed only for a Concept Exercise. blurb*: string - source*: string - source_url*: string + source*: Option[string] + source_url*: Option[string] custom*: Option[JsonNode] PracticeExerciseConfig* = object @@ -113,8 +113,8 @@ type # The below fields are synced for a Practice Exercise that exists in the # `exercism/problem-specifications` repo. blurb*: string - source*: string - source_url*: string + source*: Option[string] + source_url*: Option[string] custom*: Option[JsonNode] {.pop.} diff --git a/tests/test_fmt.nim b/tests/test_fmt.nim index 0908d36c..7e74d259 100644 --- a/tests/test_fmt.nim +++ b/tests/test_fmt.nim @@ -150,8 +150,8 @@ proc testFmt = forked_from: some(@["bar/lovely-lasagna"]), icon: "myicon", blurb: "Learn about the basics of Foo by following a lasagna recipe.", - source: "mysource", - source_url: "https://example.com", + source: some("mysource"), + source_url: some("https://example.com"), custom: some(customJson) ) const expected = """{ @@ -228,8 +228,8 @@ proc testFmt = language_versions: ">=1.2.3", test_runner: some(false), blurb: "Write a function that returns the earned points in a single toss of a Darts game.", - source: "Inspired by an exercise created by a professor Della Paolera in Argentina", - source_url: "https://example.com", + source: some("Inspired by an exercise created by a professor Della Paolera in Argentina"), + source_url: some("https://example.com"), custom: some(customJson) ) const expected = """{ diff --git a/tests/test_sync.nim b/tests/test_sync.nim index 813f6b91..4de885ab 100644 --- a/tests/test_sync.nim +++ b/tests/test_sync.nim @@ -41,8 +41,8 @@ proc testSyncCommon = forked_from: some(@["csharp/lucians-luscious-lasagna"]), icon: "", blurb: "Learn about the basics of Elixir by following a lasagna recipe.", - source: "", - source_url: "" + source: none(string), + source_url: none(string) ) let exerciseConfig = parseFile(lasagnaConfigPath, ConceptExerciseConfig) check exerciseConfig == expected @@ -65,8 +65,8 @@ proc testSyncCommon = language_versions: "", test_runner: none(bool), blurb: "Write a function that returns the earned points in a single toss of a Darts game.", - source: "Inspired by an exercise created by a professor Della Paolera in Argentina", - source_url: "" + source: some("Inspired by an exercise created by a professor Della Paolera in Argentina"), + source_url: none(string) ) let exerciseConfig = parseFile(dartsConfigPath, PracticeExerciseConfig) check exerciseConfig == expected @@ -158,8 +158,8 @@ proc testSyncCommon = forked_from: some(@["bar/lovely-lasagna"]), icon: "myicon", blurb: "Learn about the basics of Foo by following a lasagna recipe.", - source: "mysource", - source_url: "https://example.com", + source: some("mysource"), + source_url: some("https://example.com"), custom: some(customJson) ) const expected = """{ @@ -231,8 +231,8 @@ proc testSyncCommon = language_versions: ">=1.2.3", test_runner: some(false), blurb: "Write a function that returns the earned points in a single toss of a Darts game.", - source: "Inspired by an exercise created by a professor Della Paolera in Argentina", - source_url: "https://example.com", + source: some("Inspired by an exercise created by a professor Della Paolera in Argentina"), + source_url: some("https://example.com"), custom: some(customJson) ) const expected = """{ @@ -459,8 +459,8 @@ proc testSyncMetadata = let metadataPath = joinPath(psExercisesDir, "all-your-base", "metadata.toml") const expected = UpstreamMetadata( blurb: "Convert a number, represented as a sequence of digits in one base, to any other base.", - source: "", - source_url: "" + source: none(string), + source_url: none(string) ) let metadata = parseMetadataToml(metadataPath) check metadata == expected @@ -469,8 +469,8 @@ proc testSyncMetadata = let metadataPath = joinPath(psExercisesDir, "darts", "metadata.toml") const expected = UpstreamMetadata( blurb: "Write a function that returns the earned points in a single toss of a Darts game.", - source: "Inspired by an exercise created by a professor Della Paolera in Argentina", - source_url: "" + source: some("Inspired by an exercise created by a professor Della Paolera in Argentina"), + source_url: none(string) ) let metadata = parseMetadataToml(metadataPath) check metadata == expected @@ -479,8 +479,8 @@ proc testSyncMetadata = let metadataPath = joinPath(psExercisesDir, "two-fer", "metadata.toml") const expected = UpstreamMetadata( blurb: """Create a sentence of the form "One for X, one for me.".""", - source: "", - source_url: "https://github.com/exercism/problem-specifications/issues/757" + source: none(string), + source_url: some("https://github.com/exercism/problem-specifications/issues/757") ) let metadata = parseMetadataToml(metadataPath) check metadata == expected @@ -489,8 +489,8 @@ proc testSyncMetadata = let metadataPath = joinPath(psExercisesDir, "collatz-conjecture", "metadata.toml") const expected = UpstreamMetadata( blurb: "Calculate the number of steps to reach 1 using the Collatz conjecture.", - source: "An unsolved problem in mathematics named after mathematician Lothar Collatz", - source_url: "https://en.wikipedia.org/wiki/3x_%2B_1_problem" + source: some("An unsolved problem in mathematics named after mathematician Lothar Collatz"), + source_url: some("https://en.wikipedia.org/wiki/3x_%2B_1_problem") ) let metadata = parseMetadataToml(metadataPath) check metadata == expected @@ -499,8 +499,8 @@ proc testSyncMetadata = let metadataPath = joinPath(psExercisesDir, "etl", "metadata.toml") const expected = UpstreamMetadata( blurb: "We are going to do the `Transform` step of an Extract-Transform-Load.", - source: "The Jumpstart Lab team", - source_url: "http://jumpstartlab.com" + source: some("The Jumpstart Lab team"), + source_url: some("http://jumpstartlab.com") ) let metadata = parseMetadataToml(metadataPath) check metadata == expected @@ -511,13 +511,13 @@ proc testSyncMetadata = suite "update and metadataAreUpToDate": privateAccess(UpstreamMetadata) privateAccess(PracticeExerciseConfig) - const metadata = UpstreamMetadata( - blurb: "This is a really good exercise.", - source: "From a conversation with ee7.", - source_url: "https://example.com" - ) test "updates `blurb`, `source`, and `source_url`": + const metadata = UpstreamMetadata( + blurb: "This is a really good exercise.", + source: some("From a conversation with ee7."), + source_url: some("https://example.com") + ) var p = PracticeExerciseConfig( authors: @["foo"], contributors: some(@["foo"]), @@ -530,8 +530,8 @@ proc testSyncMetadata = language_versions: "", test_runner: none(bool), blurb: "", - source: "", - source_url: "" + source: none(string), + source_url: none(string) ) update(p, metadata) let expected = PracticeExerciseConfig( @@ -547,8 +547,50 @@ proc testSyncMetadata = language_versions: "", test_runner: none(bool), blurb: "This is a really good exercise.", - source: "From a conversation with ee7.", - source_url: "https://example.com" + source: some("From a conversation with ee7."), + source_url: some("https://example.com") + ) + check: + p == expected + metadataAreUpToDate(p, metadata) + + test "removes `source_url` that previously existed": + const metadata = UpstreamMetadata( + blurb: "This is a really good exercise.", + source: some("From a conversation with ee7."), + source_url: none(string) + ) + var p = PracticeExerciseConfig( + authors: @["foo"], + contributors: some(@["foo"]), + files: PracticeExerciseFiles( + solution: @["foo"], + test: @["foo"], + example: @["foo"], + editor: @[] + ), + language_versions: "", + test_runner: none(bool), + blurb: "", + source: some("From a conversation with ee7."), + source_url: some("https://example.com") + ) + update(p, metadata) + let expected = PracticeExerciseConfig( + originalKeyOrder: @[eckBlurb, eckSource], + authors: @["foo"], + contributors: some(@["foo"]), + files: PracticeExerciseFiles( + solution: @["foo"], + test: @["foo"], + example: @["foo"], + editor: @[] + ), + language_versions: "", + test_runner: none(bool), + blurb: "This is a really good exercise.", + source: some("From a conversation with ee7."), + source_url: none(string) ) check: p == expected