diff --git a/.github/workflows/prepare-release-master.yml b/.github/workflows/prepare-release-master.yml new file mode 100644 index 00000000000..944e053bfec --- /dev/null +++ b/.github/workflows/prepare-release-master.yml @@ -0,0 +1,66 @@ +name: Prepare Release + +on: + workflow_dispatch: + branches: ["master"] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - uses: tibdex/github-app-token@v1 + id: generate-token + with: + app_id: ${{ secrets.APP_ID }} + private_key: ${{ secrets.APP_PRIVATE_KEY }} + - name: Set up Python 3.10 + uses: actions/setup-python@v4 + with: + python-version: '3.10' + - name: Set up Java 11 + uses: actions/setup-java@v4 + with: + java-version: 11 + distribution: temurin + server-id: central + server-username: MAVEN_USERNAME + server-password: MAVEN_PASSWORD + - name: Cache local Maven repository + uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + - name: Run prepare release script + id: prepare-release + run: | + export MY_POM_VERSION=`mvn -q -Dexec.executable="echo" -Dexec.args='${projects.version}' --non-recursive org.codehaus.mojo:exec-maven-plugin:1.3.1:exec` + if [[ $MY_POM_VERSION =~ ^.*SNAPSHOT$ ]]; + then + . ./CI/prepare-release.sh + echo "PREPARE_RELEASE_OK=yes" >> $GITHUB_ENV + else + echo "not preparing release for release version: " ${MY_POM_VERSION} + echo "PREPARE_RELEASE_OK=no" >> $GITHUB_ENV + fi + echo "SC_VERSION=$SC_VERSION" >> $GITHUB_ENV + echo "SC_NEXT_VERSION=$SC_NEXT_VERSION" >> $GITHUB_ENV + - name: Create Prepare Release Pull Request + uses: peter-evans/create-pull-request@v4 + if: env.PREPARE_RELEASE_OK == 'yes' + with: + token: ${{ steps.generate-token.outputs.token }} + commit-message: prepare release ${{ env.SC_VERSION }} + title: 'prepare release ${{ env.SC_VERSION }}' + branch: prepare-release-${{ env.SC_VERSION }} + env: + ACTIONS_ALLOW_UNSECURE_COMMANDS: true + MAVEN_USERNAME: ${{ secrets.MAVEN_CENTRAL_USERNAME }} + MAVEN_PASSWORD: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SC_VERSION: + SC_NEXT_VERSION: diff --git a/.github/workflows/release-master.yml b/.github/workflows/release-master.yml new file mode 100644 index 00000000000..3e792f1769f --- /dev/null +++ b/.github/workflows/release-master.yml @@ -0,0 +1,228 @@ +name: Release + +on: + workflow_dispatch: + branches: ["master"] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - uses: tibdex/github-app-token@v1 + id: generate-token + with: + app_id: ${{ secrets.APP_ID }} + private_key: ${{ secrets.APP_PRIVATE_KEY }} + - name: Set up Python 3.10 + uses: actions/setup-python@v4 + with: + python-version: '3.10' + - name: Set up Java 11 + uses: actions/setup-java@v4 + with: + java-version: 11 + distribution: temurin + server-id: central + server-username: MAVEN_USERNAME + server-password: MAVEN_PASSWORD + gpg-private-key: ${{ secrets.OSSRH_GPG_PRIVATE_KEY }} + - name: Cache local Maven repository + uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + - name: Run pre release script + id: preRelease + run: | + # export GPG_TTY=$(tty) + export MY_POM_VERSION=`mvn -q -Dexec.executable="echo" -Dexec.args='${projects.version}' --non-recursive org.codehaus.mojo:exec-maven-plugin:1.3.1:exec` + if [[ $MY_POM_VERSION =~ ^.*SNAPSHOT$ ]]; + then + echo "not releasing snapshot version: " ${MY_POM_VERSION} + echo "RELEASE_OK=no" >> $GITHUB_ENV + else + . ./CI/pre-release.sh + echo "RELEASE_OK=yes" >> $GITHUB_ENV + fi + echo "SC_VERSION=$SC_VERSION" >> $GITHUB_ENV + echo "SC_NEXT_VERSION=$SC_NEXT_VERSION" >> $GITHUB_ENV + echo "SC_LAST_RELEASE=$SC_LAST_RELEASE" >> $GITHUB_ENV + echo "SC_RELEASE_TAG=v$SC_VERSION" >> $GITHUB_ENV + - name: configure git user email + run: | + git config --global user.email "action@github.com" + git config --global user.name "GitHub Action" + git config --global hub.protocol https + git remote set-url origin https://\${{ secrets.GITHUB_TOKEN }}:x-oauth-basic@github.com/''' + 'swagger-api/swagger-codegen' + '''.git + - name: Run maven deploy/release + if: env.RELEASE_OK == 'yes' + run: | + mvn --no-transfer-progress -B -Prelease deploy + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: docker login + run: | + docker login --username=${{ secrets.DOCKERHUB_SB_USERNAME }} --password=${{ secrets.DOCKERHUB_SB_PASSWORD }} + set -e + - name: Build generator image and push + uses: docker/build-push-action@v5 + with: + context: ./modules/swagger-generator + push: true + platforms: linux/amd64,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x + provenance: false + tags: swaggerapi/swagger-generator:${{ env.SC_RELEASE_TAG }},swaggerapi/swagger-generator:latest + - name: Build CLI image and push + uses: docker/build-push-action@v5 + with: + context: ./modules/swagger-codegen-cli + push: true + platforms: linux/amd64,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x + provenance: false + tags: swaggerapi/swagger-codegen-cli:${{ env.SC_RELEASE_TAG }},swaggerapi/swagger-codegen-cli:latest + - name: Run post release script + id: postRelease + if: env.RELEASE_OK == 'yes' + run: | + . ./CI/post-release.sh + - name: Create Next Snapshot Pull Request + uses: peter-evans/create-pull-request@v4 + if: env.RELEASE_OK == 'yes' + with: + token: ${{ steps.generate-token.outputs.token }} + commit-message: bump snapshot ${{ env.SC_NEXT_VERSION }}-SNAPSHOT + title: 'bump snapshot ${{ env.SC_NEXT_VERSION }}-SNAPSHOT' + branch: bump-snap-${{ env.SC_NEXT_VERSION }}-SNAPSHOT + - name: deploy + run: | + echo "${{ env.SC_RELEASE_TAG }}" + + TOKEN="${{ secrets.RANCHER2_BEARER_TOKEN }}" + RANCHER_HOST="rancher.tools.swagger.io" + CLUSTER_ID="c-n8zp2" + NAMESPACE_NAME="swagger-oss" + K8S_OBJECT_TYPE="daemonsets" + K8S_OBJECT_NAME="swagger-generator" + DEPLOY_IMAGE="swaggerapi/swagger-generator:${{ env.SC_RELEASE_TAG }}" + + workloadStatus="" + getStatus() { + echo "Getting update status..." + if ! workloadStatus="$(curl -s -X GET \ + -H "Authorization: Bearer ${TOKEN}" \ + -H 'Content-Type: application/json' \ + "https://${RANCHER_HOST}/k8s/clusters/${CLUSTER_ID}/apis/apps/v1/namespaces/${NAMESPACE_NAME}/${K8S_OBJECT_TYPE}/${K8S_OBJECT_NAME}/status")" + then + echo 'ERROR - get status k8s API call failed!' + echo "Exiting build"... + exit 1 + fi + } + + # $1 = image to deploy + updateObject() { + local image="${1}" + echo "Updating image value..." + + if ! curl -s -X PATCH \ + -H "Authorization: Bearer ${TOKEN}" \ + -H 'Content-Type: application/json-patch+json' \ + "https://${RANCHER_HOST}/k8s/clusters/${CLUSTER_ID}/apis/apps/v1/namespaces/${NAMESPACE_NAME}/${K8S_OBJECT_TYPE}/${K8S_OBJECT_NAME}" \ + -d "[{\"op\": \"replace\", \"path\": \"/spec/template/spec/containers/0/image\", \"value\": \"${image}\"}]" + then + echo 'ERROR - image update k8s API call failed!' + echo "Exiting build..." + exit 1 + fi + } + + + # Check that the TAG is valid + if [[ ${{ env.SC_RELEASE_TAG }} =~ ^[vV]?[0-9]*\.[0-9]*\.[0-9]*$ ]]; then + echo "" + echo "This is a Valid TAG..." + + # Get current image/tag in case we need to rollback + getStatus + ROLLBACK_IMAGE="$(echo "${workloadStatus}" | jq -r '.spec.template.spec.containers[0].image')" + echo "" + echo "Current image: ${ROLLBACK_IMAGE}" + + # Update image and validate response + echo "" + updateObject "${DEPLOY_IMAGE}" + echo "" + + echo "" + echo "Waiting for pods to start..." + echo "" + sleep 60s + + # Get state of the k8s object. If numberReady == desiredNumberScheduled, consider the upgrade successful. Else raise error + getStatus + status="$(echo "${workloadStatus}" | jq '.status')" + echo "" + echo "${status}" + echo "" + + numberDesired="$(echo "${status}" | jq -r '.desiredNumberScheduled')" + numberReady="$(echo "${status}" | jq -r '.numberReady')" + + if (( numberReady == numberDesired )); then + echo "${K8S_OBJECT_NAME} has been upgraded to ${DEPLOY_IMAGE}" + + # If pods are not starting, rollback the upgrade and exit the build with error + else + echo "state = error...rolling back upgrade" + updateObject "${ROLLBACK_IMAGE}" + echo "" + + echo "" + echo "Waiting for rollback pods to start..." + echo "" + sleep 60s + + getStatus + status="$(echo "${workloadStatus}" | jq '.status')" + echo "" + echo "${status}" + echo "" + + numberDesired="$(echo "${status}" | jq -r '.desiredNumberScheduled')" + numberReady="$(echo "${status}" | jq -r '.numberReady')" + + if (( numberReady == numberDesired )); then + echo "Rollback to ${ROLLBACK_IMAGE} completed." + else + echo "FATAL - rollback failed" + fi + echo "Exiting Build..." + exit 1 + fi + + else + echo "This TAG is not in a valid format..." + echo "Exiting Build..." + exit 0 + fi + echo "Exiting Build..." + exit 0 + env: + SC_RELEASE_TAG: + ACTIONS_ALLOW_UNSECURE_COMMANDS: true + MAVEN_USERNAME: ${{ secrets.MAVEN_CENTRAL_USERNAME }} + MAVEN_PASSWORD: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SC_VERSION: + SC_NEXT_VERSION: + GPG_PRIVATE_KEY: ${{ secrets.OSSRH_GPG_PRIVATE_KEY }} + GPG_PASSPHRASE: ${{ secrets.OSSRH_GPG_PRIVATE_PASSPHRASE }} + GRADLE_PUBLISH_KEY: ${{ secrets.GRADLE_PUBLISH_KEY }} + GRADLE_PUBLISH_SECRET: ${{ secrets.GRADLE_PUBLISH_SECRET }} diff --git a/CI/CI.md b/CI/CI.md new file mode 100644 index 00000000000..e7477c2739b --- /dev/null +++ b/CI/CI.md @@ -0,0 +1,88 @@ +## Continuous integration + +### Build, test and deploy +Swagger Codegen uses Github actions to run jobs/checks building, testing and deploying snapshots on push and PR events. + +These github actions are configured in `.github/workflows`: + +* maven-master.yml : Build Test Deploy master +* maven-master-pulls.yml Build Test PR + + +These actions use available actions in combination with short bash scripts. + +### Release + +Releases are semi-automated and consist in 2 actions using available public actions in combination with bash and python scripts. +**TODO**: Python code is used for historical reasons to execute GitHub APIs calls, in general a more consistent environment would +be more maintainable e.g. implementing a custom JavaScript or Docker Container GitHub Action and/or a bash only script(s). + +#### Workflow summary + +1. execute `prepare-release-master.yml` / `Prepare Release Master` for `master` branch +1. check and merge the Prepare Release PR pushed by previous step. Delete the branch +1. execute `release-master.yml` / `Release Master` for `master` branch +1. check and merge the next snaphot PR pushed by previous step. Delete the branch + +#### Prepare Release + +The first action to execute is `prepare-release-master.yml` / `Prepare Release Master` for master branch. + +This is triggered by manually executing the action, selecting `Actions` in project GitHub UI, then `Prepare Release Master` workflow +and clicking `Run Workflow` + +`Prepare Release Master` takes care of: + +* create release notes out of merged PRs +* Draft a release with related tag +* bump versions to release, and update all affected files +* build and test maven +* push a Pull Request with the changes for human check. + +After the PR checks complete, the PR can me merged, and the second phase `Release Master` started. + +#### Release + +Once prepare release PR has been merged, the second phase is provided by `release-master.yml` / `Release Master` actions for master branch. + +This is triggered by manually executing the action, selecting `Actions` in project GitHub UI, then `Release Master` workflow +and clicking `Run Workflow` + +`Release Master` takes care of: + +* build and test maven +* deploy/publish to maven central +* publish the previously prepared GitHub release / tag +* build and push docker image +* deploy/publish docker image to docker hub +* push PR for next snapshot + + + +### Secrets + +GitHub Actions make use of `Secrets` which can be configured either with Repo or Organization scope; the needed secrets are the following: + +* `APP_ID` and APP_PRIVATE_KEY`: these are the values provided by an account configured GitHub App, allowing to obtain a GitHub token +different from the default used in GitHub Actions (which does not allow to "chain" actions).Actions + +The GitHub App must be configured as detailed in [this doc](https://github.com/peter-evans/create-pull-request/blob/master/docs/concepts-guidelines.md#authenticating-with-github-app-generated-tokens). + +See also [here](https://github.com/peter-evans/create-pull-request/blob/master/docs/concepts-guidelines.md#triggering-further-workflow-runs) + +* `OSSRH_GPG_PRIVATE_KEY` and `OSSRH_GPG_PRIVATE_PASSPHRASE` : gpg key and passphrase to be used for sonatype releases +GPG private key and passphrase defined to be used for sonatype deployments, as detailed in +https://central.sonatype.org/pages/working-with-pgp-signatures.html (I'd say with email matching the one of the sonatype account of point 1 + +* `MAVEN_CENTRAL_USERNAME` and `MAVEN_CENTRAL_PASSWORD`: sonatype user/token + +* `GRADLE_PUBLISH_KEY` and `GRADLE_PUBLISH_SECRET`: credentials for https://plugins.gradle.org/ + + + + + + + + + diff --git a/CI/docker-release.sh b/CI/docker-release.sh new file mode 100755 index 00000000000..05049f0adad --- /dev/null +++ b/CI/docker-release.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +CUR=$(pwd) + +SC_RELEASE_TAG="v$SC_VERSION" + +echo "docker tag:" +echo "$SC_RELEASE_TAG" + +export DOCKER_VALIDATOR_IMAGE_NAME=swaggerapi/swagger-validator-v2 +docker build --rm=false -t $DOCKER_VALIDATOR_IMAGE_NAME:$SC_RELEASE_TAG . +docker tag $DOCKER_VALIDATOR_IMAGE_NAME:$SC_RELEASE_TAG $DOCKER_VALIDATOR_IMAGE_NAME:latest +docker push $DOCKER_VALIDATOR_IMAGE_NAME:$SC_RELEASE_TAG +docker push $DOCKER_VALIDATOR_IMAGE_NAME:latest +echo "docker images:" +docker images | grep -i validator diff --git a/CI/ghApiClient.py b/CI/ghApiClient.py new file mode 100755 index 00000000000..fcec1eace83 --- /dev/null +++ b/CI/ghApiClient.py @@ -0,0 +1,59 @@ +#!/usr/bin/python + +import os +import time +import urllib.request, urllib.error, urllib.parse +import http.client +import json + +GH_BASE_URL = "https://api.github.com/" + +GH_TOKEN = os.environ['GH_TOKEN'] +GH_AUTH = "Bearer %s" % GH_TOKEN + +def readUrl(name): + try: + request = urllib.request.Request(GH_BASE_URL + name) + request.add_header("Authorization", GH_AUTH) + content = urllib.request.urlopen(request).read() + jcont = json.loads(content) + return jcont + except urllib.error.HTTPError as e: + print(('HTTPError = ' + str(e.code))) + raise e + except urllib.error.URLError as e: + print(('URLError = ' + str(e.reason))) + raise e + except http.client.HTTPException as e: + print(('HTTPException = ' + str(e))) + raise e + except Exception: + import traceback + print(('generic exception: ' + traceback.format_exc())) + raise IOError + +def postUrl(name, body): + global GH_BASE_URL + try: + time.sleep(0.05) + request = urllib.request.Request(GH_BASE_URL + name) + request.add_header("Authorization", GH_AUTH) + request.add_header("Accept", "application/vnd.github.v3+json") + data = body.encode('utf-8') + content = urllib.request.urlopen(request, data).read() + jcont = json.loads(content) + return jcont + except urllib.error.HTTPError as e: + print(('HTTPError = ' + str(e.code))) + print((str(e))) + raise e + except urllib.error.URLError as e: + print(('URLError = ' + str(e.reason))) + raise e + except http.client.HTTPException as e: + print(('HTTPException = ' + str(e))) + raise e + except Exception: + import traceback + print(('generic exception: ' + traceback.format_exc())) + raise IOError diff --git a/CI/lastRelease.py b/CI/lastRelease.py new file mode 100755 index 00000000000..be39dd463da --- /dev/null +++ b/CI/lastRelease.py @@ -0,0 +1,19 @@ +#!/usr/bin/python + +import ghApiClient + +def getLastReleaseTag(): + content = ghApiClient.readUrl('repos/swagger-api/swagger-codegen/releases') + for l in content: + draft = l["draft"] + tag = l["tag_name"] + if str(draft) != 'True' and tag.startswith("v2"): + return tag[1:] + +# main +def main(): + result = getLastReleaseTag() + print (result) + +# here start main +main() diff --git a/CI/post-release.sh b/CI/post-release.sh new file mode 100755 index 00000000000..d9b55496f01 --- /dev/null +++ b/CI/post-release.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +CUR=$(pwd) +TMPDIR="$(dirname -- "${0}")" + +SC_RELEASE_TAG="v$SC_VERSION" + +##################### +### publish pre-prepared release (tag is created) +##################### +python $CUR/CI/publishRelease.py "$SC_RELEASE_TAG" + +##################### +### update the version to next snapshot in maven project with set version +##################### +mvn versions:set -DnewVersion="${SC_NEXT_VERSION}-SNAPSHOT" +mvn versions:commit diff --git a/CI/pre-release.sh b/CI/pre-release.sh new file mode 100755 index 00000000000..c4da53de5a1 --- /dev/null +++ b/CI/pre-release.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +CUR=$(pwd) + +export SC_VERSION=`mvn -q -Dexec.executable="echo" -Dexec.args='${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}' --non-recursive build-helper:parse-version org.codehaus.mojo:exec-maven-plugin:1.3.1:exec` +export SC_NEXT_VERSION=`mvn -q -Dexec.executable="echo" -Dexec.args='${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.nextIncrementalVersion}' --non-recursive build-helper:parse-version org.codehaus.mojo:exec-maven-plugin:1.3.1:exec` +SC_QUALIFIER=`mvn -q -Dexec.executable="echo" -Dexec.args='${parsedVersion.qualifier}' --non-recursive build-helper:parse-version org.codehaus.mojo:exec-maven-plugin:1.3.1:exec` +#SC_LAST_RELEASE=`mvn -q -Dexec.executable="echo" -Dexec.args='${releasedVersion.version}' --non-recursive org.codehaus.mojo:build-helper-maven-plugin:3.2.0:released-version org.codehaus.mojo:exec-maven-plugin:1.3.1:exec` +SC_LAST_RELEASE=`python $CUR/CI/lastRelease.py` + + +SC_RELEASE_TAG="v$SC_VERSION" + + +##################### +### build and test maven ### +##################### +mvn --no-transfer-progress -B install --file pom.xml diff --git a/CI/prepare-release.sh b/CI/prepare-release.sh new file mode 100755 index 00000000000..cec47db9d0c --- /dev/null +++ b/CI/prepare-release.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +CUR=$(pwd) + +export SC_VERSION=`mvn -q -Dexec.executable="echo" -Dexec.args='${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}' --non-recursive build-helper:parse-version org.codehaus.mojo:exec-maven-plugin:1.3.1:exec` +export SC_NEXT_VERSION=`mvn -q -Dexec.executable="echo" -Dexec.args='${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.nextIncrementalVersion}' --non-recursive build-helper:parse-version org.codehaus.mojo:exec-maven-plugin:1.3.1:exec` +SC_QUALIFIER=`mvn -q -Dexec.executable="echo" -Dexec.args='${parsedVersion.qualifier}' --non-recursive build-helper:parse-version org.codehaus.mojo:exec-maven-plugin:1.3.1:exec` +#SC_LAST_RELEASE=`mvn -q -Dexec.executable="echo" -Dexec.args='${releasedVersion.version}' --non-recursive org.codehaus.mojo:build-helper-maven-plugin:3.2.0:released-version org.codehaus.mojo:exec-maven-plugin:1.3.1:exec` +SC_LAST_RELEASE=`python $CUR/CI/lastRelease.py` + + + +SC_RELEASE_TITLE="Swagger Codegen $SC_VERSION released!" +SC_RELEASE_TAG="v$SC_VERSION" + + +##################### +### draft release Notes with next release after last release, with tag +##################### +python $CUR/CI/releaseNotes.py "$SC_LAST_RELEASE" "$SC_RELEASE_TITLE" "$SC_RELEASE_TAG" + +##################### +### update the version to release in maven project with set version +##################### +mvn versions:set -DnewVersion=$SC_VERSION +mvn versions:commit + +##################### +### build and test maven ### +##################### +mvn -B -U verify --file pom.xml diff --git a/CI/publishRelease.py b/CI/publishRelease.py new file mode 100755 index 00000000000..689fa0ea589 --- /dev/null +++ b/CI/publishRelease.py @@ -0,0 +1,27 @@ +#!/usr/bin/python + +import sys +import ghApiClient + +def lastReleaseId(tag): + content = ghApiClient.readUrl('repos/swagger-api/swagger-codegen/releases') + for l in content: + draft = l["draft"] + draft_tag = l["tag_name"] + if str(draft) == 'True' and tag == draft_tag: + return l["id"] + +def publishRelease(tag): + id = lastReleaseId(tag) + payload = "{\"tag_name\":\"" + tag + "\", " + payload += "\"draft\":" + "false" + ", " + payload += "\"target_commitish\":\"" + "master" + "\"}" + content = ghApiClient.postUrl('repos/swagger-api/swagger-codegen/releases/' + str(id), payload) + return content + +# main +def main(tag): + publishRelease (tag) + +# here start main +main(sys.argv[1]) diff --git a/CI/releaseNotes.py b/CI/releaseNotes.py new file mode 100755 index 00000000000..6bc0dff1b14 --- /dev/null +++ b/CI/releaseNotes.py @@ -0,0 +1,52 @@ +#!/usr/bin/python + +import sys +import json +from datetime import datetime +import ghApiClient + +def allPulls(releaseDate): + + result = "" + + baseurl = "https://api.github.com/repos/swagger-api/swagger-codegen/pulls/" + content = ghApiClient.readUrl('repos/swagger-api/swagger-codegen/pulls?state=closed&base=master&per_page=100') + for l in content: + stripped = l["url"][len(baseurl):] + mergedAt = l["merged_at"] + if mergedAt is not None: + if datetime.strptime(mergedAt, '%Y-%m-%dT%H:%M:%SZ') > releaseDate: + if not l['title'].startswith("bump snap"): + result += '\n' + result += "* " + l['title'] + " (#" + stripped + ")" + return result + + +def lastReleaseDate(tag): + content = ghApiClient.readUrl('repos/swagger-api/swagger-codegen/releases/tags/' + tag) + publishedAt = content["published_at"] + return datetime.strptime(publishedAt, '%Y-%m-%dT%H:%M:%SZ') + + +def addRelease(release_title, tag, content): + payload = "{\"tag_name\":\"" + tag + "\", " + payload += "\"name\":" + json.dumps(release_title) + ", " + payload += "\"body\":" + json.dumps(content) + ", " + payload += "\"draft\":" + "true" + ", " + payload += "\"prerelease\":" + "false" + ", " + payload += "\"target_commitish\":\"" + "master" + "\"}" + content = ghApiClient.postUrl('repos/swagger-api/swagger-codegen/releases', payload) + return content + +def getReleases(): + content = ghApiClient.readUrl('repos/swagger-api/swagger-codegen/releases') + return content + +# main +def main(last_release, release_title, tag): + result = allPulls(lastReleaseDate('v' + last_release)) + addRelease (release_title, tag, result) + +# here start main +main(sys.argv[1], sys.argv[2], sys.argv[3]) +