Skip to content

Commit fb4e507

Browse files
authored
Merge pull request #14904 from jdaugherty/7.0.x
fix: issues found by M5 release verification
2 parents 418f1fc + 7776775 commit fb4e507

File tree

5 files changed

+81
-35
lines changed

5 files changed

+81
-35
lines changed

INSTALL

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,33 @@ Project Structure
3030
------------------------------
3131
The source of Grails is a multi-project Gradle build that uses composite multi-project builds via Gradle's includeBuild feature. The main project is `grails-core`, which contains the core framework code and all libraries that an end user would use in their application. The `grails-gradle` project contains code meant to run on the gradle build classpath. `grails-forge` contains tooling related to App Generation.
3232

33+
Building a Release Version
34+
------------------------------
35+
The source distribution will always be a release version of Grails - this means the version number will not contain the suffix `SNAPSHOT` and the release requirements will apply by default. One of those requirements is jar file signing. In order for forge to always correctly pull the `grails-core` project, a local publishing strategy is used - the jar files are published to a directory inside of the build directory of `grails-core`. This publishing means building the jar files will always trigger the signing process. To successfully build the source distribution, either signing must be disabled or signing must be correctly configured.
36+
37+
Disabling Signing
38+
------------------------------
39+
To disable signing, set the environment variable `GRAILS_PUBLISH_RELEASE` to `false`. This can be done by running the following command in the terminal:
40+
41+
export GRAILS_PUBLISH_RELEASE=false
42+
43+
Enabling Signing
44+
------------------------------
45+
Grails makes use of the Grails Publish Gradle plugin to handle publishing artifacts. This plugin supports signing either via native tooling or via java libraries.
46+
47+
To configure the native tooling, gpg must be installed with a key imported. Then the following must be specified:
48+
49+
export SIGNING_KEY=<your-gpg-key-id>
50+
export SIGNING_PASSPHRASE=<your-gpg-key-passphrase>
51+
52+
To configure the java tooling, the following must be specified:
53+
54+
export SIGNING_KEY=<your-gpg-key-id>
55+
export SIGNING_KEYRING=<path-to-your-gpg-keyring-file>
56+
export SIGNING_PASSPHRASE=<your-gpg-key-passphrase>
57+
58+
Please note: if no GPG Key passphrase is set, then simply leave the environment variable `SIGNING_PASSPHRASE` unset.
59+
3360
Building grails-core
3461
------------------------------
3562
To build the libraries a Grails Application would use, run the following command at the source root:
@@ -58,10 +85,6 @@ To use the built libraries in a Grails Application, libraries must be published
5885
./gradlew build publishToMavenLocal -PskipTests
5986
cd grails-forge && ./gradlew build publishToMavenLocal -PskipTests
6087

61-
Please note that this will require signing with the GPG command since releases are mandated to be signed. To disable signing, set the environment variable to disable release detection:
62-
63-
export GRAILS_PUBLISH_RELEASE=false
64-
6588
Creating an Application
6689
------------------------------
6790
By default, the Grails CLI uses standard maven repos to retrieve upstream Grails libraries. However, it's possible to "override" this behavior by setting the environment variable `GRAILS_REPO_URL` to an alternative location. When wanting to use the libraries generated by a source distribution, set it to your local Maven repository, which is typically `~/.m2/repository`. This can be done by running the following command in the terminal:

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ CLI applications exist to assist in Application generation. Instructions for the
5858

