ci: configure release-please (#5016)

- Configure release-please to automatically create pull requests and
  releases.
- Run release-please and tag update in the CD workflow.
- Update Git tags pointing to latest, major.minor, and major versions as
  part of the CD workflow.
- Remove workflows (draft-release, release) that are not necessary
  anymore, and related configuration files.
- Handle automatic updates to README.md, action.yml, and action.yaml
- Mount .github to /tmp/lint/.github so super-linter finds config files,
  and the GitHub Actions to lint.
This commit is contained in:
Marco Ferrari 2023-12-20 14:58:25 +01:00 committed by GitHub
parent 117318f55c
commit 93b5ede1e8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 168 additions and 244 deletions

10
.github/linters/.jscpd.json vendored Normal file
View file

@ -0,0 +1,10 @@
{
"absolute": true,
"ignore": [
"**/workflows/cd.yml"
],
"reporters": [
"consoleFull"
],
"threshold": 0
}

View file

@ -1,43 +0,0 @@
---
name-template: 'v$RESOLVED_VERSION'
tag-template: 'v$RESOLVED_VERSION'
template: |
# Changelog
$CHANGES
See details of [all code changes](https://github.com/super-linter/super-linter/compare/$PREVIOUS_TAG...v$RESOLVED_VERSION) since previous release
categories:
- title: '🚀 Features'
labels:
- 'feature'
- 'enhancement'
- title: '🐛 Bug Fixes'
labels:
- 'fix'
- 'bugfix'
- 'bug'
- title: '🧰 Maintenance'
labels:
- 'infrastructure'
- 'automation'
- 'documentation'
- 'performance'
- title: 'Dependency updates'
labels:
- 'dependencies'
change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
version-resolver:
major:
labels:
- 'breaking'
minor:
labels:
- 'enhancement'
patch:
labels:
- 'bug'
- 'maintenance'
- 'documentation'
- 'dependencies'
default: patch

View file

@ -0,0 +1 @@
{}

View file

@ -0,0 +1,14 @@
{
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
"packages": {
".": {
"changelog-path": "CHANGELOG.md",
"release-type": "simple",
"extra-files": [
"action.yml",
"README.md",
"slim/action.yaml"
]
}
}
}

View file

@ -156,3 +156,125 @@ jobs:
"zkoppert", "Hanse00", "ferrarimarco"
]
})
release:
name: Release
needs:
- test
runs-on: ubuntu-latest
concurrency:
group: ${{ github.workflow }}-main-${{ matrix.images.environment }}
cancel-in-progress: true
permissions:
contents: write
deployments: write
issues: write
packages: write
pull-requests: write
strategy:
fail-fast: false
matrix:
images:
- environment: Release-SLIM
prefix: slim-
- environment: Release
prefix: ""
timeout-minutes: 60
steps:
- uses: google-github-actions/release-please-action@v4
id: release
with:
config-file: .github/release-please/release-please-config.json
manifest-file: .github/release-please/.release-please-manifest.json
token: ${{ secrets.GITHUB_TOKEN }}
- name: Start ${{ matrix.images.environment }} Deployment
if: steps.release.outputs.release_created
uses: bobheadxi/deployments@v1.4.0
id: deployment
with:
step: start
token: ${{ secrets.GITHUB_TOKEN }}
env: ${{ matrix.images.environment }}
- name: Configure release metedata
# shellcheck disable=SC2062
run: |
RELEASE_VERSION="${{ steps.release.outputs.tag_name }}"
if [ -z "${RELEASE_VERSION}" ]; then
echo "Error RELEASE_VERSION is empty. Exiting..."
exit 1
fi
if ! echo "${RELEASE_VERSION}" | grep -E -o "v[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+"; then
echo "Error: RELEASE_VERSION doesn't look like a semantic version: ${RELEASE_VERSION}"
exit 2
fi
SEMVER_MAJOR_VERSION=v${{ steps.release.outputs.major }}
{
echo "RELEASE_VERSION=${RELEASE_VERSION}"
echo "SEMVER_MAJOR_VERSION=${SEMVER_MAJOR_VERSION}"
} >> "${GITHUB_ENV}"
- name: Login to GHCR
if: steps.release.outputs.release_created
uses: docker/login-action@v3.0.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# We don't rebuild the image to avoid that the latest tag and the release tags don't point to the very same container image.
# Instead, we pull the latest image and tag it.
- name: Retag and Push Images
if: steps.release.outputs.release_created
uses: akhilerm/tag-push-action@v2.1.0
with:
src: ghcr.io/super-linter/super-linter:${{ matrix.images.prefix }}latest
dst: |
ghcr.io/super-linter/super-linter:${{ matrix.images.prefix }}${{ env.SEMVER_MAJOR_VERSION }}
ghcr.io/super-linter/super-linter:${{ matrix.images.prefix }}${{ env.RELEASE_VERSION }}
# No need to tag major.minor.patch because that tag is automatically created when creating the release
- name: Tag major, minor, and latest versions
if: steps.release.outputs.release_created
run: |
git tag --annotate --force ${{ env.SEMVER_MAJOR_VERSION }} -m "Release ${{ env.SEMVER_MAJOR_VERSION }}"
git tag --annotate --force latest -m "Release latest (${{ env.RELEASE_VERSION }})"
git push --force origin ${{ env.SEMVER_MAJOR_VERSION }}
git push --force origin latest
- name: Update ${{ matrix.images.environment }} Deployment
uses: bobheadxi/deployments@v1.4.0
# We depend on the 'deployment' step outputs, so we can't run this step
# if the 'deployment' step didn't run. This can happen if any step
# before the 'deployment' step fails. That's why 'always()' is not
# suitable here.
if: steps.deployment.conclusion != 'cancelled' && steps.deployment.conclusion != 'skipped'
with:
step: finish
token: ${{ secrets.GITHUB_TOKEN }}
status: ${{ job.status }}
deployment_id: ${{ steps.deployment.outputs.deployment_id }}
env: ${{ steps.deployment.outputs.env }}
env_url: https://github.com/super-linter/super-linter
- name: Create Issue on Failure
uses: actions/github-script@v7
if: failure()
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: |
const create = await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: "Failed to deploy to production",
body: "Automation has failed us!\nMore information can be found at:\n - ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}",
assignees: [
"zkoppert", "Hanse00", "ferrarimarco"
]
})

