├── scripts ├── check ├── in └── out ├── .gitignore ├── .github ├── dependabot.yml └── workflows │ └── test-linux.yml ├── Makefile ├── .mvn └── wrapper │ └── maven-wrapper.properties ├── Dockerfile ├── README.md ├── src ├── test │ └── java │ │ └── com │ │ └── rabbitmq │ │ └── concourse │ │ ├── GithubReleaseDeleteResourceTest.java │ │ └── ReleaseTest.java └── main │ └── java │ └── com │ └── rabbitmq │ └── concourse │ └── GithubReleaseDeleteResource.java ├── pom.xml ├── mvnw.cmd ├── mvnw └── LICENSE /scripts/check: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | java -jar /opt/resource/github-release-delete-resource.jar check 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | .sw? 3 | .*.sw? 4 | *.beam 5 | *.class 6 | *.dat 7 | *.dump 8 | *.iml 9 | *.ipr 10 | *.iws 11 | .DS_Store 12 | \#~ 13 | /.idea/ 14 | /deps/ 15 | /target/ 16 | /.classpath 17 | /.project 18 | /.settings 19 | 20 | -------------------------------------------------------------------------------- /scripts/in: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | destination=$1 5 | 6 | if [ -z "$destination" ]; then 7 | echo "usage: $0 " >&2 8 | exit 1 9 | fi 10 | 11 | java -jar /opt/resource/github-release-delete-resource.jar in $destination 12 | -------------------------------------------------------------------------------- /scripts/out: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | destination=$1 5 | 6 | if [ -z "$destination" ]; then 7 | echo "usage: $0 " >&2 8 | exit 1 9 | fi 10 | 11 | java -jar /opt/resource/github-release-delete-resource.jar out $destination 12 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Please see the documentation for all configuration options: 2 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 3 | version: 2 4 | updates: 5 | - package-ecosystem: "maven" 6 | directory: "/" 7 | schedule: 8 | interval: "daily" 9 | open-pull-requests-limit: 20 -------------------------------------------------------------------------------- /.github/workflows/test-linux.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven 3 | 4 | name: Build (Linux) 5 | 6 | on: 7 | push: 8 | branches: 9 | - main 10 | pull_request: 11 | branches: 12 | - main 13 | 14 | jobs: 15 | build: 16 | 17 | runs-on: ubuntu-latest 18 | 19 | steps: 20 | - uses: actions/checkout@v3 21 | - name: Set up JDK 21 22 | uses: actions/setup-java@v3 23 | with: 24 | java-version: '21' 25 | distribution: 'zulu' 26 | cache: maven 27 | - name: Build with Maven 28 | run: ./mvnw test 29 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SHELL := bash# we want bash behaviour in all shell invocations 2 | 3 | .DEFAULT_GOAL = package 4 | 5 | ### VARIABLES ### 6 | # 7 | 8 | ### TARGETS ### 9 | # 10 | 11 | .PHONY: package 12 | package: clean ## Build the binary distribution 13 | ./mvnw package -Dmaven.test.skip 14 | 15 | .PHONY: docker-image 16 | docker-image: package ## Build Docker image 17 | @docker build --tag pivotalrabbitmq/github-release-delete-resource:latest . 18 | 19 | .PHONY: push-docker-image 20 | push-docker-image: docker-image ## Push Docker image 21 | @docker push pivotalrabbitmq/github-release-delete-resource:latest 22 | 23 | .PHONY: clean 24 | clean: ## Clean all build artefacts 25 | ./mvnw clean 26 | 27 | .PHONY: compile 28 | compile: ## Compile the source code 29 | ./mvnw compile 30 | 31 | .PHONY: test 32 | test: ## Run tests 33 | ./mvnw test -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | wrapperVersion=3.3.2 18 | distributionType=only-script 19 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip 20 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:24.04 AS builder 2 | 3 | RUN set -eux; \ 4 | apt-get update; \ 5 | apt-get -y upgrade; \ 6 | apt-get install --yes --no-install-recommends \ 7 | ca-certificates \ 8 | wget \ 9 | jq 10 | 11 | ARG JAVA_VERSION="21" 12 | 13 | RUN ARCH="x86"; BUNDLE="jdk"; \ 14 | wget "https://api.azul.com/zulu/download/community/v1.0/bundles/latest/?java_version=$JAVA_VERSION&ext=tar.gz&os=linux&arch=$ARCH&hw_bitness=64&release_status=ga&bundle_type=$BUNDLE" -O jdk-info.json 15 | 16 | RUN wget --progress=bar:force:noscroll -O "jdk.tar.gz" $(cat jdk-info.json | jq --raw-output .url) 17 | RUN echo "$(cat jdk-info.json | jq --raw-output .sha256_hash) *jdk.tar.gz" | sha256sum --check --strict - 18 | 19 | RUN set -eux; \ 20 | JAVA_PATH="/usr/lib/jdk-$JAVA_VERSION"; \ 21 | mkdir $JAVA_PATH && \ 22 | tar --extract --file jdk.tar.gz --directory "$JAVA_PATH" --strip-components 1; \ 23 | $JAVA_PATH/bin/jlink --compress=zip-6 --output /jre --add-modules java.base,jdk.crypto.cryptoki,java.net.http; \ 24 | /jre/bin/java -version \ 25 | ; \ 26 | mkdir -p /app 27 | 28 | COPY target/github-release-delete-resource.jar /app 29 | 30 | FROM ubuntu:24.04 31 | 32 | RUN set -eux; \ 33 | \ 34 | apt-get update; \ 35 | apt-get -y upgrade; \ 36 | apt-get install --yes --no-install-recommends \ 37 | ca-certificates \ 38 | ; \ 39 | rm -rf /var/lib/apt/lists/* 40 | 41 | ENV LANG=en_US.UTF-8 42 | ENV LANGUAGE=en_US:en 43 | 44 | ENV JAVA_HOME=/usr/lib/jvm/java-21-openjdk/jre 45 | RUN mkdir -p $JAVA_HOME 46 | COPY --from=builder /jre $JAVA_HOME/ 47 | RUN ln -svT $JAVA_HOME/bin/java /usr/local/bin/java 48 | 49 | COPY --from=builder /app/* /opt/resource/ 50 | RUN set -eux; \ 51 | java -jar /opt/resource/github-release-delete-resource.jar test 52 | 53 | RUN groupadd --gid 1042 concourse 54 | RUN useradd --uid 1042 --gid concourse --comment "concourse user" concourse 55 | 56 | USER concourse:concourse 57 | 58 | COPY scripts/* /opt/resource/ 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | [![Build (Linux)](https://github.com/rabbitmq/github-release-delete-resource/actions/workflows/test-linux.yml/badge.svg)](https://github.com/rabbitmq/github-release-delete-resource/actions/workflows/test-linux.yml) 4 | 5 | This is a Concourse resource to delete a GitHub releases and their corresponding tags. 6 | 7 | # Building 8 | 9 | To run tests: 10 | 11 | ```shell 12 | make test 13 | ``` 14 | 15 | To push the Docker image: 16 | 17 | ```shell 18 | make push-docker-image 19 | ``` 20 | 21 | # Usage 22 | 23 | ## Source Configuration 24 | 25 | * `owner`: *Required.* The GitHub user or organization name for the repository 26 | that the releases are in. 27 | * `repository`: *Required.* The repository name that contains the releases. 28 | * `access_token`: *Required.* API token used for all requests. 29 | 30 | ## Behaviour 31 | 32 | ### `check`: Does nothing. Should not be used. 33 | 34 | ### `in`: Does nothing. Should not be used. 35 | 36 | ### `out`: Delete GitHub releases. 37 | 38 | ### Parameters 39 | 40 | * `tag_filter`: *Required.* A Java regex to target the to-be-deleted releases. 41 | * `keep_last_n`: *Required.* The number of releases to keep. 42 | 43 | # Examples 44 | 45 | ```yaml 46 | # declare the resource type 47 | --- 48 | resource_types: 49 | - name: github-release-delete 50 | type: docker-image 51 | source: 52 | repository: pivotalrabbitmq/github-release-delete-resource 53 | tag: latest 54 | 55 | # declare a repository with releases to delete 56 | resources: 57 | - name: rabbitmq-java-tools-dev-delete 58 | type: github-release-delete 59 | source: 60 | owner: rabbitmq 61 | repository: rabbitmq-java-tools-binaries-dev 62 | access_token: token 63 | 64 | # in job definition 65 | - put: rabbitmq-java-tools-dev-delete 66 | params: 67 | tag_filter: '^v-stream-perf-test-0.1.0-SNAPSHOT-[0-9]{8}-[0-9]{6}$' 68 | keep_last_n: 2 69 | ``` 70 | 71 | # License and Copyright 72 | 73 | (c) 2021-2023 Broadcom. All Rights Reserved. 74 | The term Broadcom refers to Broadcom Inc. and/or its subsidiaries. 75 | 76 | This package, the Concourse GitHub Release Delete Resource, is licensed 77 | under the Mozilla Public License 2.0 ("MPL"). 78 | 79 | See [LICENSE](./LICENSE). 80 | -------------------------------------------------------------------------------- /src/test/java/com/rabbitmq/concourse/GithubReleaseDeleteResourceTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this 4 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 5 | */ 6 | package com.rabbitmq.concourse; 7 | 8 | import static com.rabbitmq.concourse.GithubReleaseDeleteResource.filterByTag; 9 | import static com.rabbitmq.concourse.GithubReleaseDeleteResource.filterForDeletion; 10 | import static org.assertj.core.api.Assertions.assertThat; 11 | 12 | import com.rabbitmq.concourse.GithubReleaseDeleteResource.Input; 13 | import com.rabbitmq.concourse.GithubReleaseDeleteResource.Release; 14 | import java.time.ZonedDateTime; 15 | import java.time.format.DateTimeFormatter; 16 | import java.util.Arrays; 17 | import java.util.List; 18 | import org.junit.jupiter.api.Test; 19 | 20 | public class GithubReleaseDeleteResourceTest { 21 | 22 | static final String SAMPLE = 23 | "{\n" 24 | + " \"source\": {\n" 25 | + " \"owner\": \"rabbitmq\",\n" 26 | + " \"repository\": \"rabbitmq-server\",\n" 27 | + " \"access_token\": \"42\"\n" 28 | + " },\n" 29 | + " \"params\": {\n" 30 | + " \"tag_filter\": \"some regex pattern\",\n" 31 | + " \"keep_last_n\": 3\n" 32 | + " }\n" 33 | + "}"; 34 | 35 | static Release rTag(long id, String tag) { 36 | return new Release(id, tag); 37 | } 38 | 39 | static Release rDate(long id, String date) { 40 | return new Release( 41 | id, ZonedDateTime.parse(date + "T08:38:25Z", DateTimeFormatter.ISO_ZONED_DATE_TIME)); 42 | } 43 | 44 | @Test 45 | void parseInput() { 46 | Input input = GithubReleaseDeleteResource.GSON.fromJson(SAMPLE, Input.class); 47 | assertThat(input.source()).isNotNull(); 48 | assertThat(input.source().owner()).isEqualTo("rabbitmq"); 49 | assertThat(input.source().repository()).isEqualTo("rabbitmq-server"); 50 | assertThat(input.source().accessToken()).isEqualTo("42"); 51 | 52 | assertThat(input.params()).isNotNull(); 53 | assertThat(input.params().tagFilter()).isEqualTo("some regex pattern"); 54 | assertThat(input.params().keepLastN()).isEqualTo(3); 55 | } 56 | 57 | @Test 58 | void filterByTagTest() { 59 | List releases = 60 | Arrays.asList( 61 | rTag(1, "v3.9.0-alpha-stream.1"), 62 | rTag(2, "v3.9.0-alpha-stream.2"), 63 | rTag(10, "v3.8.14-alpha.2"), 64 | rTag(3, "v3.9.0-alpha-stream.3"), 65 | rTag(11, "v3.8.9-alpha.8"), 66 | rTag(12, "v3.9.0-alpha.470"), 67 | rTag(4, "v3.9.0-alpha-stream.4"), 68 | rTag(13, "v4.0.0-alpha.51")); 69 | 70 | List filtered = filterByTag(releases, "^v(3.9.0-alpha-stream.[0-9]+)$"); 71 | 72 | assertThat(filtered.stream().mapToLong(r -> r.id())) 73 | .hasSize(4) 74 | .containsExactlyInAnyOrder(1L, 2L, 3L, 4L); 75 | 76 | filtered = filterByTag(releases, "^v([0-9].[0-9].[0-9]+-alpha.[0-9]+)$"); 77 | 78 | assertThat(filtered.stream().mapToLong(r -> r.id())) 79 | .hasSize(4) 80 | .containsExactlyInAnyOrder(10L, 11L, 12L, 13L); 81 | 82 | filtered = filterByTag(releases, "^v(3.8.[0-9]+-alpha.[0-9]+)$"); 83 | 84 | assertThat(filtered.stream().mapToLong(r -> r.id())) 85 | .hasSize(2) 86 | .containsExactlyInAnyOrder(10L, 11L); 87 | } 88 | 89 | @Test 90 | void filterForDeletionTest() { 91 | List releases = 92 | Arrays.asList( 93 | rDate(1L, "2021-01-01"), 94 | rDate(3L, "2021-01-03"), 95 | rDate(4L, "2021-01-04"), 96 | rDate(2L, "2021-01-02"), 97 | rDate(8L, "2021-01-08"), 98 | rDate(6L, "2021-01-06"), 99 | rDate(9L, "2021-01-09"), 100 | rDate(7L, "2021-01-07"), 101 | rDate(5L, "2021-01-05")); 102 | 103 | assertThat(filterForDeletion(releases, 3).stream().mapToLong(r -> r.id())) 104 | .hasSize(6) 105 | .containsExactlyInAnyOrder(1L, 2L, 3L, 4L, 5L, 6L); 106 | 107 | assertThat(filterForDeletion(releases, releases.size() - 1).stream().mapToLong(r -> r.id())) 108 | .hasSize(1) 109 | .containsExactlyInAnyOrder(1L); 110 | 111 | assertThat(filterForDeletion(releases, 0)).hasSameSizeAs(releases).hasSameElementsAs(releases); 112 | 113 | assertThat(filterForDeletion(releases, releases.size() + 1)).isEmpty(); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.rabbitmq 8 | github-release-delete-resource 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | MPL 2.0 14 | https://www.mozilla.org/en-US/MPL/2.0/ 15 | repo 16 | 17 | 18 | 19 | 20 | 21 | info@rabbitmq.com 22 | Team RabbitMQ 23 | Broadcom Inc. and its subsidiaries. 24 | https://rabbitmq.com 25 | 26 | 27 | 28 | 29 | UTF-8 30 | UTF-8 31 | 2.13.1 32 | 5.13.4 33 | 3.5.5 34 | 3.27.4 35 | 5.19.0 36 | 2.46.1 37 | 3.14.0 38 | 3.5.3 39 | 3.4.2 40 | 21 41 | 21 42 | 43 | 44 | 45 | 46 | 47 | com.google.code.gson 48 | gson 49 | ${gson.version} 50 | 51 | 52 | 53 | org.junit.jupiter 54 | junit-jupiter-engine 55 | ${junit.jupiter.version} 56 | test 57 | 58 | 59 | 60 | org.assertj 61 | assertj-core 62 | ${assertj.version} 63 | test 64 | 65 | 66 | 67 | org.mockito 68 | mockito-core 69 | ${mockito.version} 70 | test 71 | 72 | 73 | 74 | 75 | 76 | 77 | ${project.artifactId} 78 | 79 | 80 | 81 | 82 | org.apache.maven.plugins 83 | maven-compiler-plugin 84 | ${maven.compiler.plugin.version} 85 | 86 | 21 87 | 21 88 | 89 | 90 | 91 | 92 | maven-surefire-plugin 93 | ${maven-surefire-plugin.version} 94 | 95 | 96 | true 97 | 98 | 99 | 100 | 101 | 102 | org.springframework.boot 103 | spring-boot-maven-plugin 104 | ${spring-boot-maven-plugin.version} 105 | 106 | 107 | 108 | repackage 109 | 110 | 111 | 112 | 113 | com.rabbitmq.concourse.GithubReleaseDeleteResource 114 | 115 | 116 | 117 | 118 | com.diffplug.spotless 119 | spotless-maven-plugin 120 | ${spotless.version} 121 | 122 | 123 | 124 | 1.21.0 125 | 126 | 127 | 128 | 129 | /* 130 | * This Source Code Form is subject to the terms of the Mozilla Public 131 | * License, v. 2.0. If a copy of the MPL was not distributed with this 132 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 133 | */ 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /src/test/java/com/rabbitmq/concourse/ReleaseTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this 4 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 5 | */ 6 | package com.rabbitmq.concourse; 7 | 8 | import static org.assertj.core.api.Assertions.assertThat; 9 | 10 | import com.rabbitmq.concourse.GithubReleaseDeleteResource.Release; 11 | import java.time.ZonedDateTime; 12 | import java.time.format.DateTimeFormatter; 13 | import org.junit.jupiter.api.Test; 14 | 15 | public class ReleaseTest { 16 | 17 | static final String SAMPLE = 18 | "{\n" 19 | + " \"url\": \"https://api.github.com/repos/rabbitmq/rabbitmq-server-binaries-dev/releases/39045306\",\n" 20 | + " \"assets_url\": \"https://api.github.com/repos/rabbitmq/rabbitmq-server-binaries-dev/releases/39045306/assets\",\n" 21 | + " \"upload_url\": \"https://uploads.github.com/repos/rabbitmq/rabbitmq-server-binaries-dev/releases/39045306/assets{?name,label}\",\n" 22 | + " \"html_url\": \"https://github.com/rabbitmq/rabbitmq-server-binaries-dev/releases/tag/v3.9.0-alpha-stream.4\",\n" 23 | + " \"id\": 39045306,\n" 24 | + " \"author\": {\n" 25 | + " \"login\": \"rabbitmq-ci\",\n" 26 | + " \"id\": 71012429,\n" 27 | + " \"node_id\": \"MDQ6VXNlcjcxMDEyNDI5\",\n" 28 | + " \"avatar_url\": \"https://avatars.githubusercontent.com/u/71012429?v=4\",\n" 29 | + " \"gravatar_id\": \"\",\n" 30 | + " \"url\": \"https://api.github.com/users/rabbitmq-ci\",\n" 31 | + " \"html_url\": \"https://github.com/rabbitmq-ci\",\n" 32 | + " \"followers_url\": \"https://api.github.com/users/rabbitmq-ci/followers\",\n" 33 | + " \"following_url\": \"https://api.github.com/users/rabbitmq-ci/following{/other_user}\",\n" 34 | + " \"gists_url\": \"https://api.github.com/users/rabbitmq-ci/gists{/gist_id}\",\n" 35 | + " \"starred_url\": \"https://api.github.com/users/rabbitmq-ci/starred{/owner}{/repo}\",\n" 36 | + " \"subscriptions_url\": \"https://api.github.com/users/rabbitmq-ci/subscriptions\",\n" 37 | + " \"organizations_url\": \"https://api.github.com/users/rabbitmq-ci/orgs\",\n" 38 | + " \"repos_url\": \"https://api.github.com/users/rabbitmq-ci/repos\",\n" 39 | + " \"events_url\": \"https://api.github.com/users/rabbitmq-ci/events{/privacy}\",\n" 40 | + " \"received_events_url\": \"https://api.github.com/users/rabbitmq-ci/received_events\",\n" 41 | + " \"type\": \"User\",\n" 42 | + " \"site_admin\": false\n" 43 | + " },\n" 44 | + " \"node_id\": \"MDc6UmVsZWFzZTM5MDQ1MzA2\",\n" 45 | + " \"tag_name\": \"v3.9.0-alpha-stream.4\",\n" 46 | + " \"target_commitish\": \"master\",\n" 47 | + " \"name\": \"3.9.0-alpha-stream.4\",\n" 48 | + " \"draft\": false,\n" 49 | + " \"prerelease\": true,\n" 50 | + " \"created_at\": \"2021-03-01T08:38:25Z\",\n" 51 | + " \"published_at\": \"2021-03-01T10:37:58Z\",\n" 52 | + " \"assets\": [\n" 53 | + " {\n" 54 | + " \"url\": \"https://api.github.com/repos/rabbitmq/rabbitmq-server-binaries-dev/releases/assets/32772090\",\n" 55 | + " \"id\": 32772090,\n" 56 | + " \"node_id\": \"MDEyOlJlbGVhc2VBc3NldDMyNzcyMDkw\",\n" 57 | + " \"name\": \"rabbitmq-server-generic-unix-3.9.0-alpha-stream.4.tar.xz\",\n" 58 | + " \"label\": \"\",\n" 59 | + " \"uploader\": {\n" 60 | + " \"login\": \"rabbitmq-ci\",\n" 61 | + " \"id\": 71012429,\n" 62 | + " \"node_id\": \"MDQ6VXNlcjcxMDEyNDI5\",\n" 63 | + " \"avatar_url\": \"https://avatars.githubusercontent.com/u/71012429?v=4\",\n" 64 | + " \"gravatar_id\": \"\",\n" 65 | + " \"url\": \"https://api.github.com/users/rabbitmq-ci\",\n" 66 | + " \"html_url\": \"https://github.com/rabbitmq-ci\",\n" 67 | + " \"followers_url\": \"https://api.github.com/users/rabbitmq-ci/followers\",\n" 68 | + " \"following_url\": \"https://api.github.com/users/rabbitmq-ci/following{/other_user}\",\n" 69 | + " \"gists_url\": \"https://api.github.com/users/rabbitmq-ci/gists{/gist_id}\",\n" 70 | + " \"starred_url\": \"https://api.github.com/users/rabbitmq-ci/starred{/owner}{/repo}\",\n" 71 | + " \"subscriptions_url\": \"https://api.github.com/users/rabbitmq-ci/subscriptions\",\n" 72 | + " \"organizations_url\": \"https://api.github.com/users/rabbitmq-ci/orgs\",\n" 73 | + " \"repos_url\": \"https://api.github.com/users/rabbitmq-ci/repos\",\n" 74 | + " \"events_url\": \"https://api.github.com/users/rabbitmq-ci/events{/privacy}\",\n" 75 | + " \"received_events_url\": \"https://api.github.com/users/rabbitmq-ci/received_events\",\n" 76 | + " \"type\": \"User\",\n" 77 | + " \"site_admin\": false\n" 78 | + " },\n" 79 | + " \"content_type\": \"application/octet-stream\",\n" 80 | + " \"state\": \"uploaded\",\n" 81 | + " \"size\": 21,\n" 82 | + " \"download_count\": 2,\n" 83 | + " \"created_at\": \"2021-03-01T10:37:58Z\",\n" 84 | + " \"updated_at\": \"2021-03-01T10:37:58Z\",\n" 85 | + " \"browser_download_url\": \"https://github.com/rabbitmq/rabbitmq-server-binaries-dev/releases/download/v3.9.0-alpha-stream.4/rabbitmq-server-generic-unix-3.9.0-alpha-stream.4.tar.xz\"\n" 86 | + " }\n" 87 | + " ],\n" 88 | + " \"tarball_url\": \"https://api.github.com/repos/rabbitmq/rabbitmq-server-binaries-dev/tarball/v3.9.0-alpha-stream.4\",\n" 89 | + " \"zipball_url\": \"https://api.github.com/repos/rabbitmq/rabbitmq-server-binaries-dev/zipball/v3.9.0-alpha-stream.4\",\n" 90 | + " \"body\": \"\"\n" 91 | + " }"; 92 | 93 | @Test 94 | void deserialize() { 95 | Release release = GithubReleaseDeleteResource.GSON.fromJson(SAMPLE, Release.class); 96 | assertThat(release.url()) 97 | .isEqualTo( 98 | "https://api.github.com/repos/rabbitmq/rabbitmq-server-binaries-dev/releases/39045306"); 99 | assertThat(release.id()).isEqualTo(39045306); 100 | assertThat(release.tag()).isEqualTo("v3.9.0-alpha-stream.4"); 101 | assertThat(release.publication()) 102 | .isEqualTo( 103 | ZonedDateTime.parse("2021-03-01T10:37:58Z", DateTimeFormatter.ISO_ZONED_DATE_TIME)); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | <# : batch portion 2 | @REM ---------------------------------------------------------------------------- 3 | @REM Licensed to the Apache Software Foundation (ASF) under one 4 | @REM or more contributor license agreements. See the NOTICE file 5 | @REM distributed with this work for additional information 6 | @REM regarding copyright ownership. The ASF licenses this file 7 | @REM to you under the Apache License, Version 2.0 (the 8 | @REM "License"); you may not use this file except in compliance 9 | @REM with the License. You may obtain a copy of the License at 10 | @REM 11 | @REM http://www.apache.org/licenses/LICENSE-2.0 12 | @REM 13 | @REM Unless required by applicable law or agreed to in writing, 14 | @REM software distributed under the License is distributed on an 15 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | @REM KIND, either express or implied. See the License for the 17 | @REM specific language governing permissions and limitations 18 | @REM under the License. 19 | @REM ---------------------------------------------------------------------------- 20 | 21 | @REM ---------------------------------------------------------------------------- 22 | @REM Apache Maven Wrapper startup batch script, version 3.3.2 23 | @REM 24 | @REM Optional ENV vars 25 | @REM MVNW_REPOURL - repo url base for downloading maven distribution 26 | @REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven 27 | @REM MVNW_VERBOSE - true: enable verbose log; others: silence the output 28 | @REM ---------------------------------------------------------------------------- 29 | 30 | @IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) 31 | @SET __MVNW_CMD__= 32 | @SET __MVNW_ERROR__= 33 | @SET __MVNW_PSMODULEP_SAVE=%PSModulePath% 34 | @SET PSModulePath= 35 | @FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( 36 | IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) 37 | ) 38 | @SET PSModulePath=%__MVNW_PSMODULEP_SAVE% 39 | @SET __MVNW_PSMODULEP_SAVE= 40 | @SET __MVNW_ARG0_NAME__= 41 | @SET MVNW_USERNAME= 42 | @SET MVNW_PASSWORD= 43 | @IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) 44 | @echo Cannot start maven from wrapper >&2 && exit /b 1 45 | @GOTO :EOF 46 | : end batch / begin powershell #> 47 | 48 | $ErrorActionPreference = "Stop" 49 | if ($env:MVNW_VERBOSE -eq "true") { 50 | $VerbosePreference = "Continue" 51 | } 52 | 53 | # calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties 54 | $distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl 55 | if (!$distributionUrl) { 56 | Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" 57 | } 58 | 59 | switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { 60 | "maven-mvnd-*" { 61 | $USE_MVND = $true 62 | $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" 63 | $MVN_CMD = "mvnd.cmd" 64 | break 65 | } 66 | default { 67 | $USE_MVND = $false 68 | $MVN_CMD = $script -replace '^mvnw','mvn' 69 | break 70 | } 71 | } 72 | 73 | # apply MVNW_REPOURL and calculate MAVEN_HOME 74 | # maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ 75 | if ($env:MVNW_REPOURL) { 76 | $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } 77 | $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" 78 | } 79 | $distributionUrlName = $distributionUrl -replace '^.*/','' 80 | $distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' 81 | $MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" 82 | if ($env:MAVEN_USER_HOME) { 83 | $MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain" 84 | } 85 | $MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' 86 | $MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" 87 | 88 | if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { 89 | Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" 90 | Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" 91 | exit $? 92 | } 93 | 94 | if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { 95 | Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" 96 | } 97 | 98 | # prepare tmp dir 99 | $TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile 100 | $TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" 101 | $TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null 102 | trap { 103 | if ($TMP_DOWNLOAD_DIR.Exists) { 104 | try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } 105 | catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } 106 | } 107 | } 108 | 109 | New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null 110 | 111 | # Download and Install Apache Maven 112 | Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." 113 | Write-Verbose "Downloading from: $distributionUrl" 114 | Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" 115 | 116 | $webclient = New-Object System.Net.WebClient 117 | if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { 118 | $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) 119 | } 120 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 121 | $webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null 122 | 123 | # If specified, validate the SHA-256 sum of the Maven distribution zip file 124 | $distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum 125 | if ($distributionSha256Sum) { 126 | if ($USE_MVND) { 127 | Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." 128 | } 129 | Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash 130 | if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { 131 | Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." 132 | } 133 | } 134 | 135 | # unzip and move 136 | Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null 137 | Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null 138 | try { 139 | Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null 140 | } catch { 141 | if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { 142 | Write-Error "fail to move MAVEN_HOME" 143 | } 144 | } finally { 145 | try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } 146 | catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } 147 | } 148 | 149 | Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" 150 | -------------------------------------------------------------------------------- /mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Apache Maven Wrapper startup batch script, version 3.3.2 23 | # 24 | # Optional ENV vars 25 | # ----------------- 26 | # JAVA_HOME - location of a JDK home dir, required when download maven via java source 27 | # MVNW_REPOURL - repo url base for downloading maven distribution 28 | # MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven 29 | # MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output 30 | # ---------------------------------------------------------------------------- 31 | 32 | set -euf 33 | [ "${MVNW_VERBOSE-}" != debug ] || set -x 34 | 35 | # OS specific support. 36 | native_path() { printf %s\\n "$1"; } 37 | case "$(uname)" in 38 | CYGWIN* | MINGW*) 39 | [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" 40 | native_path() { cygpath --path --windows "$1"; } 41 | ;; 42 | esac 43 | 44 | # set JAVACMD and JAVACCMD 45 | set_java_home() { 46 | # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched 47 | if [ -n "${JAVA_HOME-}" ]; then 48 | if [ -x "$JAVA_HOME/jre/sh/java" ]; then 49 | # IBM's JDK on AIX uses strange locations for the executables 50 | JAVACMD="$JAVA_HOME/jre/sh/java" 51 | JAVACCMD="$JAVA_HOME/jre/sh/javac" 52 | else 53 | JAVACMD="$JAVA_HOME/bin/java" 54 | JAVACCMD="$JAVA_HOME/bin/javac" 55 | 56 | if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then 57 | echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 58 | echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 59 | return 1 60 | fi 61 | fi 62 | else 63 | JAVACMD="$( 64 | 'set' +e 65 | 'unset' -f command 2>/dev/null 66 | 'command' -v java 67 | )" || : 68 | JAVACCMD="$( 69 | 'set' +e 70 | 'unset' -f command 2>/dev/null 71 | 'command' -v javac 72 | )" || : 73 | 74 | if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then 75 | echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 76 | return 1 77 | fi 78 | fi 79 | } 80 | 81 | # hash string like Java String::hashCode 82 | hash_string() { 83 | str="${1:-}" h=0 84 | while [ -n "$str" ]; do 85 | char="${str%"${str#?}"}" 86 | h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) 87 | str="${str#?}" 88 | done 89 | printf %x\\n $h 90 | } 91 | 92 | verbose() { :; } 93 | [ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } 94 | 95 | die() { 96 | printf %s\\n "$1" >&2 97 | exit 1 98 | } 99 | 100 | trim() { 101 | # MWRAPPER-139: 102 | # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. 103 | # Needed for removing poorly interpreted newline sequences when running in more 104 | # exotic environments such as mingw bash on Windows. 105 | printf "%s" "${1}" | tr -d '[:space:]' 106 | } 107 | 108 | # parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties 109 | while IFS="=" read -r key value; do 110 | case "${key-}" in 111 | distributionUrl) distributionUrl=$(trim "${value-}") ;; 112 | distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; 113 | esac 114 | done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties" 115 | [ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties" 116 | 117 | case "${distributionUrl##*/}" in 118 | maven-mvnd-*bin.*) 119 | MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ 120 | case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in 121 | *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; 122 | :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; 123 | :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; 124 | :Linux*x86_64*) distributionPlatform=linux-amd64 ;; 125 | *) 126 | echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 127 | distributionPlatform=linux-amd64 128 | ;; 129 | esac 130 | distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" 131 | ;; 132 | maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; 133 | *) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; 134 | esac 135 | 136 | # apply MVNW_REPOURL and calculate MAVEN_HOME 137 | # maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ 138 | [ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" 139 | distributionUrlName="${distributionUrl##*/}" 140 | distributionUrlNameMain="${distributionUrlName%.*}" 141 | distributionUrlNameMain="${distributionUrlNameMain%-bin}" 142 | MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" 143 | MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" 144 | 145 | exec_maven() { 146 | unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : 147 | exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" 148 | } 149 | 150 | if [ -d "$MAVEN_HOME" ]; then 151 | verbose "found existing MAVEN_HOME at $MAVEN_HOME" 152 | exec_maven "$@" 153 | fi 154 | 155 | case "${distributionUrl-}" in 156 | *?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; 157 | *) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; 158 | esac 159 | 160 | # prepare tmp dir 161 | if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then 162 | clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } 163 | trap clean HUP INT TERM EXIT 164 | else 165 | die "cannot create temp dir" 166 | fi 167 | 168 | mkdir -p -- "${MAVEN_HOME%/*}" 169 | 170 | # Download and Install Apache Maven 171 | verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." 172 | verbose "Downloading from: $distributionUrl" 173 | verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" 174 | 175 | # select .zip or .tar.gz 176 | if ! command -v unzip >/dev/null; then 177 | distributionUrl="${distributionUrl%.zip}.tar.gz" 178 | distributionUrlName="${distributionUrl##*/}" 179 | fi 180 | 181 | # verbose opt 182 | __MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' 183 | [ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v 184 | 185 | # normalize http auth 186 | case "${MVNW_PASSWORD:+has-password}" in 187 | '') MVNW_USERNAME='' MVNW_PASSWORD='' ;; 188 | has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; 189 | esac 190 | 191 | if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then 192 | verbose "Found wget ... using wget" 193 | wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" 194 | elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then 195 | verbose "Found curl ... using curl" 196 | curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" 197 | elif set_java_home; then 198 | verbose "Falling back to use Java to download" 199 | javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" 200 | targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" 201 | cat >"$javaSource" <<-END 202 | public class Downloader extends java.net.Authenticator 203 | { 204 | protected java.net.PasswordAuthentication getPasswordAuthentication() 205 | { 206 | return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); 207 | } 208 | public static void main( String[] args ) throws Exception 209 | { 210 | setDefault( new Downloader() ); 211 | java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); 212 | } 213 | } 214 | END 215 | # For Cygwin/MinGW, switch paths to Windows format before running javac and java 216 | verbose " - Compiling Downloader.java ..." 217 | "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" 218 | verbose " - Running Downloader.java ..." 219 | "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" 220 | fi 221 | 222 | # If specified, validate the SHA-256 sum of the Maven distribution zip file 223 | if [ -n "${distributionSha256Sum-}" ]; then 224 | distributionSha256Result=false 225 | if [ "$MVN_CMD" = mvnd.sh ]; then 226 | echo "Checksum validation is not supported for maven-mvnd." >&2 227 | echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 228 | exit 1 229 | elif command -v sha256sum >/dev/null; then 230 | if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then 231 | distributionSha256Result=true 232 | fi 233 | elif command -v shasum >/dev/null; then 234 | if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then 235 | distributionSha256Result=true 236 | fi 237 | else 238 | echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 239 | echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 240 | exit 1 241 | fi 242 | if [ $distributionSha256Result = false ]; then 243 | echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 244 | echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 245 | exit 1 246 | fi 247 | fi 248 | 249 | # unzip and move 250 | if command -v unzip >/dev/null; then 251 | unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" 252 | else 253 | tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" 254 | fi 255 | printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url" 256 | mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" 257 | 258 | clean || : 259 | exec_maven "$@" 260 | -------------------------------------------------------------------------------- /src/main/java/com/rabbitmq/concourse/GithubReleaseDeleteResource.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this 4 | * file, You can obtain one at https://mozilla.org/MPL/2.0/. 5 | */ 6 | package com.rabbitmq.concourse; 7 | 8 | import com.google.gson.Gson; 9 | import com.google.gson.GsonBuilder; 10 | import com.google.gson.JsonDeserializationContext; 11 | import com.google.gson.JsonDeserializer; 12 | import com.google.gson.JsonElement; 13 | import com.google.gson.JsonParseException; 14 | import com.google.gson.reflect.TypeToken; 15 | import java.lang.reflect.Type; 16 | import java.net.URI; 17 | import java.net.http.HttpClient; 18 | import java.net.http.HttpRequest; 19 | import java.net.http.HttpRequest.Builder; 20 | import java.net.http.HttpResponse; 21 | import java.net.http.HttpResponse.BodyHandlers; 22 | import java.time.Duration; 23 | import java.time.ZonedDateTime; 24 | import java.time.format.DateTimeFormatter; 25 | import java.util.ArrayList; 26 | import java.util.Collections; 27 | import java.util.Comparator; 28 | import java.util.List; 29 | import java.util.Objects; 30 | import java.util.Optional; 31 | import java.util.Scanner; 32 | import java.util.function.Consumer; 33 | import java.util.regex.Pattern; 34 | import java.util.stream.Collectors; 35 | 36 | public class GithubReleaseDeleteResource { 37 | 38 | static final Gson GSON = 39 | new GsonBuilder() 40 | .registerTypeAdapter(ZonedDateTime.class, new ZonedDateTimeDeserializer()) 41 | .create(); 42 | private static final String JSON_DELETED_VERSION = 43 | "{\n" + " \"version\": { \"version\": \"\" },\n" + " \"metadata\": [ ]\n" + "}"; 44 | 45 | public static void main(String[] args) { 46 | Scanner scanner = new Scanner(System.in); 47 | StringBuilder builder = new StringBuilder(); 48 | while (scanner.hasNextLine()) { 49 | String line = scanner.nextLine(); 50 | builder.append(line); 51 | } 52 | 53 | String command = args[0]; 54 | if ("in".equals(command)) { 55 | log("Getting special version is a no-op; returning it as is"); 56 | out(JSON_DELETED_VERSION); 57 | } else if ("out".equals(command)) { 58 | Input input = GSON.fromJson(builder.toString(), Input.class); 59 | ReleaseAccess access = new GitubRestApiReleaseAccess(input); 60 | 61 | List releases = access.list(); 62 | List filteredReleases = filterByTag(releases, input.params().tagFilter()); 63 | if (!filteredReleases.isEmpty()) { 64 | Collections.sort(filteredReleases, Comparator.comparing(Release::publication)); 65 | } 66 | List toDeleteReleases = 67 | filterForDeletion(filteredReleases, input.params().keepLastN()); 68 | 69 | logGreen("Tag filter: " + input.params().tagFilter()); 70 | 71 | filteredReleases.forEach( 72 | r -> { 73 | if (toDeleteReleases.contains(r)) { 74 | logYellow("Removing release with tag " + r.tag()); 75 | try { 76 | access.delete(r); 77 | access.deleteTag(r); 78 | } catch (Exception e) { 79 | logRed("Error while deleting release " + r + ": " + e.getMessage()); 80 | } 81 | } else { 82 | log(" Keeping release with tag " + r.tag()); 83 | } 84 | }); 85 | 86 | out(JSON_DELETED_VERSION); 87 | } else if ("test".equals(command)) { 88 | testSequence(); 89 | } else { 90 | throw new IllegalArgumentException("command not supported: " + command); 91 | } 92 | } 93 | 94 | private static void testSequence() { 95 | Consumer display = m -> logGreen(m); 96 | String message; 97 | int exitCode = 0; 98 | try { 99 | String testUri = "https://www.wikipedia.org/"; 100 | logYellow("Starting test sequence, trying to reach " + testUri); 101 | HttpRequest request = HttpRequest.newBuilder().uri(new URI(testUri)).GET().build(); 102 | HttpResponse response = 103 | HttpClient.newBuilder() 104 | .connectTimeout(Duration.ofSeconds(60)) 105 | .build() 106 | .send(request, BodyHandlers.discarding()); 107 | int statusClass = response.statusCode() - response.statusCode() % 100; 108 | message = "Response code is " + response.statusCode(); 109 | if (statusClass != 200) { 110 | display = m -> logRed(m); 111 | exitCode = 1; 112 | } 113 | } catch (Exception e) { 114 | message = "Error during test sequence: " + e.getMessage(); 115 | display = m -> logRed(m); 116 | exitCode = 1; 117 | } 118 | display.accept(message); 119 | System.exit(exitCode); 120 | } 121 | 122 | static void logGreen(String message) { 123 | log("\u001B[32m" + message + "\u001B[0m"); 124 | } 125 | 126 | static void logYellow(String message) { 127 | log("\u001B[33m" + message + "\u001B[0m"); 128 | } 129 | 130 | static void logRed(String message) { 131 | log("\u001B[31m" + message + "\u001B[0m"); 132 | } 133 | 134 | static void log(String message) { 135 | System.err.println(message); 136 | } 137 | 138 | static void out(String message) { 139 | System.out.println(message); 140 | } 141 | 142 | static List filterByTag(List releases, String tagRegex) { 143 | Pattern pattern = Pattern.compile(tagRegex); 144 | return releases.stream() 145 | .filter(r -> pattern.matcher(r.tag()).matches()) 146 | .collect(Collectors.toList()); 147 | } 148 | 149 | static List filterForDeletion(List releases, int keepLastN) { 150 | if (releases.isEmpty()) { 151 | return Collections.emptyList(); 152 | } else if (keepLastN <= 0) { 153 | // do not want to keep any, return all 154 | return releases; 155 | } else if (keepLastN >= releases.size()) { 156 | // we want to keep more than we have, so nothing to delete 157 | return Collections.emptyList(); 158 | } else { 159 | releases = new ArrayList<>(releases); 160 | Collections.sort(releases, Comparator.comparing(Release::publication)); 161 | return releases.subList(0, releases.size() - keepLastN); 162 | } 163 | } 164 | 165 | interface ReleaseAccess { 166 | 167 | List list(); 168 | 169 | void delete(Release release); 170 | 171 | void deleteTag(Release release); 172 | } 173 | 174 | static class GitubRestApiReleaseAccess implements ReleaseAccess { 175 | 176 | private final HttpClient client = 177 | HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(60)).build(); 178 | 179 | private final Input input; 180 | 181 | GitubRestApiReleaseAccess(Input input) { 182 | this.input = input; 183 | } 184 | 185 | static String nextLink(String linkHeader) { 186 | String nextLink = null; 187 | for (String link : linkHeader.split(",")) { 188 | // e.g. 189 | // ; rel="next" 190 | String[] urlRel = link.split(";"); 191 | if ("rel=\"next\"".equals(urlRel[1].trim())) { 192 | String url = urlRel[0].trim(); 193 | // removing the < and > 194 | nextLink = url.substring(1, url.length() - 1); 195 | } 196 | } 197 | return nextLink; 198 | } 199 | 200 | @Override 201 | public List list() { 202 | HttpRequest request = requestBuilder("/releases").GET().build(); 203 | try { 204 | Type type = TypeToken.getParameterized(List.class, Release.class).getType(); 205 | List releases = new ArrayList<>(); 206 | boolean hasMore = true; 207 | while (hasMore) { 208 | HttpResponse response = 209 | client.send(request, HttpResponse.BodyHandlers.ofString()); 210 | releases.addAll(GSON.fromJson(response.body(), type)); 211 | Optional link = response.headers().firstValue("link"); 212 | String nextLink; 213 | if (link.isPresent() && (nextLink = nextLink(link.get())) != null) { 214 | request = requestBuilder().uri(URI.create(nextLink)).GET().build(); 215 | } else { 216 | hasMore = false; 217 | } 218 | } 219 | return releases; 220 | } catch (Exception e) { 221 | throw new RuntimeException(e); 222 | } 223 | } 224 | 225 | @Override 226 | public void delete(Release release) { 227 | HttpRequest request = requestBuilder().DELETE().uri(URI.create(release.url())).build(); 228 | try { 229 | HttpResponse response = client.send(request, BodyHandlers.discarding()); 230 | // TODO check response code 231 | } catch (Exception e) { 232 | throw new RuntimeException(e); 233 | } 234 | } 235 | 236 | @Override 237 | public void deleteTag(Release release) { 238 | // https://api.github.com/repos/rabbitmq/rabbitmq-server-binaries-dev/git/refs/tags/v3.9.0-alpha-test.1 239 | HttpRequest request = requestBuilder("/git/refs/tags/" + release.tag()).DELETE().build(); 240 | try { 241 | HttpResponse response = client.send(request, BodyHandlers.discarding()); 242 | // TODO check response code 243 | } catch (Exception e) { 244 | throw new RuntimeException(e); 245 | } 246 | } 247 | 248 | private Builder requestBuilder() { 249 | return auth(HttpRequest.newBuilder()); 250 | } 251 | 252 | private Builder requestBuilder(String path) { 253 | return auth( 254 | HttpRequest.newBuilder() 255 | .uri( 256 | URI.create( 257 | "https://api.github.com/repos/" 258 | + input.source().owner() 259 | + "/" 260 | + input.source().repository() 261 | + path))); 262 | } 263 | 264 | private Builder auth(Builder builder) { 265 | return builder.setHeader("Authorization", "token " + input.source().accessToken()); 266 | } 267 | } 268 | 269 | static class ZonedDateTimeDeserializer implements JsonDeserializer { 270 | 271 | @Override 272 | public ZonedDateTime deserialize( 273 | JsonElement json, Type typeOfT, JsonDeserializationContext context) 274 | throws JsonParseException { 275 | return ZonedDateTime.parse(json.getAsString(), DateTimeFormatter.ISO_ZONED_DATE_TIME); 276 | } 277 | } 278 | 279 | static class Release { 280 | 281 | private long id; 282 | private String url; 283 | private ZonedDateTime published_at; 284 | private String tag_name; 285 | 286 | Release() {} 287 | 288 | Release(long id, String tag) { 289 | this.id = id; 290 | this.tag_name = tag; 291 | } 292 | 293 | Release(long id, ZonedDateTime published_at) { 294 | this.id = id; 295 | this.published_at = published_at; 296 | } 297 | 298 | long id() { 299 | return this.id; 300 | } 301 | 302 | String url() { 303 | return this.url; 304 | } 305 | 306 | String tag() { 307 | return this.tag_name; 308 | } 309 | 310 | ZonedDateTime publication() { 311 | return this.published_at; 312 | } 313 | 314 | @Override 315 | public String toString() { 316 | return "Release{" 317 | + "id=" 318 | + id 319 | + ", url='" 320 | + url 321 | + '\'' 322 | + ", published_at=" 323 | + published_at 324 | + ", tag_name='" 325 | + tag_name 326 | + '\'' 327 | + '}'; 328 | } 329 | 330 | @Override 331 | public boolean equals(Object o) { 332 | if (this == o) { 333 | return true; 334 | } 335 | if (o == null || getClass() != o.getClass()) { 336 | return false; 337 | } 338 | Release release = (Release) o; 339 | return id == release.id; 340 | } 341 | 342 | @Override 343 | public int hashCode() { 344 | return Objects.hash(id); 345 | } 346 | } 347 | 348 | static class Input { 349 | 350 | private Params params; 351 | private Source source; 352 | 353 | Params params() { 354 | return params; 355 | } 356 | 357 | Source source() { 358 | return source; 359 | } 360 | 361 | @Override 362 | public String toString() { 363 | return "Input{" + "params=" + params + ", source=" + source + '}'; 364 | } 365 | } 366 | 367 | static class Params { 368 | 369 | private String tag_filter; 370 | private int keep_last_n; 371 | 372 | String tagFilter() { 373 | return tag_filter; 374 | } 375 | 376 | int keepLastN() { 377 | return keep_last_n; 378 | } 379 | 380 | @Override 381 | public String toString() { 382 | return "Params{" + "tag_filter='" + tag_filter + '\'' + ", keep_last_n=" + keep_last_n + '}'; 383 | } 384 | } 385 | 386 | static class Source { 387 | 388 | private String owner; 389 | private String repository; 390 | private String access_token; 391 | 392 | String owner() { 393 | return owner; 394 | } 395 | 396 | String repository() { 397 | return repository; 398 | } 399 | 400 | String accessToken() { 401 | return access_token; 402 | } 403 | 404 | @Override 405 | public String toString() { 406 | return "Source{" 407 | + "owner='" 408 | + owner 409 | + '\'' 410 | + ", repository='" 411 | + repository 412 | + '\'' 413 | + ", access_token='" 414 | + access_token 415 | + '\'' 416 | + '}'; 417 | } 418 | } 419 | } 420 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. 374 | --------------------------------------------------------------------------------