Skip to content

Commit

Permalink
Merge pull request #76 from http4s/1.0.0-M38
Browse files Browse the repository at this point in the history
Release v1.0.0-M38 on http4s-core-1.0.0-M38
  • Loading branch information
rossabaker authored Jan 6, 2023
2 parents 861657f + 172ee91 commit 32d4bba
Show file tree
Hide file tree
Showing 12 changed files with 221 additions and 75 deletions.
46 changes: 15 additions & 31 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ name: Continuous Integration

on:
pull_request:
branches: ['**']
branches: ['**', '!update/**', '!pr/**']
push:
branches: ['**']
branches: ['**', '!update/**', '!pr/**']
tags: [v*]

env:
Expand All @@ -29,12 +29,12 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest]
scala: [2.13.8, 3.1.2]
scala: [2.13.8, 3.2.1]
java: [temurin@8, temurin@11, temurin@17]
exclude:
- scala: 3.1.2
- scala: 3.2.1
java: temurin@11
- scala: 3.1.2
- scala: 3.2.1
java: temurin@17
runs-on: ${{ matrix.os }}
steps:
Expand Down Expand Up @@ -104,7 +104,7 @@ jobs:
key: ${{ runner.os }}-sbt-cache-v2-${{ hashFiles('**/*.sbt') }}-${{ hashFiles('project/build.properties') }}

- name: Check that workflows are up to date
run: sbt '++${{ matrix.scala }}' 'project /' githubWorkflowCheck
run: sbt githubWorkflowCheck

- name: Check headers and formatting
if: matrix.java == 'temurin@8'
Expand All @@ -121,17 +121,21 @@ jobs:
if: matrix.java == 'temurin@8'
run: sbt '++${{ matrix.scala }}' doc

- name: Check scalafix lints
if: matrix.java == 'temurin@8' && !startsWith(matrix.scala, '3.')
run: sbt '++${{ matrix.scala }}' 'scalafixAll --check'

- name: Check unused compile dependencies
if: matrix.java == 'temurin@8'
run: sbt '++${{ matrix.scala }}' unusedCompileDependenciesTest

- name: Make target directories
if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main')
run: mkdir -p target scala-xml/target site/target project/target
run: mkdir -p target scala-xml-2/target site/target project/target

- name: Compress target directories
if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main')
run: tar cf targets.tar target scala-xml/target site/target project/target
run: tar cf targets.tar target scala-xml-2/target site/target project/target

- name: Upload target directories
if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main')
Expand Down Expand Up @@ -226,32 +230,12 @@ jobs:
tar xf targets.tar
rm targets.tar
- name: Download target directories (2.13.8)
uses: actions/download-artifact@v2
with:
name: target-${{ matrix.os }}-${{ matrix.java }}-2.13.8

- name: Inflate target directories (2.13.8)
run: |
tar xf targets.tar
rm targets.tar
- name: Download target directories (2.13.8)
uses: actions/download-artifact@v2
with:
name: target-${{ matrix.os }}-${{ matrix.java }}-2.13.8

- name: Inflate target directories (2.13.8)
run: |
tar xf targets.tar
rm targets.tar
- name: Download target directories (3.1.2)
- name: Download target directories (3.2.1)
uses: actions/download-artifact@v2
with:
name: target-${{ matrix.os }}-${{ matrix.java }}-3.1.2
name: target-${{ matrix.os }}-${{ matrix.java }}-3.2.1

- name: Inflate target directories (3.1.2)
- name: Inflate target directories (3.2.1)
run: |
tar xf targets.tar
rm targets.tar
Expand Down
15 changes: 15 additions & 0 deletions .scalafix.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
rules = [
Http4sFs2Linters
Http4sGeneralLinters
Http4sUseLiteralsSyntax
LeakingImplicitClassVal
ExplicitResultTypes
OrganizeImports
]

triggered.rules = [
Http4sFs2Linters
Http4sGeneralLinters
Http4sUseLiteralsSyntax
LeakingImplicitClassVal
]
2 changes: 1 addition & 1 deletion .scalafmt.conf
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version = 3.5.8
version = 3.6.1

style = default

Expand Down
43 changes: 43 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# http4s-scala-xml

Provides http4s entity codec instances for [scala-xml].

## `http4s-scala-xml`

This is probably the artifact you want. It works with scala-xml-2.x.

