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

Update to Scalafmt 3.8.3 #1631

Merged
merged 3 commits into from
Oct 29, 2024

Conversation

mbland
Copy link
Contributor

@mbland mbland commented Oct 23, 2024

Description

Ensures that all Scalafmt targets succeed under every supported Scala version. Part of #1482.

Scala 2.11 remains on Scalafmt 2.7.5, since there's not a more recent compatible version.

Between 3.0.0 and 3.8.3, Scalafmt's FileOps moved packages, Config.fromHoconFile moved to ScalafmtConfig, and the methods now take a java.nio.file.Path parameter. As a result, this required extracting a thin ScalafmtAdapter object, with one implementation for Scala 2.11 and Scalafmt 2.7.5, and one for Scalafmt 3.8.3.

This change also adds the file path to the Scalafmt.format() call, allowing error messages to show the actual file path instead of <input>.

Removed the verticalMultiline.newlineBeforeImplicitKW = true and unindentTopLevelOperators = false options from .scalafmt.conf. They don't appear to be available in Scalafmt 3.8.3.

Also removes some @io_bazel_rules_scala references to make the internal implementation less dependendent on that name. This will allow Bzlmod clients to use rules_scala in a bazel_dep() without setting repo_name = "io_bazel_rules_scala".

Motivation

Scalafmt 3.0.0 works with the current default Scala version 2.12.19, but breaks under Scala 2.13.14:

$ bazel test --repo_env=SCALA_VERSION=2.13.14 //test/scalafmt/...

