diff --git a/.github/workflows/maven/settings.xml b/.github/workflows/maven/settings.xml
new file mode 100644
index 00000000..a88734cf
--- /dev/null
+++ b/.github/workflows/maven/settings.xml
@@ -0,0 +1,14 @@
+
+
+
+
+ central
+ ${env.MAVEN_CENTRAL_USERNAME}
+ ${env.MAVEN_CENTRAL_TOKEN}
+
+
+
+
\ No newline at end of file
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index d81b0226..8b3d690a 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -3,6 +3,11 @@ name: Release Version
on:
workflow_dispatch:
+ inputs:
+ version:
+ description: 'Custom version (optional)'
+ required: false
+ type: string
pull_request_target:
types:
- closed
@@ -14,123 +19,134 @@ on:
- 'main'
jobs:
- deploy:
+ release:
+ if: github.repository_owner == 'guacsec'
runs-on: ubuntu-latest
- name: Deploy release
- environment: staging
-# only trigger the workflow on the base repository and if the merged branch name starts with release.
- if: (github.repository_owner == 'guacsec' && github.event.pull_request.merged == true && startsWith(github.head_ref, 'release/') ) || (github.repository_owner == 'guacsec' && github.ref_name == 'main' && contains(github.event.commits[0].message, 'release/directly'))
- outputs:
- project_version: ${{ steps.project.outputs.version }}
- last_release_tag: ${{ steps.last-release.outputs.tag-name }}
+ permissions:
+ contents: write
+ pull-requests: write
+ id-token: write
steps:
- - name: Checkout sources
- uses: actions/checkout@v3
- with:
- ssh-key: ${{ secrets.GITHUB_TOKEN }}
- fetch-depth: 0
-
+ - name: Checkout
+ uses: actions/checkout@v5
- - name: Setup Java 17
- uses: actions/setup-java@v4
+ - name: Set up Java 17
+ uses: actions/setup-java@v5
with:
- distribution: temurin
- java-version: 17
- cache: maven
+ java-version: '17'
+ distribution: 'temurin'
+ cache: 'maven'
+ gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }}
+ gpg-passphrase: GPG_PASSPHRASE
+ env:
+ GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
- - name: create ssh agent
- uses: webfactory/ssh-agent@v0.7.0
- with:
- ssh-private-key: ${{ secrets.GITHUB_TOKEN }}
+ - name: Import GPG key for Maven
+ run: |
+ mkdir -p ~/.gnupg
+ echo "${{ secrets.GPG_PRIVATE_KEY }}" | gpg --batch --import
+ env:
+ GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
- name: Configure git
run: |
git config user.name "${{ github.actor }}"
git config user.email "${{ github.actor }}@users.noreply.github.com"
-
- name: get previous released annotated tag
id: last-release
run: |
echo "tag-name=$(git describe | awk -F '-' '{print $1}')" >> "$GITHUB_OUTPUT"
- - name: Deploy release to GitHub
- run: |
- mvn release:prepare release:perform -B -ff
+ - name: Set version
+ if: github.event.inputs.version != ''
+ run: mvn -B versions:set -DnewVersion=${{ github.event.inputs.version }} -DgenerateBackupPoms=false
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ - name: Remove snapshot
+ if: github.event.inputs.version == ''
+ run: mvn -B versions:set -DremoveSnapshot -DgenerateBackupPoms=false
- - name: Get pom version of released artifact
- id: project
+ - name: Get version
+ id: get_version
run: |
- git checkout HEAD^ pom.xml
echo "version=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)" >> "$GITHUB_OUTPUT"
- git restore pom.xml --staged --worktree
+ - name: Check if Maven artifact version exists
+ id: check_maven
+ run: |
+ VERSION="${{ steps.get_version.outputs.version }}"
+ GROUP_ID="io.github.guacsec"
+ ARTIFACT_ID="trustify-da-java-client"
+ echo "Checking if Maven artifact $GROUP_ID:$ARTIFACT_ID:$VERSION exists..."
+
+ # Check Maven Central for the artifact
+ HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "https://repo1.maven.org/maven2/io/github/guacsec/trustify-da-java-client/$VERSION/trustify-da-java-client-$VERSION.pom")
+ if [ "$HTTP_CODE" = "200" ]; then
+ echo "maven_exists=true" >> $GITHUB_OUTPUT
+ echo "Maven artifact $GROUP_ID:$ARTIFACT_ID:$VERSION already exists, skipping Maven publish"
+ else
+ echo "maven_exists=false" >> $GITHUB_OUTPUT
+ echo "Maven artifact $GROUP_ID:$ARTIFACT_ID:$VERSION does not exist (HTTP $HTTP_CODE), will publish"
+ fi
+ continue-on-error: true
+
+ - name: Show artifact check results
+ run: |
+ echo "=== Artifact Check Results ==="
+ echo "Maven artifact exists: ${{ steps.check_maven.outputs.maven_exists }}"
+ echo "Will publish to Maven Central: ${{ steps.check_maven.outputs.maven_exists == 'false' }}"
- release:
- runs-on: ubuntu-latest
- name: Release
- if: (github.repository_owner == 'guacsec' && startsWith(github.head_ref, 'release/')) || (github.repository_owner == 'guacsec' && github.ref_name == 'main' && contains(github.event.commits[0].message, 'release/directly'))
- environment: staging
- needs: deploy
- steps:
+ - name: Compute Maven profiles
+ id: compute_profiles
+ run: |
+ PROFILES="gpg-sign"
+ if [ "${{ steps.check_maven.outputs.maven_exists }}" = "false" ]; then
+ PROFILES="${PROFILES},publish-maven"
+ fi
+ echo "profiles=$PROFILES" >> $GITHUB_OUTPUT
+
+ - name: Build and publish to Maven Central
+ if: steps.check_maven.outputs.maven_exists == 'false'
+ run: |
+ mvn -B deploy -P${{ steps.compute_profiles.outputs.profiles }} --settings .github/workflows/maven/settings.xml
- - name: Create release notes for ${{ needs.deploy.outputs.project_version }} release
- uses: actions/github-script@v7
- id: release-notes
- with:
- github-token: ${{ secrets.GITHUB_TOKEN }}
- script: |
- const repo_name = context.payload.repository.full_name
- const response = await github.request('POST /repos/' + repo_name + '/releases' + '/generate-notes', {
- tag_name: '${{ needs.deploy.outputs.project_version }}',
- previous_tag_name: '${{ needs.deploy.outputs.last_release_tag }}'
- })
- return response.data.body
-
- - name: Create new ${{ needs.deploy.outputs.project_version }} release
- uses: actions/github-script@v7
- with:
- github-token: ${{ secrets.GITHUB_TOKEN }}
- script: |
- const repo_name = context.payload.repository.full_name
- const response = await github.request('POST /repos/' + repo_name + '/releases', {
- tag_name: '${{ needs.deploy.outputs.project_version }}',
- name: '${{ needs.deploy.outputs.project_version }}',
- body: ${{ steps.release-notes.outputs.result }},
- draft: false,
- prerelease: false,
- make_latest: 'true'
- })
-
- - name: Checkout sources
- uses: actions/checkout@v3
- with:
- ssh-key: ${{ secrets.GITHUB_TOKEN }}
- fetch-depth: 0
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
+ MAVEN_CENTRAL_USERNAME: ${{ secrets.MAVEN_CENTRAL_USERNAME }}
+ MAVEN_CENTRAL_TOKEN: ${{ secrets.MAVEN_CENTRAL_TOKEN }}
- - name: Configure git
+ - name: Skip publishing - artifact already exists
+ if: steps.check_maven.outputs.maven_exists == 'true'
run: |
- git config user.name "${{ github.actor }}"
- git config user.email "${{ github.actor }}@users.noreply.github.com"
+ echo "Maven artifact already exists, skipping publish step"
+ echo "Maven exists: ${{ steps.check_maven.outputs.maven_exists }}"
- - name: Get pom version of new snapshot artifact
- id: project_snapshot
- run: |
- git pull
- echo "version=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)" >> "$GITHUB_OUTPUT"
+ - name: Create Release
+ id: create_release
+ uses: softprops/action-gh-release@v1
+ with:
+ name: Release ${{ github.event.inputs.version || steps.get_version.outputs.version }}
+ tag_name: v${{ github.event.inputs.version || steps.get_version.outputs.version }}
+ generate_release_notes: true
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ - name: Update to next version
+ if: success()
+ run: |
+ mvn -B release:update-versions
+ # Run the phase that triggers README.md update
+ mvn -B validate
- - name: Update readme usage section
- run: >
- sed -i
- 's/.*<\/version>/${{ steps.project_snapshot.outputs.version }}<\/version>/g'
- README.md
+ - name: Create Pull Request with next version
+ id: cpr
+ uses: peter-evans/create-pull-request@v5
+ with:
+ commit-message: "build(release): update to next development version"
+ branch: chore/bump-version
+ title: "chore: bump to next development version"
+ signoff: true
+ body: |
+ This PR updates the project to the next development version after the release.
- - name: Push modifications
- run: |
- git add README.md
- git commit -m "docs: updated usage section with version ${{ steps.project_snapshot.outputs.version }} [skip ci]"
- git push
diff --git a/.github/workflows/stage.yml b/.github/workflows/stage.yml
deleted file mode 100644
index 66a99cd4..00000000
--- a/.github/workflows/stage.yml
+++ /dev/null
@@ -1,143 +0,0 @@
----
-name: Stage
-
-on:
- pull_request_target:
- types:
- - closed
- branches:
- - main
- paths:
- - "src/main/**"
- - "pom.xml"
- - ".github/workflows/**"
-
-jobs:
- deploy:
- runs-on: ubuntu-latest
- name: Deploy snapshot
- env:
- RUN_PYTHON_BIN: ${{ vars.RUN_PYTHON_BIN }}
- if: github.repository_owner == 'guacsec' && github.event.pull_request.merged == true && !startsWith(github.head_ref, 'release/')
- outputs:
- project_version: ${{ steps.project.outputs.version }}
- steps:
- - name: Checkout sources
- uses: actions/checkout@v3
-
- - name: Setup Java 17
- uses: actions/setup-java@v4
- with:
- distribution: temurin
- java-version: 17
- cache: maven
-
- - name: Get pom specs
- id: project
- run: |
- echo "version=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)" >> "$GITHUB_OUTPUT"
-
- - name: Deploy snapshot to GitHub
- if: |
- contains(steps.project.outputs.version, 'SNAPSHOT') &&
- github.repository == 'guacsec/trustify-da-java-client'
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: mvn deploy -Pprepare-deployment,deploy-github -B -ff -DskipTests=true -Dskip.junit_platform=true
-
- release:
- runs-on: ubuntu-latest
- name: Release snapshot
- environment: staging
- needs: deploy
- if: |
- contains(needs.deploy.outputs.project_version, 'SNAPSHOT') &&
- github.repository_owner == 'guacsec' && github.event.pull_request.merged == true && !startsWith(github.head_ref, 'release/')
- steps:
- - name: Check for existing ${{ needs.deploy.outputs.project_version }} release
- id: existing_release
- uses: actions/github-script@v7
- env:
- PROJECT_VERSION: ${{ needs.deploy.outputs.project_version }}
- continue-on-error: true
- with:
- github-token: ${{ secrets.GITHUB_TOKEN }}
- script: |
- const repo = context.repo;
- const tag = process.env.PROJECT_VERSION;
- try {
- const response = await github.rest.repos.getReleaseByTag({
- owner: repo.owner,
- repo: repo.repo,
- tag: tag
- });
- core.setOutput('id', response.data.id);
- } catch (error) {
- if (error.status === 404) {
- core.info(`Release for tag '${tag}' not found.`);
- } else {
- throw error;
- }
- }
-
- - name: Checkout sources
- uses: actions/checkout@v3
-
- - name: Delete ${{ needs.deploy.outputs.project_version }} release if exists
- if: ${{ steps.existing_release.outputs.id }}
- uses: actions/github-script@v6
- env:
- RELEASE_ID: ${{ steps.existing_release.outputs.id }}
- with:
- github-token: ${{ secrets.GITHUB_TOKEN }}
- script: |
- const repo = context.repo;
- const releaseId = process.env.RELEASE_ID;
-
- try {
- console.log(`Deleting release ID: ${releaseId}`);
- await github.rest.repos.deleteRelease({
- owner: repo.owner,
- repo: repo.repo,
- release_id: releaseId
- });
- console.log(`Deleted release ID: ${releaseId}`);
- } catch (error) {
- if (error.status === 404) {
- console.log(`Release ID: ${releaseId} not found. Skipping deletion.`);
- } else {
- throw error;
- }
- }
- - name: Delete ${{ needs.deploy.outputs.project_version }} tag if exists
- continue-on-error: true
- run: git push --delete origin ${{ needs.deploy.outputs.project_version }}
-
- # Workaround for GitHub release cache issue — avoids ghost "draft" releases
- - name: Sleep to allow release deletion to propagate
- run: sleep 5
-
- - name: Create new ${{ needs.deploy.outputs.project_version }} release
- uses: actions/github-script@v7
- env:
- PROJECT_VERSION: ${{ needs.deploy.outputs.project_version }}
- with:
- github-token: ${{ secrets.GITHUB_TOKEN }}
- script: |
- const repo = context.repo;
- const tag = process.env.PROJECT_VERSION;
-
- console.log(`Creating release for tag: ${tag}`);
-
- const response = await github.rest.repos.createRelease({
- owner: repo.owner,
- repo: repo.repo,
- tag_name: tag,
- name: tag,
- draft: false,
- prerelease: true,
- generate_release_notes: true,
- make_latest: 'false',
- });
-
- console.log(`Release created: ${response.data.html_url}`);
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index f0465012..15de1ed7 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -32,8 +32,8 @@
> The following are used strictly by CI workflows. Use `mvn install` to install the module locally.
* `prepare-deployment` - use this profile for packaging of jars to deploy to artifact repository,
it will create a *flatten pom* and a *sources*, and *javadoc* *jars*
-* `deploy-github` - use this profile to include github registry distribution definition,
- used for deploying and releasing
+* `gpg-sign` - use this profile to GPG sign artifacts for Maven Central publishing
+* `publish-maven` - use this profile to publish to Maven Central
### Good to know
diff --git a/README.md b/README.md
index 676bf4ad..c794da02 100644
--- a/README.md
+++ b/README.md
@@ -696,6 +696,21 @@ Customize image analysis optionally by using *Environment Variables* or *Java Pr
| TRUSTIFY_DA_IMAGE_ARCH | Default Architecture used for multi-arch images when `TRUSTIFY_DA_IMAGE_PLATFORM` is not set | |
| TRUSTIFY_DA_IMAGE_VARIANT | Default Variant used for multi-arch images when `TRUSTIFY_DA_IMAGE_PLATFORM` is not set | |
+### Releases
+
+To create a new release:
+
+1. **Trigger Release Workflow**: Go to Actions → "Release Version" → "Run workflow"
+2. **Choose Version**:
+ - Leave version empty to automatically release current snapshot (e.g., `0.0.9-SNAPSHOT` → `0.0.9`)
+ - Or specify custom version (e.g., `1.0.0`)
+3. **Automatic Process**: The workflow will:
+ - Publish to Maven Central
+ - Create GitHub release with auto-generated notes
+ - Bump to next development version via pull request
+
+Released artifacts are available on [Maven Central](https://repo1.maven.org/maven2/io/github/guacsec/trustify-da-java-client/).
+
### Known Issues
- For pip requirements.txt - It's been observed that for python versions 3.11.x, there might be slowness for invoking the analysis.
diff --git a/pom.xml b/pom.xml
index e2ded2e2..760c9068 100644
--- a/pom.xml
+++ b/pom.xml
@@ -57,6 +57,7 @@
2.15.0
3.5.3
2.44.4
+ 0.9.0
@@ -103,6 +104,19 @@
https://github.com/guacsec/trustify-da-java-client/actions
+
+
+ central
+ Maven Central
+ https://central.sonatype.com/repository/maven-releases/
+
+
+ central
+ Maven Central Snapshots
+ https://central.sonatype.com/repository/maven-snapshots/
+
+
+
@@ -307,7 +321,7 @@
maven-release-plugin
${maven-release-plugin.version}
- -DskipTests=true -Dskip.junit_platform=true -Pprepare-deployment,deploy-github
+ -DskipTests=true -Dskip.junit_platform=true -Pprepare-deployment
v@{project.version}
Build (Release): [skip ci]
@@ -884,30 +898,6 @@ limitations under the License.]]>
-
-
-
- deploy-github
-
-
- github
- https://maven.pkg.github.com/guacsec/trustify-da-java-client
-
-
- github
- https://maven.pkg.github.com/guacsec/trustify-da-java-client
-
-
-
-
-
- de.sormuras.junit
- junit-platform-maven-plugin
-
-
-
-
-
prepare-deployment
@@ -953,5 +943,51 @@ limitations under the License.]]>
+
+
+ gpg-sign
+
+
+
+ maven-gpg-plugin
+
+
+ sign-artifacts
+ verify
+
+ sign
+
+
+
+ --pinentry-mode
+ loopback
+
+
+
+
+
+
+
+
+
+
+
+ publish-maven
+
+
+
+ org.sonatype.central
+ central-publishing-maven-plugin
+ ${central-publishing-maven-plugin.version}
+ true
+
+ central
+ true
+
+
+
+
+
+