Skip to content

Commit 15b9d3a

Browse files
authored
Merge pull request #175 from adpi2/yazgoo-main
Split in two commands: `githubGenerateSnapshot` and `githubPublishSnapshot`
2 parents d3f1393 + 7ee6ea5 commit 15b9d3a

File tree

22 files changed

+154
-93
lines changed

22 files changed

+154
-93
lines changed

.github/workflows/ci.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
working-directory: sbt-plugin
1616
steps:
1717
- uses: actions/checkout@v3
18-
- uses: coursier/setup-action@v1.2.0-M3
18+
- uses: coursier/setup-action@v1.3.5
1919
with:
2020
apps: scalafmt sbt
2121
- run: scalafmt --test
@@ -43,7 +43,7 @@ jobs:
4343
jvm: ${{ matrix.jvm }}
4444
apps: sbt
4545
- run: sbt test
46-
- run: sbt "scripted dependency-manifest/*"
46+
- run: sbt "scripted dependency-manifest/* generate-snapshot/*"
4747
- run: sbt "scripted submit-snapshot/*"
4848
if: github.event_name == 'push' || github.event.pull_request.head.repo.owner.login == 'scalacenter'
4949

dist/index.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/index.js.map

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sbt-plugin/.scalafmt.conf

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version = "3.4.3"
1+
version = "3.8.1"
22
runner.dialect = scala212source3
33
maxColumn = 120
44
align.preset = some

sbt-plugin/src/main/contraband/input.contra

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ enum OnFailure {
88
warning
99
}
1010