View file

@ -1,35 +0,0 @@
---
####################################
####################################
## Draft releases on Push to main ##
####################################
####################################
name: Release Drafter
###########################
# Start on push to main #
###########################
on:
push:
# branches to consider in the event; optional, defaults to all
branches:
- main
#################
# Start the job #
#################
permissions:
contents: read
jobs:
update_release_draft:
permissions:
contents: write # for release-drafter/release-drafter to create a github release
pull-requests: write # for release-drafter/release-drafter to add label to PR
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
# Drafts your next Release notes as Pull Requests are merged into "master"
- uses: release-drafter/release-drafter@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View file

@ -1,138 +0,0 @@
---
name: Release
on:
release:
types: [published]
workflow_dispatch:
inputs:
release_version:
description: 'version to release. Ex: v4.3.2'
required: true
default: 'v'
jobs:
release:
name: Release Images
runs-on: ubuntu-latest
permissions:
contents: write
deployments: write
issues: write
packages: write
strategy:
fail-fast: false
matrix:
images:
- prefix: slim-
environment: Release-SLIM
- prefix: ""
environment: Release
timeout-minutes: 60
steps:
- name: Setup Docker BuildX
uses: docker/setup-buildx-action@v3.0.0
- name: Login to GHCR
uses: docker/login-action@v3.0.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Retrieve Current Release Version
# shellcheck disable=SC2062
run: |
RELEASE_VERSION="${{ github.event.release.name }}"
if [ -z "${RELEASE_VERSION}" ]; then
echo "No release version found in environment, using input..."
RELEASE_VERSION="${{ github.event.inputs.release_version }}"
fi
# Check the RELEASE_VERSION again
if [ -z "${RELEASE_VERSION}" ]; then
echo "Error RELEASE_VERSION is empty. Exiting..."
exit 1
fi
if ! echo "${RELEASE_VERSION}" | grep -E -o "v[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+"; then
echo "Error: RELEASE_VERSION doesn't look like a semantic version: ${RELEASE_VERSION}"
exit 2
fi
SEMVER_VERSION=${RELEASE_VERSION#v}
SEMVER_MAJOR_VERSION=${SEMVER_VERSION%%.*}
SEMVER_MAJOR_VERSION_WITH_PREFIX=v${SEMVER_MAJOR_VERSION}
{
echo "RELEASE_VERSION=${RELEASE_VERSION}"
echo "SEMVER_VERSION=${SEMVER_VERSION}"
echo "SEMVER_MAJOR_VERSION=${SEMVER_MAJOR_VERSION}"
echo "SEMVER_MAJOR_VERSION_WITH_PREFIX=${SEMVER_MAJOR_VERSION_WITH_PREFIX}"
} >> "${GITHUB_ENV}"
- name: Start ${{ matrix.images.environment }} Deployment
uses: bobheadxi/deployments@v1.4.0
id: deployment
with:
step: start
token: ${{ secrets.GITHUB_TOKEN }}
env: ${{ matrix.images.environment }}
# We don't rebuild the image to avoid that the latest tag and the release tags don't point to what the release tag is pointing to.
# Instead, we pull the latest image and tag it.
- name: Retag and Push Images
uses: akhilerm/tag-push-action@v2.1.0
with:
src: ghcr.io/super-linter/super-linter:${{ matrix.images.prefix }}latest
dst: |
ghcr.io/super-linter/super-linter:${{ matrix.images.prefix }}${{ env.SEMVER_MAJOR_VERSION_WITH_PREFIX }}
ghcr.io/super-linter/super-linter:${{ matrix.images.prefix }}${{ env.RELEASE_VERSION }}
- name: Checkout Code
uses: actions/checkout@v4
with:
ref: main
# Full git history is needed to get a proper list of commits and tags
fetch-depth: 0
# We use ^{} to recursively deference the tag to get the commit the tag is pointing at.
# Then, we use that reference to create new tags, so that the new tags point to the commit
# the original tag was pointing to, and not to the original tag.
# This notation is documented at https://git-scm.com/docs/gitrevisions#Documentation/gitrevisions.txt-emltrevgtemegemv0998em
- name: Update Major Version and Latest Git Tag
run: |
git tag --force "${SEMVER_MAJOR_VERSION_WITH_PREFIX}" "${RELEASE_VERSION}^{}"
git tag --force latest "${RELEASE_VERSION}^{}"
git push --force origin "refs/tags/${SEMVER_MAJOR_VERSION_WITH_PREFIX}" "refs/tags/latest"
- name: Update ${{ matrix.images.environment }} Deployment
uses: bobheadxi/deployments@v1.4.0
if: always()
with:
step: finish
token: ${{ secrets.GITHUB_TOKEN }}
status: ${{ job.status }}
deployment_id: ${{ steps.deployment.outputs.deployment_id }}
env: ${{ steps.deployment.outputs.env }}
env_url: https://github.com/super-linter/super-linter/releases/tag/${{ env.RELEASE_VERSION }}
- name: Create Issue on Failure
if: failure()
uses: actions/github-script@v7
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: |
const create = await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: "Failed to deploy release to production",
body: "Automation has failed us! Failed to push release ${{ env.RELEASE_VERSION }}\nMore information can be found at:\n - ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}",
assignees: [
'zkoppert',
'Hanse00',
'ferrarimarco'
]
})

