Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions .github/workflows/prepare-release-master.yml
Original file line number Diff line number Diff line change
@@ -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:
228 changes: 228 additions & 0 deletions .github/workflows/release-master.yml
Original file line number Diff line number Diff line change
@@ -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 }}
88 changes: 88 additions & 0 deletions CI/CI.md
Original file line number Diff line number Diff line change
@@ -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/









Loading
Loading