### SBT coordinates

```scala
libraryDependencies ++= Seq(
"org.http4s" %% "http4s-scala-xml" % http4sScalaXmlV
)
```

## `http4s-scala-xml-1`

This repository also publishes an alternate `http4s-scala-xml-1`
artifact. The Scala package is the same, so this dependency must
never be bundled with `http4s-scala-xml`. It exists because several
signficant libraries, like [Twirl], are still based on scala-xml-1.x
in Scala 2. Use this library to avoid diamond dependencies, but
upgrade when you can.

### SBT coordinates

```scala
libraryDependencies ++= Seq(
"org.http4s" %% "http4s-scala-xml-1" % http4sScalaXmlV
)
```


## Compatibility

| artifact | version | http4s-core | scala-xml | Scala 2.12 | Scala 2.13 | Scala 3 | Status | |
|:-------------------|:--------|:------------|:----------|------------|------------|---------|--------|---|
| http4s-scala-xml | 0.23.x | 0.23.x | 2.x |||| Stable | |
| http4s-scala-xml-1 | 0.23.x | 0.23.x | 1.x |||| Stable | |

[scala-xml]: https://github.com/scala/scala-xml
[twirl]: https://github.com/playframework/twirl
41 changes: 25 additions & 16 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,45 @@ ThisBuild / tlBaseVersion := "1.0"
ThisBuild / developers := List(
tlGitHubDev("rossabaker", "Ross A. Baker")
)
ThisBuild / startYear := Some(2014)

val Scala213 = "2.13.8"
ThisBuild / crossScalaVersions := Seq(Scala213, "3.1.2")
ThisBuild / crossScalaVersions := Seq(Scala213, "3.2.1")
ThisBuild / scalaVersion := Scala213

lazy val root = project.in(file(".")).aggregate(scalaXml).enablePlugins(NoPublishPlugin)
lazy val root = project.in(file(".")).aggregate(scalaXml2).enablePlugins(NoPublishPlugin)

val http4sVersion = "1.0.0-M35"
val http4sVersion = "1.0.0-M38"
val scalacheckXmlVersion = "0.1.0"
val scalaXmlVersion = "2.1.0"
val munitVersion = "0.7.29"
val munitCatsEffectVersion = "1.0.7"
val munitVersion = "1.0.0-M7"
val munitCatsEffectVersion = "2.0.0-M3"

lazy val scalaXml = project
.in(file("scala-xml"))
lazy val scalaXml2 = project
.in(file("scala-xml-2"))
.settings(
name := "http4s-scala-xml",
description := "Provides scala-xml codecs for http4s",
startYear := Some(2014),
libraryDependencies ++= Seq(
"org.http4s" %%% "http4s-core" % http4sVersion,
"org.scala-lang.modules" %%% "scala-xml" % scalaXmlVersion,
"org.scalameta" %%% "munit-scalacheck" % munitVersion % Test,
"org.typelevel" %%% "munit-cats-effect-3" % munitCatsEffectVersion % Test,
"org.http4s" %%% "http4s-laws" % http4sVersion % Test,
),
tlMimaPreviousVersions ++= (0 to 11).map(y => s"0.23.$y").toSet,
libraryDependencies += "org.scala-lang.modules" %%% "scala-xml" % scalaXmlVersion,
commonSettings,
)

lazy val commonSettings = Seq(
Compile / unmanagedSourceDirectories += (LocalRootProject / baseDirectory).value / "scala-xml" / "src" / "main" / "scala",
Test / unmanagedSourceDirectories += (LocalRootProject / baseDirectory).value / "scala-xml" / "src" / "test" / "scala",
libraryDependencies ++= Seq(
"org.http4s" %%% "http4s-core" % http4sVersion,
"org.http4s" %%% "http4s-laws" % http4sVersion % Test,
"org.scalameta" %%% "munit-scalacheck" % munitVersion % Test,
"org.typelevel" %%% "munit-cats-effect" % munitCatsEffectVersion % Test,
"org.typelevel" %%% "scalacheck-xml" % scalacheckXmlVersion % Test,
),
)