View file

@ -117,6 +117,7 @@ validate-container-image-labels: ## Validate container image labels
$(BUILD_REVISION) \
$(BUILD_VERSION)
# Mount a directory that doesn't have too many files to keep this test short
.phony: test-find
test-find: ## Run super-linter on a subdirectory with USE_FIND_ALGORITHM=true
docker run \
@ -126,7 +127,7 @@ test-find: ## Run super-linter on a subdirectory with USE_FIND_ALGORITHM=true
-e ENABLE_GITHUB_ACTIONS_GROUP_TITLE=true \
-e DEFAULT_BRANCH=main \
-e USE_FIND_ALGORITHM=true \
-v "$(CURDIR)/.github":/tmp/lint \
-v "$(CURDIR)/.github":/tmp/lint/.github \
$(SUPER_LINTER_TEST_CONTAINER_URL)
.phony: lint-codebase

View file

@ -81,6 +81,8 @@ More in-depth [tutorial](https://www.youtube.com/watch?v=EDAmFKO4Zt0&t=118s) ava
To run super-linter as a GitHub Action, you do the following:
<!-- x-release-please-start-major -->
1. Create a new [GitHub Actions workflow](https://docs.github.com/en/actions/using-workflows/about-workflows#about-workflows) in your repository with the following content:
```yaml
@ -119,6 +121,8 @@ To run super-linter as a GitHub Action, you do the following:
1. Push the new commit to the remote repository.
1. Create a new pull request to observe the results.
<!-- x-release-please-end -->
## Add Super-Linter badge in your repository README
You can show Super-Linter status with a badge in your repository README:

View file

@ -4,7 +4,9 @@ author: 'GitHub'
description: 'It is a simple combination of various linters, written in bash, to help validate your source code.'
runs:
using: 'docker'
# x-release-please-start-major
image: 'docker://ghcr.io/super-linter/super-linter:v5'
# x-release-please-end
branding:
icon: 'check-square'
color: 'white'

View file

@ -1,32 +1,16 @@
# Creating Super-Linter Release
# Super-Linter releases
The Process to create a `Release` of the **super-linter/super-linter** is as follows:
The Process to create a super-linter release is as follows:
1. Merge the release pull request.
## Release workflows
Every push to the default branch triggers GitHub Actions workflows that:
- Build and deploy of super-linter container images:
- Every push to `master/main` triggers a build and deploy of the **super-linter/super-linter**
- This creates the following images:
- `super-linter/super-linter:latest`
- `super-linter/super-linter:slim-latest`
- This also causes the `Release drafter` action to update a new draft Release
When an *Admin* wants to create a Release, the process is as follows:
- The *Admin* pushes an update to `master/main` and updates the `action.yml` to point to the next **Release** version
- Example: `image: 'docker://ghcr.io/super-linter/super-linter:v4.6.2'` becomes: `image: 'docker://ghcr.io/super-linter/super-linter:v4.6.3'`
- Then the *admin* can go to the Release page and update the current `draft Release`
- The *Admin* will set the correct version strings, and update any additional information in the current `draft Release`
- Once the *Admin* is ready, they will select **Publish Release**
- This triggers the **GitHub Actions** to take the current codebase, and build the containers, and deploy to their locations
- This creates and pushes the following container images:
- `super-linter/super-linter:latest`
- `super-linter/super-linter:v4`
- `super-linter/super-linter:v4.6.3`
- `super-linter/super-linter:slim-latest`
- `super-linter/super-linter:slim-v4`
- `super-linter/super-linter:slim-v4.6.3`
- This also updates the `latest` and `vMAJOR` Git tags to point to the same commit that the release Git tag is pointing at.
- At this point, the Release is complete and images are available for general consumption
## Pitfalls and Issues
If the *Admin* Does not update the `action.yml` to the new version before the Release is published, then the Release will point back to the old version, and any Images will also be sent back to the previous version.
This is very much a chicken and the egg issue, but seems to be easily resolved by following the correct path.
- Update to the release pull request.

View file

@ -4,7 +4,9 @@ author: 'GitHub'
description: 'It is a simple combination of various linters, written in bash, to help validate your source code.'
runs:
using: 'docker'
# x-release-please-start-major
image: 'docker://ghcr.io/super-linter/super-linter:slim-v5'
# x-release-please-end
branding:
icon: 'check-square'
color: 'white'