Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

changes to generate next edition via cli using directory RSS feed #31

Merged
merged 5 commits into from
Dec 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 23 additions & 23 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
matrix:
os: [ubuntu-latest]
scala: [2.13.12]
java: [temurin@17]
java: [corretto@21]
project: [rootJVM]
runs-on: ${{ matrix.os }}
steps:
Expand All @@ -38,21 +38,21 @@ jobs:
with:
fetch-depth: 0

- name: Download Java (temurin@17)
id: download-java-temurin-17
if: matrix.java == 'temurin@17'
- name: Download Java (corretto@21)
id: download-java-corretto-21
if: matrix.java == 'corretto@21'
uses: typelevel/download-java@v1
with:
distribution: temurin
java-version: 17
distribution: corretto
java-version: 21

- name: Setup Java (temurin@17)
if: matrix.java == 'temurin@17'
- name: Setup Java (corretto@21)
if: matrix.java == 'corretto@21'
uses: actions/setup-java@v2
with:
distribution: jdkfile
java-version: 17
jdkFile: ${{ steps.download-java-temurin-17.outputs.jdkFile }}
java-version: 21
jdkFile: ${{ steps.download-java-corretto-21.outputs.jdkFile }}

- name: Cache sbt
uses: actions/cache@v2
Expand All @@ -70,18 +70,18 @@ jobs:
run: sbt githubWorkflowCheck

- name: Check headers and formatting
if: matrix.java == 'temurin@17'
if: matrix.java == 'corretto@21'
run: sbt 'project ${{ matrix.project }}' '++ ${{ matrix.scala }}' headerCheckAll scalafmtCheckAll 'project /' scalafmtSbtCheck

- name: Test
run: sbt 'project ${{ matrix.project }}' '++ ${{ matrix.scala }}' test

- name: Check binary compatibility
if: matrix.java == 'temurin@17'
if: matrix.java == 'corretto@21'
run: sbt 'project ${{ matrix.project }}' '++ ${{ matrix.scala }}' mimaReportBinaryIssues

- name: Generate API documentation
if: matrix.java == 'temurin@17'
if: matrix.java == 'corretto@21'
run: sbt 'project ${{ matrix.project }}' '++ ${{ matrix.scala }}' doc

site:
Expand All @@ -90,29 +90,29 @@ jobs:
matrix:
os: [ubuntu-latest]
scala: [2.13.12]
java: [temurin@17]
java: [corretto@21]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout current branch (full)
uses: actions/checkout@v2
with:
fetch-depth: 0

- name: Download Java (temurin@17)
id: download-java-temurin-17
if: matrix.java == 'temurin@17'
- name: Download Java (corretto@21)
id: download-java-corretto-21
if: matrix.java == 'corretto@21'
uses: typelevel/download-java@v1
with:
distribution: temurin
java-version: 17
distribution: corretto
java-version: 21

- name: Setup Java (temurin@17)
if: matrix.java == 'temurin@17'
- name: Setup Java (corretto@21)
if: matrix.java == 'corretto@21'
uses: actions/setup-java@v2
with:
distribution: jdkfile
java-version: 17
jdkFile: ${{ steps.download-java-temurin-17.outputs.jdkFile }}
java-version: 21
jdkFile: ${{ steps.download-java-corretto-21.outputs.jdkFile }}

- name: Cache sbt
uses: actions/cache@v2
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
next/next.md

# sbt
target/
project/plugins/project/
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ For more information have a look at our [about us](docs/Resources/About.md)

## How to contribute Links

Create a PR adding your link to [next/next.md](next/next.md). This is the file that will get published next.
Add yourself with details of your rss path to our directory (see next section below) of bloggers and your articles will automatically be included in our next edition of Scala News.


## Do you have a Scala related Blog? Want to add it in our [Blog Directory](docs/Resources/Blog_Directory.md)?

Expand Down
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ ThisBuild / githubWorkflowPublishTargetBranches := Seq()
// publish website from this branch
ThisBuild / tlSitePublishBranch := Some("main")

ThisBuild / githubWorkflowJavaVersions := Seq(JavaSpec.temurin("17"))
ThisBuild / githubWorkflowJavaVersions := Seq(JavaSpec.corretto("21"))