11-
## Input of the githubSubmitDependencyGraph command
12-
type SubmitInput {
11+
## Input of the githubGenerateSnapshot command
12+
type DependencySnapshotInput {
1313
onResolveFailure: ch.epfl.scala.OnFailure
1414

1515
## A set of modules to ignore.

sbt-plugin/src/main/scala/ch/epfl/scala/GithubDependencyGraphPlugin.scala

+6-4
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,12 @@ object GithubDependencyGraphPlugin extends AutoPlugin {
2727
.map(_.toConfigRef)
2828

2929
object autoImport {
30-
val githubSubmitInputKey: AttributeKey[SubmitInput] = AttributeKey("githubSubmitInput")
30+
val githubSnapshotInputKey: AttributeKey[DependencySnapshotInput] = AttributeKey("githubSnapshotInput")
3131
val githubBuildFile: AttributeKey[githubapi.FileInfo] = AttributeKey("githubBuildFile")
3232
val githubManifestsKey: AttributeKey[Map[String, githubapi.Manifest]] = AttributeKey("githubDependencyManifests")
3333
val githubProjectsKey: AttributeKey[Seq[ProjectRef]] = AttributeKey("githubProjectRefs")
34+
val githubSnapshotFileKey: AttributeKey[File] = AttributeKey("githubSnapshotFile")
35+
3436
val githubDependencyManifest: TaskKey[Option[githubapi.Manifest]] = taskKey(
3537
"The dependency manifest of the project"
3638
)
@@ -90,7 +92,7 @@ object GithubDependencyGraphPlugin extends AutoPlugin {
9092
}
9193

9294
private def includeProject(projectRef: ProjectRef, state: State, logger: Logger): Boolean = {
93-
val ignoredModules = state.attributes(githubSubmitInputKey).ignoredModules
95+
val ignoredModules = state.attributes(githubSnapshotInputKey).ignoredModules
9496
val moduleName = getModuleName(projectRef, state)
9597
val ignored = ignoredModules.contains(moduleName)
9698
if (!ignored) logger.info(s"Including dependency graph of $moduleName")
@@ -120,7 +122,7 @@ object GithubDependencyGraphPlugin extends AutoPlugin {
120122
val thisProject = Keys.thisProject.value
121123
val internalConfigurationMap = Keys.internalConfigurationMap.value
122124

123-
val inputOpt = state.get(githubSubmitInputKey)
125+
val inputOpt = state.get(githubSnapshotInputKey)
124126
val buildFileOpt = state.get(githubBuildFile)
125127

126128
val onResolveFailure = inputOpt.flatMap(_.onResolveFailure)
@@ -198,7 +200,7 @@ object GithubDependencyGraphPlugin extends AutoPlugin {
198200
else DependencyScope.development
199201
val metadata = Map("config" -> JString(configRef.name))
200202
val node = DependencyNode(packageUrl, metadata, Some(relationship), Some(scope), dependencies)
201-
(moduleRef -> node)
203+
moduleRef -> node
202204
}
203205

204206
val projectModuleRef = getReference(projectID)

sbt-plugin/src/main/scala/ch/epfl/scala/SubmitDependencyGraph.scala

+65-54
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package ch.epfl.scala
22

3-
import java.nio.charset.StandardCharsets
43
import java.nio.file.Paths
54
import java.time.Instant
65

@@ -22,31 +21,35 @@ import sjsonnew.shaded.scalajson.ast.unsafe.JValue
2221
import sjsonnew.support.scalajson.unsafe.{Parser => JsonParser, _}
2322

2423
object SubmitDependencyGraph {
25-
val Submit = "githubSubmitDependencyGraph"
26-
val usage: String = s"""$Submit {"projects":[], "scalaVersions":[]}"""
27-
val brief = "Submit the dependency graph to Github Dependency API."
28-
val detail = "Submit the dependency graph of a set of projects and scala versions to Github Dependency API"
24+
val Generate = "githubGenerateSnapshot"
25+
private val GenerateUsage = s"""$Generate {"projects":[], "scalaVersions":[]}"""
26+
private val GenerateDetail = "Generate the dependency graph of a set of projects and scala versions"
2927

30-
val SubmitInternal: String = s"${Submit}Internal"
31-
val internalOnly = "internal usage only"
28+
private val GenerateInternal = s"${Generate}Internal"
29+
private val InternalOnly = "internal usage only"
30+
31+
val Submit = "githubSubmitSnapshot"
32+
private val SubmitDetail = "Submit the dependency graph to Github Dependency API."
33+
34+
def usage(command: String): String = s"""$command {"projects":[], "scalaVersions":[]}"""
3235

3336
val commands: Seq[Command] = Seq(
34-
Command(Submit, (usage, brief), detail)(inputParser)(submit),
35-
Command.command(SubmitInternal, internalOnly, internalOnly)(submitInternal)
37+
Command(Generate, (GenerateUsage, GenerateDetail), GenerateDetail)(inputParser)(generate),
38+
Command.command(GenerateInternal, InternalOnly, InternalOnly)(generateInternal),
39+
Command.command(Submit, SubmitDetail, SubmitDetail)(submit)
3640
)
3741

3842
private lazy val http: HttpClient = Gigahorse.http(Gigahorse.config)
3943

40-
private def inputParser(state: State): Parser[SubmitInput] =
44+
private def inputParser(state: State): Parser[DependencySnapshotInput] =
4145
Parsers.any.*.map { raw =>
4246
JsonParser
4347
.parseFromString(raw.mkString)
44-
.flatMap(Converter.fromJson[SubmitInput])
48+
.flatMap(Converter.fromJson[DependencySnapshotInput])
4549
.get
4650
}.failOnException
4751

48-
private def submit(state: State, input: SubmitInput): State = {
49-
checkGithubEnv() // fail fast if the Github CI environment is incomplete
52+
private def generate(state: State, input: DependencySnapshotInput): State = {
5053
val loadedBuild = state.setting(Keys.loadedBuild)
5154
// all project refs that have a Scala version
5255
val projectRefs = loadedBuild.allProjectRefs
@@ -65,48 +68,58 @@ object SubmitDependencyGraph {
6568
state.log.info(s"Resolving snapshot of $buildFile")
6669

6770
val initState = state
68-
.put(githubSubmitInputKey, input)
71+
.put(githubSnapshotInputKey, input)
6972
.put(githubBuildFile, githubapi.FileInfo(buildFile.toString))
7073
.put(githubManifestsKey, Map.empty[String, Manifest])
7174
.put(githubProjectsKey, projectRefs)
7275

7376
val storeAllManifests = scalaVersions.flatMap { scalaVersion =>
7477
Seq(s"++$scalaVersion", s"Global/${githubStoreDependencyManifests.key} $scalaVersion")
7578
}
76-
val commands = storeAllManifests :+ SubmitInternal
79+
val commands = storeAllManifests :+ GenerateInternal
7780
commands.toList ::: initState
7881
}
7982

80-
private def submitInternal(state: State): State = {
83+
private def generateInternal(state: State): State = {
8184
val snapshot = githubDependencySnapshot(state)
82-
val snapshotUrl = s"${githubApiUrl()}/repos/${githubRepository()}/dependency-graph/snapshots"
83-
8485
val snapshotJson = CompactPrinter(Converter.toJsonUnsafe(snapshot))
85-
8686
val snapshotJsonFile = IO.withTemporaryFile("dependency-snapshot-", ".json", keepFile = true) { file =>
8787
IO.write(file, snapshotJson)
8888
state.log.info(s"Dependency snapshot written to ${file.getAbsolutePath}")
8989
file
9090
}
91+
setGithubOutputs("snapshot-json-path" -> snapshotJsonFile.getAbsolutePath)
92+
state.put(githubSnapshotFileKey, snapshotJsonFile)
93+
}
9194

95+
def submit(state: State): State = {
96+
checkGithubEnv() // fail if the Github CI environment
97+
val snapshotJsonFile = state
98+
.get(githubSnapshotFileKey)
99+
.getOrElse(
100+
throw new MessageOnlyException(
101+
"Missing snapshot file. This command must execute after the githubGenerateSnapshot command"
102+
)
103+
)
104+
val snapshotUrl = s"${githubApiUrl()}/repos/${githubRepository()}/dependency-graph/snapshots"
105+
val job = githubJob()
92106
val request = Gigahorse
93107
.url(snapshotUrl)
94-
.post(snapshotJson, StandardCharsets.UTF_8)
108+
.post(snapshotJsonFile)
95109
.addHeaders(
96110
"Content-Type" -> "application/json",
97111
"Authorization" -> s"token ${githubToken()}"
98112
)
99113

100-
state.log.info(s"Submiting dependency snapshot of job ${snapshot.job} to $snapshotUrl")
114+
state.log.info(s"Submitting dependency snapshot of job $job to $snapshotUrl")
101115
val result = for {
102116
httpResp <- Try(Await.result(http.processFull(request), Duration.Inf))
103117
snapshot <- getSnapshot(httpResp)
104118
} yield {
105119
state.log.info(s"Submitted successfully as $snapshotUrl/${snapshot.id}")
106120
setGithubOutputs(
107121
"submission-id" -> s"${snapshot.id}",
108-
"submission-api-url" -> s"${snapshotUrl}/${snapshot.id}",
109-
"snapshot-json-path" -> snapshotJsonFile.getAbsolutePath
122+
"submission-api-url" -> s"${snapshotUrl}/${snapshot.id}"
110123
)
111124
state
112125
}
@@ -115,11 +128,9 @@ object SubmitDependencyGraph {
115128
}
116129

117130
// https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-output-parameter
118-
private def setGithubOutputs(outputs: (String, String)*): Unit = IO.writeLines(
119-
file(githubOutput),
120-
outputs.toSeq.map { case (name, value) => s"${name}=${value}" },
121-
append = true
122-
)
131+
private def setGithubOutputs(outputs: (String, String)*): Unit =
132+
for (output <- githubOutput())
133+
IO.writeLines(output, outputs.map { case (name, value) => s"${name}=${value}" }, append = true)
123134

124135
private def getSnapshot(httpResp: FullResponse): Try[SnapshotResponse] =
125136
httpResp.status match {
@@ -165,32 +176,32 @@ object SubmitDependencyGraph {
165176
}
166177

167178
private def checkGithubEnv(): Unit = {
168-
githubWorkspace()
169-
githubWorkflow()
170-
githubJobName()
171-
githubAction()
172-
githubRunId()
173-
githubSha()
174-
githubRef()
175-
githubApiUrl()
176-
githubRepository()
177-
githubToken()
178-
}
179-
180-
private def githubWorkspace(): String = githubCIEnv("GITHUB_WORKSPACE")
181-
private def githubWorkflow(): String = githubCIEnv("GITHUB_WORKFLOW")
182-
private def githubJobName(): String = githubCIEnv("GITHUB_JOB")
183-
private def githubAction(): String = githubCIEnv("GITHUB_ACTION")
184-
private def githubRunId(): String = githubCIEnv("GITHUB_RUN_ID")
185-
private def githubSha(): String = githubCIEnv("GITHUB_SHA")
186-
private def githubRef(): String = githubCIEnv("GITHUB_REF")
187-
private def githubApiUrl(): String = githubCIEnv("GITHUB_API_URL")
188-
private def githubRepository(): String = githubCIEnv("GITHUB_REPOSITORY")
189-
private def githubToken(): String = githubCIEnv("GITHUB_TOKEN")
190-
private def githubOutput(): String = githubCIEnv("GITHUB_OUTPUT")
191-
192-
private def githubCIEnv(name: String): String =
193-
Properties.envOrNone(name).getOrElse {
179+
def check(name: String): Unit = Properties.envOrNone(name).orElse {
194180
throw new MessageOnlyException(s"Missing environment variable $name. This task must run in a Github Action.")
195181
}
182+
check("GITHUB_WORKSPACE")
183+
check("GITHUB_WORKFLOW")
184+
check("GITHUB_JOB")
185+
check("GITHUB_ACTION")
186+
check("GITHUB_RUN_ID")
187+
check("GITHUB_SHA")
188+
check("GITHUB_REF")
189+
check("GITHUB_API_URL")
190+
check("GITHUB_REPOSITORY")
191+
check("GITHUB_TOKEN")
192+
check("GITHUB_OUTPUT")
193+
}
194+
195+
private def githubWorkspace(): String = Properties.envOrElse("GITHUB_WORKSPACE", "")
196+
private def githubWorkflow(): String = Properties.envOrElse("GITHUB_WORKFLOW", "")
197+
private def githubJobName(): String = Properties.envOrElse("GITHUB_JOB", "")
198+
private def githubAction(): String = Properties.envOrElse("GITHUB_ACTION", "")
199+
private def githubRunId(): String = Properties.envOrElse("GITHUB_RUN_ID", "")
200+
private def githubSha(): String = Properties.envOrElse("GITHUB_SHA", "")
201+
private def githubRef(): String = Properties.envOrElse("GITHUB_REF", "")
202+
203+
private def githubApiUrl(): String = Properties.envOrElse("GITHUB_API_URL", "")
204+
private def githubRepository(): String = Properties.envOrElse("GITHUB_REPOSITORY", "")
205+
private def githubToken(): String = Properties.envOrElse("GITHUB_TOKEN", "")
206+
private def githubOutput(): Option[File] = Properties.envOrNone("GITHUB_OUTPUT").map(file)
196207
}

sbt-plugin/src/sbt-test/dependency-manifest/ignore-scaladoc/build.sbt

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import ch.epfl.scala.githubapi.DependencyRelationship
22
import ch.epfl.scala.githubapi.DependencyScope
33
import ch.epfl.scala.githubapi.Manifest
4-
import ch.epfl.scala.SubmitInput
4+
import ch.epfl.scala.DependencySnapshotInput
55
import sjsonnew.shaded.scalajson.ast.unsafe.JString
66

77
val checkScaladoc = taskKey[Unit]("Check scaladoc_3 is in the manifest ")
@@ -17,8 +17,8 @@ inThisBuild(
1717
)
1818

1919
Global / ignoreScaladoc := {
20-
val input = SubmitInput(None, Vector.empty, ignoredConfigs = Vector("scala-doc-tool"))
21-
StateTransform(state => state.put(githubSubmitInputKey, input))
20+
val input = DependencySnapshotInput(None, Vector.empty, ignoredConfigs = Vector("scala-doc-tool"))
21+
StateTransform(state => state.put(githubSnapshotInputKey, input))
2222
}
2323

2424
lazy val p1 = project

sbt-plugin/src/sbt-test/dependency-manifest/ignore-test/build.sbt

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import ch.epfl.scala.githubapi.DependencyRelationship
22
import ch.epfl.scala.githubapi.DependencyScope
33
import ch.epfl.scala.githubapi.Manifest
4-
import ch.epfl.scala.SubmitInput
4+
import ch.epfl.scala.DependencySnapshotInput
55
import sjsonnew.shaded.scalajson.ast.unsafe.JString
66

77
val checkTest = taskKey[Unit]("Check munit_3 is in the manifest ")
@@ -17,8 +17,8 @@ inThisBuild(
1717
)
1818

1919
Global / ignoreTestConfig := {
20-
val input = SubmitInput(None, Vector.empty, ignoredConfigs = Vector("test"))
21-
StateTransform(state => state.put(githubSubmitInputKey, input))
20+
val input = DependencySnapshotInput(None, Vector.empty, ignoredConfigs = Vector("test"))
21+
StateTransform(state => state.put(githubSnapshotInputKey, input))
2222
}
2323

2424
lazy val p1 = project
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
> 'githubGenerateSnapshot {}'
2+
> Global / checkManifests 4
3+
4+
> 'githubGenerateSnapshot {"ignoredModules":["a_2.13", "b_2.13"]}'
5+
> Global / checkManifests 2
6+
7+
> 'githubGenerateSnapshot {"ignoredModules":["a_2.12", "a_2.13", "b_2.13"]}'
8+
> Global / checkManifests 1
9+
10+
> 'githubGenerateSnapshot {"ignoredModules":[]}'
11+
> Global / checkManifests 4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
-> 'githubGenerateSnapshot {}'
2+
-> 'Global / githubGenerateSnapshot {"onResolveFailure": "error"}'
3+
4+
> 'githubGenerateSnapshot {"onResolveFailure": "warning"}'
5+
> Global / checkManifests 1

sbt-plugin/src/sbt-test/submit-snapshot/ci-submit/test

-12
This file was deleted.

sbt-plugin/src/sbt-test/submit-snapshot/resolve-failure/test

-5
This file was deleted.

0 commit comments

Comments
 (0)