lazy val docs = project
.in(file("site"))
.dependsOn(scalaXml)
.dependsOn(scalaXml2)
.settings(
libraryDependencies ++= Seq(
"org.http4s" %%% "http4s-dsl" % http4sVersion,
Expand Down
4 changes: 2 additions & 2 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class JsonXmlHttpEndpoint[F[_]](implicit F: Async[F]) extends Http4sDsl[F] {
}

private def personXmlDecoder: EntityDecoder[F, Person] =
org.http4s.scalaxml.xml[F].map(Person.fromXml)
org.http4s.scalaxml.xmlDecoder[F].map(Person.fromXml)

implicit private def jsonXmlDecoder: EntityDecoder[F, Person] =
jsonOf[F, Person].orElse(personXmlDecoder)
Expand All @@ -55,4 +55,4 @@ class JsonXmlHttpEndpoint[F[_]](implicit F: Async[F]) extends Http4sDsl[F] {
}
}
}
```
```
2 changes: 1 addition & 1 deletion project/build.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
sbt.version=1.6.2
sbt.version=1.8.1
2 changes: 1 addition & 1 deletion project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
addSbtPlugin("org.http4s" % "sbt-http4s-org" % "0.13.4")
addSbtPlugin("org.http4s" % "sbt-http4s-org" % "0.14.7")
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2014 http4s.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.http4s.scalaxml

import scala.xml._
import scala.xml.transform._

trait ScalaXmlSuiteVersion {
object stripComments extends RewriteRule {
override def transform(n: Node): Seq[Node] =
n match {
case _: Comment => Seq.empty
case n => Seq(n)
}
}

object trimProper extends RewriteRule {
override def transform(n: Node): Seq[Node] =
Utility.trimProper(n)
}

// https://github.com/http4s/http4s-scala-xml/issues/32
object normalize extends RuleTransformer(stripComments, trimProper)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright 2014 http4s.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.http4s.scalaxml

import scala.xml.transform._

trait ScalaXmlSuiteVersion {
// https://github.com/http4s/http4s-scala-xml/issues/32
//
// Nothing to do here but make the tests compatible with
// scala-xml-1's parser.
object normalize extends RuleTransformer()
}
30 changes: 28 additions & 2 deletions scala-xml/src/main/scala/org/http4s/scalaxml/ElemInstances.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@
package org.http4s
package scalaxml

import cats.data.EitherT
import cats.effect.Async
import cats.effect.Concurrent
import cats.syntax.all._
import fs2.io.toInputStreamResource
import org.http4s.Charset.`UTF-8`
import org.http4s.headers.`Content-Type`

Expand All @@ -33,7 +37,7 @@ import scala.xml.XML
trait ElemInstances {
protected def saxFactory: SAXParserFactory

implicit def xmlEncoder(implicit charset: Charset = `UTF-8`): EntityEncoder.Pure[Elem] =
implicit def xmlEncoder[F[_]](implicit charset: Charset = `UTF-8`): EntityEncoder[F, Elem] =
EntityEncoder.stringEncoder
.contramap[Elem] { node =>
val sw = new StringWriter
Expand All @@ -48,7 +52,8 @@ trait ElemInstances {
*
* @return an XML element
*/
implicit def xml[F[_]](implicit F: Concurrent[F]): EntityDecoder[F, Elem] = {
@deprecated("Blocks. Use xmlDecoder with an Async constraint.", "0.23.12")
def xml[F[_]](implicit F: Concurrent[F]): EntityDecoder[F, Elem] = {
import EntityDecoder._
decodeBy(MediaType.text.xml, MediaType.text.html, MediaType.application.xml) { msg =>
val source = new InputSource()
Expand All @@ -66,4 +71,25 @@ trait ElemInstances {
}
}
}

implicit def xmlDecoder[F[_]](implicit F: Async[F]): EntityDecoder[F, Elem] = {
import EntityDecoder._
decodeBy(MediaType.text.xml, MediaType.text.html, MediaType.application.xml) { msg =>
val source = new InputSource()
msg.charset.foreach(cs => source.setEncoding(cs.nioCharset.name))

EitherT(
toInputStreamResource(msg.body)
.use { in =>
source.setByteStream(in)
val saxParser = saxFactory.newSAXParser()
F.blocking(XML.loadXML(source, saxParser))
}
.map(Either.right[DecodeFailure, Elem](_))
.recover { case e: SAXParseException =>
Left(MalformedMessageBodyFailure("Invalid XML", Some(e)))
}
)
}
}
}
Loading

0 comments on commit 32d4bba

Please sign in to comment.