val Scala213 = "2.13.12"
ThisBuild / crossScalaVersions := Seq(Scala213)
Expand Down
2 changes: 1 addition & 1 deletion config.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
{
"name": "Alexandru Nedelcu",
"url": "https://alexn.org/blog/",
"rss": "https://alexn.org/feeds/all.xml"
"rss": "https://alexn.org/feeds/blog.xml"
},
{
"name": "Jakub Kozłowski",
Expand Down
67 changes: 58 additions & 9 deletions core/src/main/scala/com/softinio/scalanews/Bloggers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,14 @@ import java.util.Date
import cats.effect._
import cats.nio.file.Files
import com.rometools.rome.feed.synd.SyndEntry
import org.http4s.Uri

import scala.jdk.CollectionConverters._
import com.softinio.scalanews.algebra.Article
import com.softinio.scalanews.algebra.Blog

object Bloggers {
private val nextMarkdownFilePath =
Paths.get("next/next.md")
private val directoryMarkdownFilePath =
Paths.get("docs/Resources/Blog_Directory.md")
def generateDirectory(bloggerList: List[Blog]): IO[String] = {
Expand Down Expand Up @@ -57,7 +58,31 @@ object Bloggers {
}
}

def generateNews(articleList: List[Article]): IO[String] = {
IO.blocking {
val header = """
|# Scala News

|A curated list of Scala related news from the community.

|## Articles

|| Article | Author |
|| ------------- | -----:|"""

val news = articleList.map { article =>
s"|| [${article.title}](${article.url}) | ${article.author} |"
}

s"""
$header
${news.mkString("\n")}
""".stripMargin
}
}

private def getArticlesFromEntries(
blog: Blog,
entries: List[SyndEntry],
startDate: Date,
endDate: Date
Expand All @@ -67,15 +92,21 @@ object Bloggers {
.filter(_.getLink != null)
.filter(_.getTitle != null)
.map { entry =>
Article(
entry.getTitle,
Uri
.fromString(entry.getLink)
.getOrElse(Uri.unsafeFromString("https://www.scala-lang.org/")),
entry.getPublishedDate
)
{
val blogAuthor = Option(entry.getAuthor)
.filter(!_.isEmpty)
.filter(_.toLowerCase() != "unknown")
.getOrElse(blog.name)

Article(
entry.getTitle,
entry.getLink,
blogAuthor,
entry.getPublishedDate
)
}
}
.filter { case Article(_, _, publishedDate) =>
.filter { case Article(_, _, _, publishedDate) =>
publishedDate.after(startDate) && publishedDate.before(endDate)
}
.distinct
Expand All @@ -94,6 +125,7 @@ object Bloggers {
feedResult <- Rome.fetchFeed(blog.rss.toURL.toString)
} yield {
getArticlesFromEntries(
blog,
feedResult
.map(_.getEntries.asScala.toList)
.getOrElse(List[SyndEntry]()),
Expand Down Expand Up @@ -126,4 +158,21 @@ object Bloggers {
)
} yield ExitCode.Success
}

def generateNextBlog(
startDate: Date,
endDate: Date
): IO[ExitCode] = {
for {
exists <- Files[IO].exists(nextMarkdownFilePath)
_ <- if (exists) Files[IO].delete(nextMarkdownFilePath) else IO.unit
articleList <- createBlogList(startDate, endDate)
news <- generateNews(articleList)
_ <- Files[IO].write(
nextMarkdownFilePath,
news.getBytes(),
StandardOpenOption.CREATE_NEW
)
} yield ExitCode.Success
}
}
52 changes: 40 additions & 12 deletions core/src/main/scala/com/softinio/scalanews/Main.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package com.softinio.scalanews

import java.text.SimpleDateFormat

import cats.effect._
import cats.implicits._

Expand All @@ -38,10 +40,25 @@ object Main

case class Blogger(directory: Boolean)

case class GenerateNextBlog(
startDate: String,
endDate: String
)

val dateFormatter = new SimpleDateFormat("yyyy-MM-dd")

val archiveDateOps: Opts[String] =
Opts
.argument[String](metavar = "archiveDate")

val startDateOps: Opts[String] =
Opts
.argument[String](metavar = "startDate")

val endDateOps: Opts[String] =
Opts
.argument[String](metavar = "endDate")

val publishDateOps: Opts[Option[String]] =
Opts
.option[String](
Expand Down Expand Up @@ -81,18 +98,29 @@ object Main
.map(Blogger)
}

val generateNextBlogOpts: Opts[GenerateNextBlog] =
Opts.subcommand("generate", "Generate next blog") {
(startDateOps, endDateOps).mapN(GenerateNextBlog)
}

override def main: Opts[IO[ExitCode]] =
(publishOpts orElse createOpts orElse bloggerOpts).map {
case Publish(publishDate, archiveDate, archiveFolder) =>
FileHandler.publish(publishDate, archiveDate, archiveFolder)
case Create(overwrite) => FileHandler.create(overwrite)
case Blogger(directory) => {
if (directory) {
for {
config <- ConfigLoader.load()
result <- Bloggers.createBloggerDirectory(config.bloggers)
} yield (result)
} else IO(ExitCode.Success)
(publishOpts orElse createOpts orElse generateNextBlogOpts orElse bloggerOpts)
.map {
case Publish(publishDate, archiveDate, archiveFolder) =>
FileHandler.publish(publishDate, archiveDate, archiveFolder)
case Create(overwrite) => FileHandler.create(overwrite)
case GenerateNextBlog(startDate, endDate) =>
Bloggers.generateNextBlog(
dateFormatter.parse(startDate),
dateFormatter.parse(endDate)
)
case Blogger(directory) => {
if (directory) {
for {
config <- ConfigLoader.load()
result <- Bloggers.createBloggerDirectory(config.bloggers)
} yield (result)
} else IO(ExitCode.Success)
}
}
}
}
14 changes: 13 additions & 1 deletion core/src/main/scala/com/softinio/scalanews/algebra/Article.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,16 @@ package com.softinio.scalanews.algebra
import java.util.Date
import org.http4s.Uri

case class Article(title: String, url: Uri, publishedDate: Date)
case class Article(title: String, url: Uri, author: String, publishedDate: Date)

object Article {
def apply(
title: String,
url: String,
author: String,
publishedDate: Date
): Article = {
val parsedUrl = Uri.fromString(url).toOption.get
Article(title, parsedUrl, author, publishedDate)
}
}
12 changes: 5 additions & 7 deletions docs/Resources/About.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,26 @@

Hi Everyone and Welcome to Scala's latest resource to keep up with the news of what's happening around the Scala community.

What makes this resource unique is that every edition of it will be crowd sourced. Yes that means I need everyones help to contribute links to include in the next edition of the newsletter by submitting a PR.

## Why Did I create this

There where multiple reasons, some of which where as follows:

- I want to see more people write more long form blogs and articles, so this is my bit to help your writings to be discovered. I have even added a page to serve as a blog directory with a link to a bloggers website and rss feed. Let's bring back the google reader days all and write more blogs and spend less time on social media :-)
- I wanted an excuse to use [Laika](https://planet42.github.io/Laika/) via [sbt-typelevel](https://typelevel.org/sbt-typelevel/) to see what it's like.
- As a bonus, I wanted a resource to get a list of links to latest information that is not on medium or behind a pay wall and we can all contribute to it via a PR on GitHub.
- As a bonus, I wanted a resource to get a list of links to latest information that is not on medium or behind a pay wall.

## Will this site be successful?

- I need everyone in the community to contribute links as I don't have time to do it alone, So please contribute.
- I need everyone in the community to write blogs, have their blog support rss and add themselves to our bloggers directory.
- Hopefully with time everyone will be using their preferred rss reader to follow the bloggers they like and there won't be any need for this site so that its success is measured by it being archived as not needed or just being there to serve as a directory of Scala bloggers to follow using rss.

## How Do I add a link to be included in the next edition?
## How do I add my Blog to the Blog Directory?

See [README](https://github.com/softinio/scalanews/blob/main/README.md) for details.

## How do I add my Blog to the Blog Directory?
## How Do I add a link to be included in the next edition?

See [README](https://github.com/softinio/scalanews/blob/main/README.md) for details.
Just add your blog to our blog directory. All editions of Scala News are autogenerated using the RSS feeds of all bloggers listed in our directory.

## What kind of links will be published?

Expand Down
Loading
Loading