diff --git a/.github/workflows/update_spdx_licenses.yml b/.github/workflows/update_spdx_licenses.yml new file mode 100644 index 00000000..5f633638 --- /dev/null +++ b/.github/workflows/update_spdx_licenses.yml @@ -0,0 +1,122 @@ +name: Update SPDX licenses + +on: + schedule: + - cron: "0 0 * * *" + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +# https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/controlling-permissions-for-github_token +permissions: { } + +jobs: + update: + name: Update Schemas + runs-on: ubuntu-latest + outputs: + changed: ${{ steps.diff.outputs.changed }} + version: ${{ steps.version.outputs.version }} + timeout-minutes: 10 + steps: + - name: Checkout + # see https://github.com/actions/checkout + uses: actions/checkout@v5 + with: + ref: ${{ github.ref_name }} + - name: Set up JDK + # see https://github.com/actions/setup-java + uses: actions/setup-java@v5 + with: + java-version: '21' + distribution: 'zulu' + java-package: jdk + - name: Update SPDX + run: tools/updateSpdx.sh + - name: detect version + id: version + run: | + value=$( jq -r '.["$comment"]' schema/spdx.schema.json ) + echo "version=$value" >> $GITHUB_OUTPUT + - name: Detect changes + id: diff + run: | + if git diff --quiet -- 'schema/spdx.*' + then + echo "$GITHUB_REF_NAME is up-to-date" + echo "changed=false" >> $GITHUB_OUTPUT + else + echo "$GITHUB_REF_NAME is not up-to-date" + echo "changed=true" >> $GITHUB_OUTPUT + fi + - name: Artifact changes + if: ${{ steps.diff.outputs.changed == 'true' }} + # https://github.com/actions/upload-artifact + uses: actions/upload-artifact@v4 + with: + retention-days: 1 + name: schema-spdx + path: schema/spdx.* + if-no-files-found: error + pullrequest: + name: Pull-request Changes + runs-on: ubuntu-latest + needs: [ 'update' ] + if: ${{ needs.update.outputs.changed == 'true' }} + permissions: + contents: write # push commits + pull-requests: write # create pullrequests + env: + SB_VERSION: ${{ needs.update.outputs.version }} + SB_BRANCH: ${{ github.ref_name }}_update-spdx/${{ needs.update.outputs.version }} + steps: + - name: Checkout + # see https://github.com/actions/checkout + uses: actions/checkout@v5 + with: + ref: ${{ github.ref_name }} + - name: Switch branch + id: branch + run: | + set -eux + git remote set-branches origin "$SB_BRANCH" + if git ls-remote --exit-code --heads origin "$SB_BRANCH" + then + echo "existed=true" >> $GITHUB_OUTPUT + git fetch --depth=1 origin "$SB_BRANCH" + git checkout -b "$SB_BRANCH" "origin/$SB_BRANCH" + else + echo "existed=false" >> $GITHUB_OUTPUT + git checkout -b "$SB_BRANCH" + fi + - name: Fetch changes + # https://github.com/actions/download-artifact + uses: actions/download-artifact@v5 + with: + name: schema-spdx + path: schema + - name: Commit and push + run: | + set -eux + if git diff --quiet -- 'schema/spdx.*' + then + echo "branch up-to-date" + exit 0 + fi + git config user.name 'spdx-license-bumber[bot]' + git config user.email 'spdx-license-bumber@bot.local' + git add -A schema + git commit -s -m "feat: bump SPDX licenses $SB_VERSION" + git push origin "$SB_BRANCH" + - name: Pull request + if: ${{ steps.branch.outputs.existed == 'false' }} + run: > + gh pr create + --title "feat: bump SPDX Licenses $SB_VERSION" + --body "$SB_VERSION" + --base "$GITHUB_REF_NAME" + --head "$SB_BRANCH" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/tools/src/main/java/org/cyclonedx/tools/SpdxXsdGenerator.java b/tools/src/main/java/org/cyclonedx/tools/SpdxXsdGenerator.java index 4c2ffa04..1b11ee8d 100644 --- a/tools/src/main/java/org/cyclonedx/tools/SpdxXsdGenerator.java +++ b/tools/src/main/java/org/cyclonedx/tools/SpdxXsdGenerator.java @@ -26,17 +26,39 @@ import java.nio.charset.StandardCharsets; import java.util.LinkedHashMap; import java.util.Map; +import java.util.Objects; import java.util.Set; public class SpdxXsdGenerator { - //todo : automatically obtain latest release from: https://api.github.com/repos/spdx/license-list-data/releases - //todo : make configurable - private static final String SPDX_VERSION = "3.27.0"; + public static void main(String[] args) throws Exception { + String tagName = args.length == 0 || Objects.equals(args[0], "latest") + ? getLatestReleaseTagName() + : args[0]; + new SpdxXsdGenerator(tagName) + .generateSchemas(); + } + + private static final String REPO = "spdx/license-list-data"; + + private static String getLatestReleaseTagName() throws Exception { + String apiReleasesLatest = "https://api.github.com/repos/" + REPO + "/releases/latest"; + HttpResponse apiResponse = Unirest.get(apiReleasesLatest).asJson(); + final JSONObject apiResponseRoot = apiResponse.getBody().getObject(); + return apiResponseRoot.getString("tag_name"); + } + + private final String tagName; - public static void main(String args[]) throws Exception { - String licenseUrl = "https://raw.githubusercontent.com/spdx/license-list-data/v" + SPDX_VERSION + "/json/licenses.json"; - String exceptionsUrl = "https://raw.githubusercontent.com/spdx/license-list-data/v" + SPDX_VERSION + "/json/exceptions.json"; + public SpdxXsdGenerator(String tagName) { + this.tagName = tagName; + } + + public void generateSchemas() throws Exception { + System.out.println("Generate Schemas for " + REPO + " tagName: " + tagName); + + String licenseUrl = "https://raw.githubusercontent.com/" + REPO + "/" + tagName + "/json/licenses.json"; + String exceptionsUrl = "https://raw.githubusercontent.com/" + REPO + "/" + tagName + "/json/exceptions.json"; HttpResponse licenseResponse = Unirest.get(licenseUrl).asJson(); final JSONObject licenseRoot = licenseResponse.getBody().getObject(); @@ -62,15 +84,14 @@ public static void main(String args[]) throws Exception { createJsonSchema(licenseMap, exceptionMap); } - - private static void createXmlSchema(Map licenses, Map exceptions) throws IOException { + private void createXmlSchema(Map licenses, Map exceptions) throws IOException { StringBuilder sb = new StringBuilder(); sb .append("").append("\n") .append("").append("\n\n") + .append(indent(11)).append("version=\"1.0-" + stripLeadingV(tagName) + "\">").append("\n\n") .append(indent(4)).append("").append("\n") .append(indent(8)).append("").append("\n"); @@ -90,13 +111,13 @@ private static void createXmlSchema(Map licenses, Map licenses, Map exceptions) throws IOException { + private void createJsonSchema(Map licenses, Map exceptions) throws IOException { StringBuilder sb = new StringBuilder(); sb .append("{").append("\n") .append(indent(2)).append("\"$schema\": \"http://json-schema.org/draft-07/schema#\",").append("\n") .append(indent(2)).append("\"$id\": \"http://cyclonedx.org/schema/spdx.schema.json\",").append("\n") - .append(indent(2)).append("\"$comment\": \"v1.0-" + SPDX_VERSION + "\",").append("\n") + .append(indent(2)).append("\"$comment\": \"v1.0-" + stripLeadingV(tagName) + "\",").append("\n") .append(indent(2)).append("\"type\": \"string\",").append("\n") .append(indent(2)).append("\"enum\": ["); @@ -144,4 +165,10 @@ private static String indent(int spaces) { return sb.toString(); } + public static String stripLeadingV(String input) { + if (input != null && input.length() > 1 && input.charAt(0) == 'v' ) { + return input.substring(1); + } + return input; + } } diff --git a/tools/updateSpdx.sh b/tools/updateSpdx.sh index 7a973a5c..953742a5 100755 --- a/tools/updateSpdx.sh +++ b/tools/updateSpdx.sh @@ -6,6 +6,7 @@ this_dir="$(dirname "$this")" project_root="$(dirname "$this_dir")" schema_dir="$project_root/schema" +cd "$this_dir" mvn clean \ compile \ exec:java -Dexec.mainClass='org.cyclonedx.tools.SpdxXsdGenerator' \