ERROR: .../test/scalafmt/BUILD:49:20:
  ScalaFmt test/scalafmt/test/scalafmt/unformatted/unformatted-test.scala.fmt.output
  failed: (Exit 1): scalafmt failed: error executing command
  (from target //test/scalafmt:unformatted-test)
  bazel-out/darwin_arm64-opt-exec-2B5CBBC6/bin/scala/scalafmt/scalafmt
  '--jvm_flag=-Dfile.encoding=UTF-8' ... (remaining 1 argument skipped)

java.util.NoSuchElementException: last of empty IndexedSeq
    at scala.collection.IndexedSeqOps.last(IndexedSeq.scala:110)
    at scala.collection.IndexedSeqOps.last$(IndexedSeq.scala:105)
    at scala.meta.tokens.Tokens.last(Tokens.scala:29)
    at org.scalafmt.internal.Router.$anonfun$getSplitsImpl$90(Router.scala:707)
    at scala.Option.map(Option.scala:242)
    at org.scalafmt.internal.Router.getSplitsImpl(Router.scala:706)
    at org.scalafmt.internal.Router.getSplits(Router.scala:2314)
    at org.scalafmt.internal.BestFirstSearch.$anonfun$routes$1(BestFirstSearch.scala:38)
    [ ...snip... ]

This matches:

Which mentions apparent fixes in:

So the fix was to upgrade the Scalafmt version. That said, I held its Scalameta dependencies to 4.9.9 per the following link, even though 4.10.2 is out now.


This change updates Scalameta to version 4.9.9 because between 4.9.9 and 4.10.2, Scalafmt breaks Scala 3 file formatting by unindenting some code that it shouldn't. Or, our usage of it breaks somehow; I can't find any open or closed issues in the Scalameta project that matches what happes in rules_scala. (Perhaps I can file one eventually.)

The solution was to keep the Scalameta dependencies at 4.9.9. FWIW, this was one of the most time consuming bugs to pinpoint and rectify in the entire Bzlmodification process.

This was the failing command inside test_cross_version:

$ bazel run //scalafmt:unformatted-test3.format-test

INFO: Analyzed target //scalafmt:unformatted-test3.format-test
  (0 packages loaded, 0 targets configured).
INFO: From ScalaFmt scalafmt/scalafmt/unformatted/unformatted-test3.scala.fmt.output:

The test_cross_version/scalafmt/unformatted/unformatted-test3.scala file formatted by this test target looks like this:

import org.scalatest.flatspec._

class Test extends
  AnyFlatSpec:

        "Test"  should  "be formatted" in  {
     assert(true)
        }

I hacked ScalaWorker.format() to print the code variable, and could see that after the first Scalafmt.format() pass, the code looks like this:

import org.scalatest.flatspec._

class Test extends AnyFlatSpec:

"Test" should "be formatted" in {
  assert(true)
}

Since the result doesn't match the original code, it tries to call Scalafmt.format() again on this "formatted" code with the incorrect indentation. That's when we get the following, which doesn't look anything like the original file:

Unable to format file due to bug in scalafmt
scalafmt/unformatted/unformatted-test3.scala:3:
  error: [dialect scala3 [with overrides]] `;` expected but `:` found
class Test extends AnyFlatSpec:
                              ^

As it turns out, bumping to com.google.protobuf:protobuf-java:4.28.2 alone (#1624) breaks the bump to Scalafmt 3.8.3. Then bumping to rules_proto 6.0.2, with the separate protobuf v21.7 (#1623), fixes it, presumably by recompiling protoc.

The in-between breakage happened in the test_cross_build project:

$ bazel build //scalafmt:formatted-binary2

INFO: Analyzed target //scalafmt:formatted-binary2
  (4 packages loaded, 64 targets configured).
ERROR: .../test_cross_build/scalafmt/BUILD:59:22:
  ScalaFmt scalafmt/scalafmt/formatted/formatted-binary2.scala.fmt.output
  failed: Worker process did not return a WorkResponse:

---8<---8<--- Start of log, file at .../bazel-workers/worker-3-ScalaFmt.log ---8<---8<---
Exception in thread "main" java.lang.NoSuchMethodError:
  'void com.google.devtools.build.lib.worker.WorkerProtocol$WorkRequest.makeExtensionsImmutable()'
    at com.google.devtools.build.lib.worker.WorkerProtocol$WorkRequest.<init>(WorkerProtocol.java:1029)
    at com.google.devtools.build.lib.worker.WorkerProtocol$WorkRequest.<init>(WorkerProtocol.java:922)
    at com.google.devtools.build.lib.worker.WorkerProtocol$WorkRequest$1.parsePartialFrom(WorkerProtocol.java:2482)
    at com.google.devtools.build.lib.worker.WorkerProtocol$WorkRequest$1.parsePartialFrom(WorkerProtocol.java:2476)
    at com.google.protobuf.AbstractParser.parsePartialFrom(AbstractParser.java:192)
    at com.google.protobuf.AbstractParser.parsePartialDelimitedFrom(AbstractParser.java:232)
    at com.google.protobuf.AbstractParser.parseDelimitedFrom(AbstractParser.java:244)
    at com.google.protobuf.AbstractParser.parseDelimitedFrom(AbstractParser.java:249)
    at com.google.protobuf.AbstractParser.parseDelimitedFrom(AbstractParser.java:25)
    at com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException(GeneratedMessage.java:367)
    at com.google.devtools.build.lib.worker.WorkerProtocol$WorkRequest.parseDelimitedFrom(WorkerProtocol.java:1438)
    at io.bazel.rulesscala.worker.Worker.persistentWorkerMain(Worker.java:81)
    at io.bazel.rulesscala.worker.Worker.workerMain(Worker.java:49)
    at io.bazel.rules_scala.scalafmt.ScalafmtWorker$.main(ScalafmtWorker.scala:12)
    at io.bazel.rules_scala.scalafmt.ScalafmtWorker.main(ScalafmtWorker.scala)
---8<---8<--- End of log ---8<---8<---
Target //scalafmt:formatted-binary2 failed to build

rewrite.redundantBraces.stringInterpolation = true
rewrite.rules = [
RedundantParens,
PreferCurlyFors,
SortImports
]
unindentTopLevelOperators = false
lineEndings=preserve
lineEndings = preserve
Copy link
Contributor

@WojciechMazur WojciechMazur Oct 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unindentTopLevelOperators can be probably replaced with indentOperator.topLevelOnly. AFAIR it worked good enough in one project I was migrating in the past from scalafmt 2.7.5 -> 3.8.1

Suggested change
lineEndings = preserve
indentOperator.topLevelOnly = true
lineEndings = preserve

In that case we were having a bit reverse direction: unindentTopLevelOperators = true into indentOperator.topLevelOnly = false

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, thanks! Done

@@ -1,16 +1,15 @@
runner.dialect = scala213
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be worthy to add version = "3.8.3" so it's easier to check which version of scalamft we require.

Suggested change
runner.dialect = scala213
version = "3.8.3"
runner.dialect = scala213

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, here and in the other .scalafmt.conf files.

Heh, I had version = "3.8.3" in at some point in my bzlmod working branch, because Scalafmt failed without it. Then I took it out here because it didn't seem required. But I do like the explicitness of it.

@WojciechMazur
Copy link
Contributor

If you've used the scripts/create_repositories.py to update dependencies then scalameta_version defined there should also be updated.
Also, I can see Scala version updates. Consider merging #1636 before so we can separate these two upgrades.

mbland added a commit to mbland/rules_scala that referenced this pull request Oct 23, 2024
@mbland
Copy link
Contributor Author

mbland commented Oct 24, 2024

@WojciechMazur I didn't use scripts/create_repositories.py, actually—I didn't see that land in #1607 until after I'd tweaked these files by hand. I'm a little scared to try it on the Scalafmt deps, because as mentioned in the description, I locked it to Scalameta 4.9.9 because 4.10.x breaks Scala 3 formatting, and I don't know exactly why. (If you have a tip, or a workaround, I'm all ears.)

That said, I'll checkout a new branch and give it a try, see what happens. I'm also going to prepare another local test branch rebased on #1636 to have it ready. It does seem like it'd be easier to land #1636, then this one.

@mbland
Copy link
Contributor Author

mbland commented Oct 24, 2024

Wow, rebasing on #1636 worked perfectly, with all tests passing, as well as bazel test --repo_env=SCALA_VERSION=2.13.15 //test/scalafmt/.... I do need to bump the Scala 2 libs in the scala_3_{1,2,3,4,5}.bzl files to 2.13.15 (they're still 2.13.14 right now), but that's a piece of cake.

Since the rebase was so easy, I definitely think #1636 should go in first.

mbland added a commit to mbland/rules_scala that referenced this pull request Oct 24, 2024
mbland added a commit to mbland/rules_scala that referenced this pull request Oct 24, 2024
Brings all the Scalafmt 3.8.3 updates from bazelbuild#1631 up to date with the
Scala version bumps from bazelbuild#1636.
mbland added a commit to mbland/rules_scala that referenced this pull request Oct 24, 2024
Ran at the suggestion of @WojciechMazur in bazelbuild#1631.

After running the script, I selected these specific changes with `git
add -p`. I was pleased that the script left the Scalameta deps at
version 4.9.9, and it bumped the Scalatest versions appropriately.

However, there were a number of downgrades and updates to the Scala 2
`deps` in the Scala 3 files that I didn't accept. I'll include them in
the next commit on this branch, but do _not_ merge them.
mbland added a commit to mbland/rules_scala that referenced this pull request Oct 24, 2024
As mentioned in the previous commit, this was the output I rejected from
running `scripts/create_repository.py`.

These deps were downgraded:

- protobuf-java: 4.28.2 to 3.8.0 or 3.7.0
- scalap: from latest Scala version to an earlier version, including
  2.13.14 to 2.13.11
- com.lihaoyi.pprint: from pprint_3:0.9.0 to pprint_2.13:0.6.4
- compiler-interface: 1.10.1 to 1.3.5 or 1.9.6
- com.lihaoyi.geny: from geny_3:1.1.1 to geny_2.13:0.6.5

Plus, all the `@io_bazel_rules_scala_scala_*_2` deps explicitly added to
the `scala_3_{1,2,3,4,5}.bzl` files in bazelbuild#1631 for Scalafmt were stripped
of the `_2` suffix.
@mbland
Copy link
Contributor Author

mbland commented Oct 24, 2024

I've created a new mbland/rules_scala/bzlmod-update-scalafmt-deps-after-scala-versions-update branch with commits representing:

The commit for the successful create_repository.py run passed the Scalafmt tests from ./test_cross_version.sh. The unsuccessful run crashed with the error described in #1624 before the protobuf-java 4.28.2 update.

So I'll be happy to rebase this PR after #1636 lands, and cherry-pick the second and third commits above into it. But I don't yet know what to suggest regarding the downgrades from the last commit.

mbland added a commit to mbland/rules_scala that referenced this pull request Oct 24, 2024
@simuons
Copy link
Collaborator

simuons commented Oct 25, 2024

Hi, @mbland, just want to let you know that #1636 was merged.

Ensures that all Scalafmt targets succeed under every supported Scala
version. Part of bazelbuild#1482.

Scala 2.11 remains on Scalafmt 2.7.5, since there's not a more recent
compatible version.

Between 3.0.0 and 3.8.3, Scalafmt's `FileOps` moved packages,
`Config.fromHoconFile` moved to `ScalafmtConfig`, and the methods now
take a `java.nio.file.Path` parameter. As a result, this required
extracting a thin `ScalafmtAdapter` object, with one implementation for
Scala 2.11 and Scalafmt 2.7.5, and one for Scalafmt 3.8.3.

This change also adds the file path to the `Scalafmt.format()` call,
allowing error messages to show the actual file path instead of
`<input>`.

Removed the `verticalMultiline.newlineBeforeImplicitKW = true` and
`unindentTopLevelOperators = false` options from `.scalafmt.conf`.
They don't appear to be available in Scalafmt 3.8.3.

Also removes some `@io_bazel_rules_scala` references to make the
internal implementation less dependendent on that name. This will allow
Bzlmod clients to use `rules_scala` in a `bazel_dep()` without setting
`repo_name = "io_bazel_rules_scala"`.

---

Scalafmt 3.0.0 works with the current default Scala version 2.12.19,
but breaks under Scala 2.13.14:

```txt
$ bazel test --repo_env=SCALA_VERSION=2.13.14 //test/scalafmt/...

ERROR: .../test/scalafmt/BUILD:49:20:
  ScalaFmt test/scalafmt/test/scalafmt/unformatted/unformatted-test.scala.fmt.output
  failed: (Exit 1): scalafmt failed: error executing command
  (from target //test/scalafmt:unformatted-test)
  bazel-out/darwin_arm64-opt-exec-2B5CBBC6/bin/scala/scalafmt/scalafmt
  '--jvm_flag=-Dfile.encoding=UTF-8' ... (remaining 1 argument skipped)

java.util.NoSuchElementException: last of empty IndexedSeq
    at scala.collection.IndexedSeqOps.last(IndexedSeq.scala:110)
    at scala.collection.IndexedSeqOps.last$(IndexedSeq.scala:105)
    at scala.meta.tokens.Tokens.last(Tokens.scala:29)
    at org.scalafmt.internal.Router.$anonfun$getSplitsImpl$90(Router.scala:707)
    at scala.Option.map(Option.scala:242)
    at org.scalafmt.internal.Router.getSplitsImpl(Router.scala:706)
    at org.scalafmt.internal.Router.getSplits(Router.scala:2314)
    at org.scalafmt.internal.BestFirstSearch.$anonfun$routes$1(BestFirstSearch.scala:38)
    [ ...snip... ]
```

This matches:

- scala/community-build#1680

Which mentions apparent fixes in:

- scalameta/scalameta#3235
- scalameta/scalafmt#3581

So the fix was to upgrade the Scalafmt version. That said, I held its
Scalameta dependencies to 4.9.9 per the following link, even though
4.10.2 is out now.

- https://mvnrepository.com/artifact/org.scalameta/scalafmt-core_2.13/3.8.3

---

This change updates Scalameta to version 4.9.9 because between 4.9.9 and
4.10.2, Scalafmt breaks Scala 3 file formatting by unindenting some code
that it shouldn't. Or, our usage of it breaks somehow; I can't find any
open or closed issues in the Scalameta project that matches what happes
in rules_scala. (Perhaps I can file one eventually.)

- https://github.com/scalameta/scalafmt/issues

The solution was to keep the Scalameta dependencies at 4.9.9. FWIW, this
was one of the most time consuming bugs to pinpoint and rectify in the
entire Bzlmodification process.

This was the failing command inside `test_cross_version`:

```txt
$ bazel run //scalafmt:unformatted-test3.format-test

INFO: Analyzed target //scalafmt:unformatted-test3.format-test
  (0 packages loaded, 0 targets configured).
INFO: From ScalaFmt scalafmt/scalafmt/unformatted/unformatted-test3.scala.fmt.output:
```

The `test_cross_version/scalafmt/unformatted/unformatted-test3.scala`
file formatted by this test target looks like this:

```scala
import org.scalatest.flatspec._

class Test extends
  AnyFlatSpec:

        "Test"  should  "be formatted" in  {
     assert(true)
        }
```

I hacked `ScalaWorker.format()` to print the `code` variable, and could
see that  after the first `Scalafmt.format()` pass, the code looks like
this:

```scala
import org.scalatest.flatspec._

class Test extends AnyFlatSpec:

"Test" should "be formatted" in {
  assert(true)
}
```

Since the result doesn't match the original code, it tries to call
`Scalafmt.format()` again on this "formatted" code with the incorrect
indentation. That's when we get the following, which doesn't look
anything like the original file:

```txt
Unable to format file due to bug in scalafmt
scalafmt/unformatted/unformatted-test3.scala:3:
  error: [dialect scala3 [with overrides]] `;` expected but `:` found
class Test extends AnyFlatSpec:
                              ^
```

---

As it turns out, bumping to com.google.protobuf:protobuf-java:4.28.2
alone breaks the bump to Scalafmt 3.8.3. Then bumping to rules_proto
6.0.2, with the separate protobuf v21.7, fixes it, presumably by
recompiling `protoc`.

The in-between breakage happened in the `test_cross_build` project:

```txt
$ bazel build //scalafmt:formatted-binary2

INFO: Analyzed target //scalafmt:formatted-binary2
  (4 packages loaded, 64 targets configured).
ERROR: .../test_cross_build/scalafmt/BUILD:59:22:
  ScalaFmt scalafmt/scalafmt/formatted/formatted-binary2.scala.fmt.output
  failed: Worker process did not return a WorkResponse:

---8<---8<--- Start of log, file at .../bazel-workers/worker-3-ScalaFmt.log ---8<---8<---
Exception in thread "main" java.lang.NoSuchMethodError:
  'void com.google.devtools.build.lib.worker.WorkerProtocol$WorkRequest.makeExtensionsImmutable()'
    at com.google.devtools.build.lib.worker.WorkerProtocol$WorkRequest.<init>(WorkerProtocol.java:1029)
    at com.google.devtools.build.lib.worker.WorkerProtocol$WorkRequest.<init>(WorkerProtocol.java:922)
    at com.google.devtools.build.lib.worker.WorkerProtocol$WorkRequest$1.parsePartialFrom(WorkerProtocol.java:2482)
    at com.google.devtools.build.lib.worker.WorkerProtocol$WorkRequest$1.parsePartialFrom(WorkerProtocol.java:2476)
    at com.google.protobuf.AbstractParser.parsePartialFrom(AbstractParser.java:192)
    at com.google.protobuf.AbstractParser.parsePartialDelimitedFrom(AbstractParser.java:232)
    at com.google.protobuf.AbstractParser.parseDelimitedFrom(AbstractParser.java:244)
    at com.google.protobuf.AbstractParser.parseDelimitedFrom(AbstractParser.java:249)
    at com.google.protobuf.AbstractParser.parseDelimitedFrom(AbstractParser.java:25)
    at com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException(GeneratedMessage.java:367)
    at com.google.devtools.build.lib.worker.WorkerProtocol$WorkRequest.parseDelimitedFrom(WorkerProtocol.java:1438)
    at io.bazel.rulesscala.worker.Worker.persistentWorkerMain(Worker.java:81)
    at io.bazel.rulesscala.worker.Worker.workerMain(Worker.java:49)
    at io.bazel.rules_scala.scalafmt.ScalafmtWorker$.main(ScalafmtWorker.scala:12)
    at io.bazel.rules_scala.scalafmt.ScalafmtWorker.main(ScalafmtWorker.scala)
---8<---8<--- End of log ---8<---8<---
Target //scalafmt:formatted-binary2 failed to build
```
Brings all the Scalafmt 3.8.3 updates from bazelbuild#1631 up to date with the
Scala version bumps from bazelbuild#1636.
@mbland mbland force-pushed the bzlmod-update-scalafmt-deps branch from baf7ed1 to 9879592 Compare October 25, 2024 19:21
@mbland
Copy link
Contributor Author

mbland commented Oct 25, 2024

@simuons Thanks! Just rebased, ran some of the tests, and pushed.

I'll send the successful updates from running scripts/create_repository.py that I mentioned earlier in a separate PR after this one lands.

@mbland
Copy link
Contributor Author

mbland commented Oct 28, 2024

@simuons Thanks for the approval on this and #1632, but neither have merged yet. Pinging in case that wasn't intentional.

mbland added a commit to mbland/rules_scala that referenced this pull request Oct 29, 2024
These probably should've been a part of bazelbuild#1631, though it seems that no
harm was done in that pull request.
@liucijus liucijus merged commit 190fbee into bazelbuild:master Oct 29, 2024
2 checks passed
@mbland mbland deleted the bzlmod-update-scalafmt-deps branch October 29, 2024 13:21
@mbland
Copy link
Contributor Author

mbland commented Oct 29, 2024

Thanks, @liucijus!

mbland added a commit to mbland/rules_scala that referenced this pull request Oct 29, 2024
Updates Scalatest to 3.2.19 and Scalafmt to 3.8.3. Part of bazelbuild#1482.

After running the script at the suggestion of @WojciechMazur in bazelbuild#1631, I
selected these specific changes with `git add -p`. I was pleased that
the script left the Scalameta deps at version 4.9.9, and it bumped the
Scalatest versions appropriately.

However, there were a number of downgrades and updates to the Scala 2
`deps` in the Scala 3 files that I didn't accept:

- protobuf-java: 4.28.2 to 3.8.0 or 3.7.0
- scalap: from latest Scala version to an earlier version, including
  2.13.14 to 2.13.11
- com.lihaoyi.pprint: from pprint_3:0.9.0 to pprint_2.13:0.6.4
- compiler-interface: 1.10.1 to 1.3.5 or 1.9.6
- com.lihaoyi.geny: from geny_3:1.1.1 to geny_2.13:0.6.5

Plus, all the `@io_bazel_rules_scala_scala_*_2` deps explicitly added to
the `scala_3_{1,2,3,4,5}.bzl` files in bazelbuild#1631 for Scalafmt were stripped
of the `_2` suffix.

Perhaps it's worth updating `create_repository.py` at some point so
versions aren't automatically downgraded and `_2` suffixes are honored.
mbland added a commit to mbland/rules_scala that referenced this pull request Oct 30, 2024
Without this change, it was possible for Scala 3 core library versions
to become overwritten with Scala 2 versions specified as dependencies of
other jars. Specifically, all the `@io_bazel_rules_scala_scala_*_2` deps
explicitly added to the `scala_3_{1,2,3,4,5}.bzl` files in bazelbuild#1631 for
Scalafmt get stripped of the `_2` suffix before this change.

Also computed `is_scala_3` in `create_file` and passed it through where
needed. At some point it might be worth refactoring the script into a
proper object instead.
mbland added a commit to mbland/rules_scala that referenced this pull request Oct 30, 2024
mbland added a commit to mbland/rules_scala that referenced this pull request Oct 30, 2024
The script will now only update an existing artifact if the newly
resolved version is greater than that already in the
third_party/repositories file. Part of bazelbuild#1482.

Tested by running on `master` both before and after bazelbuild#1631. The script
produced no new changes, and is even faster now, since it also won't try
to downgrade existing artifact versions. More specifically, this change
prevents the following downgrades:

- scalap: from latest Scala version to an earlier version, including
  2.13.14 to 2.13.11
- com.lihaoyi.pprint: from pprint_3:0.9.0 to pprint_2.13:0.6.4
- compiler-interface: 1.10.1 to 1.3.5 or 1.9.6
- com.lihaoyi.geny: from geny_3:1.1.1 to geny_2.13:0.6.5
mbland added a commit to mbland/rules_scala that referenced this pull request Nov 1, 2024
These probably should've been a part of bazelbuild#1631, though it seems that no
harm was done in that pull request.
liucijus pushed a commit that referenced this pull request Nov 4, 2024
* First create_repository.py refactoring

Preserves the behavior of the previous version in preparation for
further improvements and eventual behavior changes. Part of #1482.

Tested by running the original script, calling `git stash
third_party/...`, then running the updated script. Confirmed that the
updated script produced no new changes in the working tree compared to
the indexed changes.

* Second create_repository.py refactoring

Preserves the behavior of the previous version in preparation for further
improvements and eventual behavior changes. Part of #1482.

This change eliminates a lot of duplication, and replaces the previous
functions to add trailing commas to the output with a `re.sub()` call.

Tested by running the original script, calling `git stash third_party/...`,
then running the updated script. Confirmed that the updated script produced no
new changes in the working tree compared to the indexed changes.

Also:

- Added `#!/usr/bin/env python3` and set file mode 0755 to enable
  running the script directly instead of as an argument to `python3`.

- Used `pathlib.Path` on `__file__` to enable running the script from
  any directory, not just from inside `scripts/`.

- Updated `scripts/README.md` to reflect some of the script changes, and
  to improve the Markdown formatting in general.

- Added the `DOWNLOADED_ARTIFACTS_FILE` variable, added its value to
  `.gitignore`, and added a `Path.unlink()` at the end of the script to
  clean it up.

* Third create_repository.py refactoring

Preserves the behavior of the previous version in preparation for
further improvements and eventual behavior changes. Part of #1482.

This vastly improves performance by _not_ downloading and hashing
artifacts that are already present in the current configuration.

Added `PROTOBUF_JAVA_VERSION = "4.28.2"` as a core artifact to avoid
downgrades, and to signal the importance of this particular artifact.

Tested by running the original script, calling `git stash
third_party/...`, then running the updated script. Confirmed that the
updated script produced no new changes in the working tree compared to
the indexed changes, modulo the previous `protobuf-java` downgrade.

* Small create_repository.py format updates, fixes

Added missing traliling comma in `COORDINATE_GROUPS[0]`.

Updated `get_label` to check for groups starting with `org.scala-lang.`

Sorted `deps` in `to_rules_scala_compatible_dict` and always sets `deps`
in the return value, even when empty.

* Ensure Scala 2 libs get "_2" repo names in Scala 3

Without this change, it was possible for Scala 3 core library versions
to become overwritten with Scala 2 versions specified as dependencies of
other jars. Specifically, all the `@io_bazel_rules_scala_scala_*_2` deps
explicitly added to the `scala_3_{1,2,3,4,5}.bzl` files in #1631 for
Scalafmt get stripped of the `_2` suffix before this change.

Also computed `is_scala_3` in `create_file` and passed it through where
needed. At some point it might be worth refactoring the script into a
proper object instead.

* Bump Scalafmt to 3.8.3 in create_repository.py

This matches the version set in #1631.

* Prevent create_repository.py from downgrading jars

The script will now only update an existing artifact if the newly
resolved version is greater than that already in the
third_party/repositories file. Part of #1482.

Tested by running on `master` both before and after #1631. The script
produced no new changes, and is even faster now, since it also won't try
to downgrade existing artifact versions. More specifically, this change
prevents the following downgrades:

- scalap: from latest Scala version to an earlier version, including
  2.13.14 to 2.13.11
- com.lihaoyi.pprint: from pprint_3:0.9.0 to pprint_2.13:0.6.4
- compiler-interface: 1.10.1 to 1.3.5 or 1.9.6
- com.lihaoyi.geny: from geny_3:1.1.1 to geny_2.13:0.6.5

* Ensure all artifact deps written to repo files

Updates the main loop in `create_file` to iterate over the newly
generated artifact dictionary, not the original dictionary parsed from
the existing file. This ensures that all dependencies of the updated
artifacts are written to the file.

This also improves performance when rerunning, since the script will no
longer keep trying to fetch the previously missing artifacts.

Tested by running once, `git add`ing the results, and running again to
ensure the second run was a no-op.

* Update get_label, fix scala3 label bug

Fixes a bug in the previous implementation whereby the `scala3_`
components of org.scala-lang artifact labels listed in an artifact's
`deps` weren't transformed to `scala_`. Improved the handling of
org.scala-lang artifacts more generally via the new
`adjust_scala_lang_label` function.

Refactored the `COORDINATE_GROUPS` array into a series of separate `set`
variables named after their `get_label` transformations. Makes the
`get_label` implementation read a little more easily.

* Replace `split_artifact_and_version`

I finally noticed that `get_maven_coordinates` already did the same
parsing, essentially. I migrated the comment and implementation from
`split_artifact_and_version` into it.

* Check against current ResolvedArtifact instances

Updates `create_artifact_version_map` to
`create_current_resolved_artifacts_map` to set up future improvements.

Specifically, an existing artifact's dependency coordinates aren't
updated unless the resolved artifact version is newer. A small change
after this will ensure all existing dependency coordinates get updated.
This could be a one-off change, or we could decide to keep it; either
way, it would be a very small one to make.

Also:

- Added `MavenCoordinates.artifact_name` to replace
  `artifact_name_from_maven_coordinates`.

- Renamed `is_newer_than_current_version` to `is_newer_version`.

- Added logic in `create_artifact_metadata_map` to ensure values with
  `testonly` set to `True` aren't part of the automatic resolution
  process.

* Handle scalap, org.thesamet.scalapb special cases

Preserves the existing labels for these artifacts.

Tested by running in a new branch that updates the direct dependencies
of core artifacts. Prior to this change, the `scalap` repo and some of
the `org.thesamet.scalapb` repos were duplicated with a new label. After
this change, that duplication disappears.

* Add --version, emit command, stderr only on error

These are changes suggested by @WojciechMazur in #1639.

* Raise and catch SubprocessError, return exit code

Further embellishment of the suggestions from @WojciechMazur in #1639.

This way we can see exactly which version updates encountered an error,
and how many, while continuing to attempt to update other versions.

* Hoist output_dir from create_or_update_repo_file

Makes the logic slightly easier to follow.

* Hoist OUTPUT_DIR as top level constant

I still like passing it as an argument to
`create_or_update_repository_file`.

* Add --output_dir flag, add defaults to --help

Making the output directory configurable from the command line was the
next logical extension. This makes it possible to see what the script
will generate from scratch without having to erase the existing repo
files.

Figured it would be nice to see the default values in the `--help`
output.

* Create a new empty file if no previous file exists

Decided it might be better to literally start from scratch in
`--output_dir` than trying to copy a file from `OUTPUT_DIR`. One could
always copy files from `OUTPUT_DIR` before running the script if so
desired.

Also changed the `__main__` logic to exit immediately on
`CreateRepositoryError` rather than attempt to keep going.

* Remove redundant `file.exists()` check

Eliminated the check in `create_or_update_repository_file` in favor of
that in `copy_previous_version_or_create_new_file_if_missing`.

* Improve `create_repository.py --help` docstrings

* Refactor `get_label` in `create_repository.py`

`get_label` now uses the `SPECIAL_CASE_GROUP_LABELS` dict instead of the
`LAST_GROUP_COMPONENT_GROUP` and `NEXT_TO_LAST_GROUP_COMPONENT_GROUP`
sets.

Also added `com.google.guava` to `ARTIFACT_LABEL_ONLY_GROUPS` to
generate the correct `io_bazel_rules_scala_guava` label. Added
`com.google.api.grpc` and `dev.dirs.directories` to
`SCALA_PROTO_RULES_GROUPS`.

Updated indentation of `ARTIFACT_LABEL_ONLY_GROUPS` and
`GROUP_AND_ARTIFACT_LABEL_GROUPS` elements.

* Emit correct label for scala-collection-compat

Specifically, `org_scala_lang_modules_scala_collection_compat`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants