diff --git a/.github/linters/.jscpd.json b/.github/linters/.jscpd.json new file mode 100644 index 00000000..6fec7687 --- /dev/null +++ b/.github/linters/.jscpd.json @@ -0,0 +1,10 @@ +{ + "absolute": true, + "ignore": [ + "**/workflows/cd.yml" + ], + "reporters": [ + "consoleFull" + ], + "threshold": 0 +} diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml deleted file mode 100644 index 38a6aa91..00000000 --- a/.github/release-drafter.yml +++ /dev/null @@ -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 diff --git a/.github/release-please/.release-please-manifest.json b/.github/release-please/.release-please-manifest.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/.github/release-please/.release-please-manifest.json @@ -0,0 +1 @@ +{} diff --git a/.github/release-please/release-please-config.json b/.github/release-please/release-please-config.json new file mode 100644 index 00000000..5ab4ba41 --- /dev/null +++ b/.github/release-please/release-please-config.json @@ -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" + ] + } + } +} diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 8ba7cb4a..01623b19 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -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" + ] + }) diff --git a/.github/workflows/draft-release.yml b/.github/workflows/draft-release.yml deleted file mode 100644 index 7a4af18d..00000000 --- a/.github/workflows/draft-release.yml +++ /dev/null @@ -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 }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 0087fa75..00000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -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' - ] - }) diff --git a/Makefile b/Makefile index c94ab446..44e9e60c 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/README.md b/README.md index 7f9e83f1..65dbb8c5 100644 --- a/README.md +++ b/README.md @@ -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: + + 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. + + ## Add Super-Linter badge in your repository README You can show Super-Linter status with a badge in your repository README: diff --git a/action.yml b/action.yml index f1eea7f8..ee84c834 100644 --- a/action.yml +++ b/action.yml @@ -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' diff --git a/docs/release-process.md b/docs/release-process.md index dc29ebf3..aff411ca 100644 --- a/docs/release-process.md +++ b/docs/release-process.md @@ -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. diff --git a/slim/action.yml b/slim/action.yml index dec89816..c2b22dce 100644 --- a/slim/action.yml +++ b/slim/action.yml @@ -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'