diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 0000000000..191ccd628f --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,26 @@ +changelog: + exclude: + labels: + - skip-changelog + categories: + - title: ๐Ÿš€ Features + labels: + - enhancement + - title: ๐Ÿ’ฃ Breaking Changes + labels: + - change + - title: ๐Ÿ› Bug Fixes + labels: + - bug + - title: ๐Ÿ“ Documentation + labels: + - documentation + - title: ๐Ÿงช Tests + labels: + - tests + - title: ๐Ÿ”จ Maintenance + labels: + - chore + - title: โฌ†๏ธ Dependencies + labels: + - dependencies diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c365e8cc7e..354bde9b1b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,9 +3,10 @@ name: Continuous Integration on: push: branches: - - 'main' + - main + - release-* tags: - - 'v[0-9]+.[0-9]+.[0-9]+' + - 'v[0-9]+.[0-9]+.[0-9]+*' paths-ignore: - '**.md' pull_request: @@ -119,16 +120,37 @@ jobs: key: nginx-kubernetes-gateway-${{ github.run_id }}-${{ github.run_number }} - name: Docker Buildx uses: docker/setup-buildx-action@v2 + - name: Login to GitHub Container Registry + uses: docker/login-action@v2 + if: ${{ startsWith(github.ref, 'refs/tags') }} + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Docker meta + id: meta + uses: docker/metadata-action@v4 + with: + images: | + name=ghcr.io/nginxinc/nginx-kubernetes-gateway + tags: | + type=semver,pattern={{version}} + type=edge + type=ref,event=pr + type=ref,event=branch,enable=${{ startsWith(github.ref, 'refs/heads/release') }} + flavor: | + latest=true - name: Build Image Debian uses: docker/build-push-action@v3 with: file: build/Dockerfile context: '.' target: local - load: true + tags: ${{ steps.meta.outputs.tags }} + load: ${{ !startsWith(github.ref, 'refs/tags') }} + push: ${{ startsWith(github.ref, 'refs/tags') }} cache-from: type=gha cache-to: type=gha,mode=max - tags: nginx/nginx-kubernetes-gateway:${{ needs.vars.outputs.sha }} build-args: | VERSION=${{ needs.vars.outputs.version }} GIT_COMMIT=${{ needs.vars.outputs.sha }} @@ -137,7 +159,7 @@ jobs: uses: aquasecurity/trivy-action@0.2.3 continue-on-error: true with: - image-ref: nginx/nginx-kubernetes-gateway:${{ needs.vars.outputs.sha }} + image-ref: ghcr.io/nginxinc/nginx-kubernetes-gateway:${{ steps.meta.outputs.version }} format: 'template' template: '@/contrib/sarif.tpl' output: 'trivy-results-nginx-kubernetes-gateway.sarif' diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000000..4921286bac --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,125 @@ +name: Create Draft Release + +on: + push: + branches: + - release-* + workflow_dispatch: + inputs: + tagFrom: + description: The tag to create the release from. + required: true + type: string + tagTo: + description: The tag to create the release to. + required: true + type: string + branch: + description: The branch where the release will be created. + required: true + type: string + +jobs: + + binary: + name: Create Draft Release + runs-on: ubuntu-20.04 + steps: + - uses: actions/setup-node@v3 + - run: npm install semver + - uses: actions/github-script@v6 + continue-on-error: true + with: + script: | + const semver = require('semver'); + const ref = context.ref.split("/")[2] + + const releases = (await github.rest.repos.listReleases({ + owner: context.payload.repository.owner.login, + repo: context.payload.repository.name, + per_page: 100, + })).data + + let latest_release + const latest_release_current_branch = releases.find(release => !release.draft && release.tag_name.startsWith("v" + ref.split("-")[1])) + + if (latest_release_current_branch === undefined){ + latest_release = (await github.rest.repos.getLatestRelease({ + owner: context.payload.repository.owner.login, + repo: context.payload.repository.name, + })).data.tag_name + } else { + latest_release = latest_release_current_branch.tag_name + } + + let tagFrom, tagTo, branch + if (context.eventName === 'workflow_dispatch'){ + console.log(`Dispatch run with inputs: ${JSON.stringify(context.payload.inputs)}`) + ;({ tagFrom, tagTo, branch } = context.payload.inputs) + } else { + ;({ tagFrom, tagTo, branch } = { + tagFrom: latest_release, + tagTo: 'next', + branch: ref, + }) + console.log(`Push run with: { tagFrom: ${tagFrom}, tagTo: ${tagTo}, branch: ${branch} }`) + } + console.log(`The latest release was ${tagFrom}`) + + let version = tagTo.replace('v', '') + if (version === 'next'){ + const temp_notes = (await github.rest.repos.generateReleaseNotes({ + owner: context.payload.repository.owner.login, + repo: context.payload.repository.name, + tag_name: tagTo, + previous_tag_name: tagFrom, + target_commitish: branch, + })).data.body + + let level + temp_notes.includes("### ๐Ÿš€ Features") ? level = 'minor' : level = 'patch' + temp_notes.includes("### ๐Ÿ’ฃ Breaking Changes") ? level = 'major' : level = level + version = semver.inc(tagFrom, level) + console.log(`The level of the release is ${level}`) + } + const draft = releases.find((r) => r.draft && r.tag_name === "v"+version) + const draft_found = !(draft === undefined) + + console.log(`The next version is v${version}`) + + const release_notes = (await github.rest.repos.generateReleaseNotes({ + owner: context.payload.repository.owner.login, + repo: context.payload.repository.name, + tag_name: 'v' + version, + previous_tag_name: tagFrom, + target_commitish: branch, + })) + + let release + if (draft_found){ + console.log("Draft found") + release = (await github.rest.repos.updateRelease({ + owner: context.payload.repository.owner.login, + repo: context.payload.repository.name, + release_id: draft.id, + tag_name: 'v' + version, + target_commitish: branch, + name: 'v' + version, + body: release_notes.data.body, + draft: true, + })) + } else { + console.log("Draft not found") + release = (await github.rest.repos.createRelease({ + owner: context.payload.repository.owner.login, + repo: context.payload.repository.name, + tag_name: 'v' + version, + target_commitish: ref, + name: 'v' + version, + body: release_notes.data.body, + draft: true, + })) + } + + console.log(`Release created: ${release.data.html_url}`) + console.log(`Release notes: ${release_notes.data.body}`)