5959
The Apache Grails Wrapper is a tiny distribution (25KB) that can manage larger sized CLIs for Grails. It consists of a
6060
`grailsw` shell script, a `grailsw.bat` batch script, and the jar file `grails-wrapper.jar`. It can be downloaded from
61-
the latest [GitHub Release](https://github.com/apache/grails-core/releases) page starting with 7.0.0-M4 & it is included
61+
the latest [GitHub Release](https://github.com/apache/grails-core/releases) page starting with version 7.0.0-M4 & it is
62+
included
6263
in any created project. The wrapper is used to either create an Apache Grails Application or to run commands in an
6364
existing Grails Application directory. The wrapper is generally meant to be forward compatible and downloads the Apache
6465
Grails CLIs to the directory `$HOME/.grails/wrapper`.
@@ -95,7 +96,7 @@ release page. You can use the command `./grails-forge-cli --help` to see what's
9596
### SDKMAN
9697

9798
If managing multiple, local copies of the Grails CLI, it is recommended to use [SDKMAN!](https://sdkman.io/). Assuming
98-
SDKMAN is installed, this command would install the 7.0.0-M4 version:
99+
SDKMAN is installed, this command would install the `7.0.0-M4` version:
99100

100101
sdk install grails 7.0.0-M4
101102

RELEASE.md

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,13 @@ For Example:
7373
verify.sh v7.0.0-M4 /tmp/grails-verify
7474
```
7575

76-
### Download the Staged Artifacts
76+
Otherwise, you may follow the subsequent steps in this section to verify each step individually.
77+
78+
### Manual Verification: Download the Staged Artifacts
7779

7880
Use `etc/bin/download-release-artifacts.sh` to download the staged artifacts. This script will download the source distribution, wrapper binary distribution, and sdkman binary distribution. The distribution should come from [https://dist.apache.org/repos/dist/dev/incubator/grails/core/version](https://dist.apache.org/repos/dist/dev/incubator/grails/core).
7981

80-
### Source Distribution Verification
82+
### Manual Verification: Source Distribution Verification
8183

8284
The following are the source distribution artifacts:
8385
* `apache-grails-<version>-incubating-src.zip` - the source distribution
@@ -102,7 +104,7 @@ Extracts the zip file and verifies the contents:
102104
* Ensure the `PUBLISHED_ARTIFACTS` file is present so we know how to pull the various jar files.
103105
* Ensure the `CHECKSUMS` file is present so we can ensure those checksums match the staged artifacts.
104106

105-
### Jar file Signature Verification (Nexus Staging Repositories)
107+
### Manual Verification: Jar file Signature Verification (Nexus Staging Repositories)
106108

107109
As part of uploading to repository.apache.org the signatures are verified to match a KEY that has been distributed, but RAO does not verify that the jar files are built with a key trusted by the Grails project.
108110

@@ -113,7 +115,7 @@ Example:
113115
./etc/bin/verify-jar-artifacts.sh v7.0.0-M4 <grailsdownloadlocation>
114116
```
115117

116-
### Reproducible Jar File
118+
### Manual Verification: Reproducible Jar Files
117119
After all jar files are verified to be signed by a valid Grails key, we need to build a local copy to ensure the file was built with the right code base. The `very-reproducible.sh` script handles this check, but if the bootstrap needs to be manually bootstrapped, perform the following step:
118120

119121
gradle -p gradle bootstrap
@@ -124,13 +126,17 @@ If there are any jar file differences, confirm they are relevant by following th
124126
1. Extract the differing jar file using the `etc/bin/extract-build-artifact.sh <jarfilepath from diff.txt>`
125127
2. In IntelliJ, under `etc/bin/results` there will now be a `firstArtifact` & `secondArtifact` folder. Select them both, right click, and select `Compared Directories`
126128

127-
### Binary Distribution Verification
129+
Please note that Grails is officially built on Linux so if there are differences they may be due to the OS platform.
130+
There is a dockerfile checked into to assist building in an environment like GitHub actions. Please see the section
131+
`Appendix: Verification from a Container` for more information.
132+
133+
### Manual Verification: Binary Distribution Verification
128134

129135
Grails has 2 binary distributions:
130136
* `grailsw` - the Grails wrapper, which is a script that downloads the necessary jars to run Grails. This will exist inside of the generated applications, but can be optionally downloaded as a standalone binary distribution.
131137
* `grails` - the delegating CLI, which is a script that delegates to the Grails Forge CLI. This is the `sdkman` distribution.
132138

133-
#### Verify Grails Wrapper Binary Distribution
139+
#### Manual Verification: Verify Grails Wrapper Binary Distribution
134140

135141
The following are the Grails Wrapper distribution artifacts:
136142
* `apache-grails-wrapper-<version>-incubating-bin.zip` - the wrapper distribution
@@ -152,7 +158,7 @@ Verifies the wrapper distribution signature via the command:
152158
Extracts the zip file and verifies the contents:
153159
* Ensure the `LICENSE` & `NOTICE` files are present to ensure license compliance.
154160

155-
#### Verify Grails Delegating CLI Binary Distribution
161+
#### Manual Verification: Verify Grails Delegating CLI Binary Distribution
156162

157163
The following are the Grails distribution artifacts:
158164
* `apache-grails-<version>-incubating-bin.zip` - the cli distribution that will be uploaded to sdkman
@@ -176,12 +182,17 @@ Extracts the zip file and verifies the contents:
176182

177183
## 3. Verifying the CLIs are Functional
178184

179-
The CLI distribution consists of various CLI's: `grailsw` (wrapper), `grails` (delegating), `grails-forge-cli`, and `grails-shell-cli`. Each CLI needs tested to ensure it's functional prior to release:
185+
The CLI distribution consists of various CLI's: `grailsw` (wrapper), `grails` (delegating), `grails-forge-cli`, and
186+
`grails-shell-cli`. Each CLI needs tested to ensure it's functional prior to release. The `verify.sh` script will output
187+
example commands to perform this verification. However, it if manually verifying, these are the minimum suggested steps:
180188

181-
* testing `grailsw`:
189+
* Testing `grailsw`:
182190
* set GRAILS_REPO_URL to the staging repository (https://repository.apache.org/content/groups/staging)
183191
* run `grailsw` and ensure it downloads the correct jars to `.grails` (verify the checksums of the jars)
184-
* testing `grails-shell-cli`:
192+
* Please note that the Grails Wrapper (`grailsw`) writes to the `.grails` directory in the user's home directory. If
193+
not run in an isolated environment, it may attempt to use already downloaded artifacts. If the wrapper fails, try
194+
removing the `.grails` directory to confirm it isn't a transient state issue.
195+
* Testing `grails-shell-cli`:
185196
* create a basic app:
186197
```bash
187198
grails-shell-cli create-app test
@@ -310,18 +321,13 @@ Setup the key for validity:
310321

311322
# Appendix: Verification from a Container
312323

313-
The Grails image is officially built on linux in a GitHub action using an Ubuntu container. To run a linux container locally, you can use the following command:
324+
The Grails image is officially built on linux in a GitHub action using an Ubuntu container. To run a linux container
325+
locally, you can use the following command (substitute `<git-tag-of-release` with the tag name):
314326

315327
```bash
316328
docker build -t grails:testing -f etc/bin/Dockerfile . && docker run -it --rm -v $(pwd):/home/groovy/project -p 8080:8080 grails:testing bash
317329
cd grails-verify
318-
verify.sh v7.0.0-M4 .
319-
cd grails
320-
gradlew wrapper
321-
cd grails-gradle
322-
gradlew wrapper
323-
cd ../..
324-
verify-reproducible.sh .
330+
verify.sh <git-tag-of-release> .
325331
```
326332

327333
Please note that the argument `-p 8080:8080` is used to expose the port 8080 of the container to the host machine's port 8080 (fromContainerPort:toHostPort). This allows you to access any running Grails application in the container from your host. If you have another application on port 8080, you can change the port mapping to avoid conflicts, e.g., `-p 8080:8081`.

gradle/publish-root-config.gradle

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -140,15 +140,8 @@ subprojects {
140140
}
141141
}
142142

143-
project.afterEvaluate {
144-
tasks.register('publishAllPublicationsToTestCaseMavenRepoRepository').configure {
145-
dependsOn(
146-
subprojects
147-
.findAll { it.name in publishedProjects }
148-
.collect { it.tasks.named('publishAllPublicationsToTestCaseMavenRepoRepository') }
149-
)
150-
}
151-
}
143+
// subprojects will register dependencies via the publish plugin
144+
tasks.register('publishAllPublicationsToTestCaseMavenRepoRepository')
152145

153146
def aggregatePublishedArtifacts = tasks.register('aggregatePublishedArtifacts')
154147

grails-gradle/plugins/src/main/groovy/org/grails/gradle/plugin/publishing/GrailsPublishGradlePlugin.groovy

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import grails.util.GrailsNameUtils
2222
import groovy.namespace.QName
2323
import io.github.gradlenexus.publishplugin.InitializeNexusStagingRepository
2424
import io.github.gradlenexus.publishplugin.NexusPublishPlugin
25+
import org.gradle.api.GradleException
2526
import org.gradle.api.Plugin
2627
import org.gradle.api.Project
2728
import org.gradle.api.Task
@@ -178,12 +179,12 @@ Note: if project properties are used, the properties must be defined prior to ap
178179
projectPluginManager.apply(MavenPublishPlugin)
179180

180181
boolean localSigning = false
182+
String signingKeyId = project.findProperty('signing.keyId') ?: System.getenv('SIGNING_PASSPHRASE')
181183
if (isRelease) {
182-
String signingKeyId = project.findProperty('signing.keyId') ?: System.getenv('SIGNING_KEY')
183184
extraPropertiesExtension.setProperty('signing.keyId', signingKeyId)
184185
String secringFile = project.findProperty('signing.secretKeyRingFile') ?: System.getenv('SIGNING_KEYRING')
185186
if (!secringFile) {
186-
project.logger.info("No keyring file has been specified. Assuming the use of local gpgCommand instead.")
187+
project.logger.lifecycle('No keyring file (SIGNING_KEYRING) has been specified. Assuming the use of local gpgCommand to sign instead.')
187188
localSigning = true
188189
extraPropertiesExtension.setProperty('signing.gnupg.keyName', signingKeyId)
189190
} else {
@@ -282,6 +283,17 @@ Note: if project properties are used, the properties must be defined prior to ap
282283
}
283284
}
284285
}
286+
} else {
287+
// This is a local publish. Add the test case repository if it's defined on the extension.
288+
def testRepoPath = gpe.testRepositoryPath.getOrNull()
289+
if (testRepoPath) {
290+
repositories {
291+
maven {
292+
name = 'TestCaseMavenRepo'
293+
url = testRepoPath
294+
}
295+
}
296+
}
285297
}
286298

287299
publications {
@@ -426,12 +438,23 @@ Note: if project properties are used, the properties must be defined prior to ap
426438
// The sign task does not properly setup dependencies, see https://github.com/gradle/gradle/issues/26091
427439
project.tasks.withType(Sign).configureEach {
428440
it.dependsOn(project.tasks.withType(Jar))
441+
it.doFirst {
442+
if (!signingKeyId) {
443+
throw new GradleException('A signing key is required to sign a release. Set GRAILS_PUBLISH_RELEASE=false to bypass signing.')
444+
}
445+
}
429446
}
430447
project.tasks.withType(PublishToMavenRepository).configureEach {
431448
it.mustRunAfter(project.tasks.withType(Sign))
432449
}
433450
}
434451

452+
if (project.rootProject.tasks.names.contains('publishAllPublicationsToTestCaseMavenRepoRepository')) {
453+
project.rootProject.tasks.named('publishAllPublicationsToTestCaseMavenRepoRepository').configure {
454+
it.dependsOn(project.tasks.named('publishAllPublicationsToTestCaseMavenRepoRepository'))
455+
}
456+
}
457+
435458
addInstallTaskAliases(project)
436459
}
437460
}

0 commit comments

Comments
 (0)