Skip to content
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
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Java build & test
name: Build & Test

on: [push]

Expand Down
39 changes: 14 additions & 25 deletions .github/workflows/pre_release_on_develop_merge.yml
Original file line number Diff line number Diff line change
@@ -1,57 +1,45 @@
name: Pre-release on develop merge

on:
push:
branches:
- develop
workflow_run:
workflows: ["Build & Test"]
types:
- completed

jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK 18
uses: actions/setup-java@v3
with:
java-version: '18'
distribution: 'adopt'
cache: maven
- name: Cache local Maven repository
uses: actions/cache@v3
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- name: Build and Test with Maven
run: mvn verify

build-and-release:
needs: build-and-test
if: ${{ github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.head_branch == 'develop' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Checkout code
uses: actions/checkout@v3

- name: Set up JDK 18
uses: actions/setup-java@v3
with:
java-version: '18'
distribution: 'adopt'
cache: maven

- name: Cache local Maven repository
uses: actions/cache@v3
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-

- name: Build with Maven
run: mvn package

- name: Extract Version from POM
id: extract_version
run: echo "version=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)" >> $GITHUB_OUTPUT

- name: Generate Timestamp
id: gen_timestamp
run: echo "timestamp=$(date +'%Y%m%d_%H%M%S')" >> $GITHUB_OUTPUT

- name: Create Pre-release
id: create_release
uses: actions/create-release@v1
Expand All @@ -62,6 +50,7 @@ jobs:
release_name: Pre-release ${{ steps.extract_version.outputs.version }} (${{ steps.gen_timestamp.outputs.timestamp }})
draft: false
prerelease: true

- name: Upload Release Asset
uses: actions/upload-release-asset@v1
env:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ public static void openLatestReleaseInDefaultBrowser() {
* Opens the webpage for the given binary release in the official remote repository.
* */
public static void openReleaseInDefaultBrowser(Version tag) {
LOGGER.info("Opening v[{}]'s release's homepage using default browser...", tag);
LOGGER.info("Opening [{}]'s release's homepage using default browser...", tag);

Try.run(() -> openGithubReleaseInDefaultBrowser(GITHUB_REPOSITORY_OWNER, GITHUB_REPOSITORY_NAME, tag.get()))
Try.run(() -> openGithubReleaseInDefaultBrowser(GITHUB_REPOSITORY_OWNER, GITHUB_REPOSITORY_NAME, tag.toString()))
.onFailure(t -> LOGGER.error("There was an error opening the latest release tagged [{}] in remote repository [{}/{}]", tag, GITHUB_REPOSITORY_OWNER, GITHUB_REPOSITORY_NAME, t));
}

Expand Down Expand Up @@ -136,7 +136,7 @@ private static String getLatestReleaseTagFromGithub(String owner, String repo, b
* combination.
* */
private static void openGithubReleaseInDefaultBrowser(String owner, String repo, String tag) throws IOException {
String latestReleaseUrl = String.format("https://github.com/%s/%s/releases/tag/v%s", owner, repo, tag);
String latestReleaseUrl = String.format("https://github.com/%s/%s/releases/tag/%s", owner, repo, tag);

Desktop desktop = Desktop.getDesktop();
if (desktop.isSupported(Desktop.Action.BROWSE)) {
Expand Down
73 changes: 53 additions & 20 deletions src/main/java/com/dazednconfused/catalauncher/update/Version.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,30 @@
import java.util.regex.Pattern;

/**
* Represents a version with optional pre-release information. This class supports semantic versioning and pre-release tags.
* <br/><br/>
* Examples of valid version strings:
* <ul>
* <li>{@code v1.2.3}</li>
* <li>{@code prerelease-1.2.3-YYYYmmDD_HHmmSS}</li>
* </ul>
*
* @see <a href="https://stackoverflow.com/a/11024200">https://stackoverflow.com/a/11024200</a>
* */
*
*/
public class Version implements Comparable<Version> {

private static final Pattern VERSION_PATTERN = Pattern.compile("^(?:prerelease-)?v?([0-9]+(\\.[0-9]+)*)(?:-(.+))?$");
private static final String PRERELEASE_PREFIX = "prerelease-";

private final String semver;
private final String preReleaseTag;
private final boolean isPreRelease;

public String get() {
return this.semver;
}

public String getPreReleaseTag() {
return this.preReleaseTag;
}

public boolean isPreRelease() {
return this.isPreRelease;
}

/**
* Constructs a Version object from a version string.
*
* @param versionString the version string, e.g., "v1.2.3", "prerelease-v1.2.3-alpha", etc.
* Constructs a {@link Version} object from a version string.
*
* @param versionString the version string, e.g., "v1.2.3", "prerelease-v1.2.3-alpha", etc
* @throws IllegalArgumentException if the version string is null or does not match the expected format
*/
public Version(String versionString) {
Expand All @@ -42,11 +39,38 @@ public Version(String versionString) {
if (!matcher.matches()) {
throw new IllegalArgumentException("Invalid version format");
}
this.isPreRelease = versionString.startsWith("prerelease-");
this.isPreRelease = versionString.startsWith(PRERELEASE_PREFIX);
this.semver = matcher.group(1);
this.preReleaseTag = matcher.group(3);
}

/**
* Returns the semantic version of the {@link Version}.
*
* @return The semantic version (ie: {@code 1.2.3})
*/
public String getSemver() {
return this.semver;
}

/**
* Returns the pre-release tag of the {@link Version}.
*
* @return The pre-release tag, or {@code null} if not a pre-release
*/
public String getPreReleaseTag() {
return this.preReleaseTag;
}

/**
* Checks if the {@link Version} is a pre-release.
*
* @return {@code true} if the version is a pre-release, {@code false} otherwise
*/
public boolean isPreRelease() {
return this.isPreRelease;
}

@Override
public int compareTo(Version that) {
if (that == null) {
Expand Down Expand Up @@ -107,11 +131,20 @@ public int hashCode() {
return Objects.hash(semver, preReleaseTag, isPreRelease);
}

/**
* Returns the full version string.
*
* @return "v" followed by the semantic version if not a pre-release (ie: {@code v1.2.3}); or "prerelease-" followed
* by the semantic version and pre-release tag if it is a pre-release (ie: {@code prerelease-1.2.3-YYYYmmDD_HHmmSS}).
*/
@Override
public String toString() {
if (isPreRelease && preReleaseTag != null) {
return "prerelease-" + semver + "-" + preReleaseTag;
if (isPreRelease) {
if (preReleaseTag != null) {
return PRERELEASE_PREFIX + semver + "-" + preReleaseTag;
}
return PRERELEASE_PREFIX + semver;
}
return semver;
return "v" + this.semver;
}
}
94 changes: 92 additions & 2 deletions src/test/java/update/VersionTest.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package update;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;

import com.dazednconfused.catalauncher.update.Version;

Expand Down Expand Up @@ -56,8 +57,8 @@ void versions_comparable_in_collections_success() {
versions.add(new Version("1.01.0"));
versions.add(new Version("1.00.1"));

assertThat(Collections.min(versions).get()).isEqualTo("1.00.1");
assertThat(Collections.max(versions).get()).isEqualTo("2");
assertThat(Collections.min(versions).getSemver()).isEqualTo("1.00.1");
assertThat(Collections.max(versions).getSemver()).isEqualTo("2");
}

@Test
Expand All @@ -75,4 +76,93 @@ void versions_is_compatible_with_v_prefix() {

assertThat(a.equals(b)).isTrue();
}

@Test
void version_with_prerelease_is_lower_than_release() {
Version prerelease = new Version("prerelease-1.0.0-alpha");
Version release = new Version("1.0.0");

assertThat(prerelease.compareTo(release)).isEqualTo(-1); // (prerelease < release)
assertThat(prerelease).isNotEqualTo(release);
}

@Test
void version_with_prerelease_tags_are_compared_lexicographically() {
Version alpha = new Version("prerelease-1.0.0-alpha");
Version beta = new Version("prerelease-1.0.0-beta");

assertThat(alpha.compareTo(beta)).isEqualTo(-1); // (alpha < beta)
assertThat(alpha).isNotEqualTo(beta);
}

@Test
void version_with_prerelease_and_no_tag_is_lower_than_with_tag() {
Version noTag = new Version("prerelease-1.0.0");
Version withTag = new Version("prerelease-1.0.0-alpha");

assertThat(noTag.compareTo(withTag)).isEqualTo(-1); // (noTag < withTag)
assertThat(noTag).isNotEqualTo(withTag);
}

@Test
void version_with_invalid_format_throws_exception() {
assertThatThrownBy(() -> new Version("invalid-version"))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Invalid version format");
}

@Test
void version_with_null_string_throws_exception() {
assertThatThrownBy(() -> new Version(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Version cannot be null");
}

@Test
void version_with_extra_zeroes_in_prerelease_tag_is_not_equal() {
Version a = new Version("prerelease-1.0.0-alpha");
Version b = new Version("prerelease-1.0.0-alpha.0");

assertThat(a).isNotEqualTo(b);
}

@Test
void version_with_prerelease_and_same_base_version_is_equal() {
Version a = new Version("prerelease-1.0.0");
Version b = new Version("prerelease-1.0.0");

assertThat(a.compareTo(b)).isEqualTo(0); // (a == b)
assertThat(a.equals(b)).isTrue();
}

@Test
void version_toString_returns_expected_for_release() {
Version v = new Version("1.2.3");
assertThat(v.toString()).hasToString("v1.2.3");
}

@Test
void version_toString_returns_expected_for_release_with_v_prefix() {
Version v = new Version("v2.0.1");
assertThat(v.toString()).hasToString("v2.0.1");
}

@Test
void version_toString_returns_expected_for_prerelease_with_tag() {
Version v = new Version("prerelease-1.2.3-alpha");
assertThat(v.toString()).hasToString("prerelease-1.2.3-alpha");
}

@Test
void version_toString_returns_expected_for_prerelease_with_complex_tag() {
Version v = new Version("prerelease-1.2.3-20240601_123456");
assertThat(v.toString()).hasToString("prerelease-1.2.3-20240601_123456");
}

@Test
void version_toString_returns_expected_for_prerelease_without_tag() {
Version v = new Version("prerelease-1.2.3");
assertThat(v.toString()).hasToString("prerelease-1.2.3");
}

}
Loading