Skip to content
This repository was archived by the owner on Feb 3, 2026. It is now read-only.

feat: Implement the fmt.Stringer interface for User, Group, and Mapping structs #85

feat: Implement the fmt.Stringer interface for User, Group, and Mapping structs

feat: Implement the fmt.Stringer interface for User, Group, and Mapping structs #85

# Copyright 2025 The Authors (see AUTHORS file)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
name: 'lint'
# NOTE: This workflow is NOT intended to be a reusable workflow via
# workflow_call. Instead it will be "reused" by configuring via organization
# rulesets as a required workflow. As such, this workflow follows the naming
# convention for other workflow_call-able workflows in the abcxyz/actions
# respository.
on:
# Note that for org required workflows:
# "Any filters you specify for the supported events are ignored
# - for example, branches, branches-ignore, paths, types and so on."
# https://docs.github.com/en/enterprise-cloud@latest/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/available-rules-for-rulesets#supported-event-triggers
pull_request:
merge_group:
concurrency:
group: '${{ github.workflow }}-${{ github.head_ref || github.ref }}'
cancel-in-progress: true
jobs:
init:
runs-on: 'ubuntu-latest'
if: |
github.repository != 'abcxyz/actions'
outputs:
lint-targets: '${{ steps.lint-targets.outputs.lint-targets }}'
gomod-dirs: '${{ steps.lint-targets.outputs.gomod-dirs }}'
packagejson-dirs: '${{ steps.lint-targets.outputs.packagejson-dirs }}'
steps:
- name: 'Checkout'
uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # ratchet:actions/checkout@v4
with:
fetch-depth: 1 # shallow checkout
ref: '${{ github.event.pull_request.head.sha }}'
- name: 'Identify Lint Targets'
id: 'lint-targets'
env:
REF: '${{ github.event.pull_request.head.sha }}'
LC_ALL: 'C'
shell: 'bash'
run: |-
set -euo pipefail
# match_files determines if the current git repository has any files
# matching the given pattern. This has been performance tested
# against a shallow checkout of chromium (future changes should be
# tested in the same manner).
match_files() {
local filepattern="${1}"
matches="$(git ls-tree -r --name-only "${REF}" | grep -m 1 -E "${filepattern}")"
code="$?"
if [[ -n "${matches}" ]]; then
# Ignore exit codes because we found a match.
# Exit code 141 and higher may occur because we exit early.
return 0
fi
return "${code}"
}
find_dirs() {
local filepattern="${1}"
git ls-tree -r --name-only "${REF}" | grep -E "${filepattern}" | xargs -I {} bash -c 'echo $(dirname {})' | sort || true
}
to_json() {
local filepaths="${1}"
echo "${filepaths}" | jq -R -s -c 'split("\n")[:-1]' || true
}
# Go linting handled separtely from the rest of linting in order to
# shard linting across each go.mod file.
GOMOD_DIRS="$(find_dirs '(go.mod$)')"
if [[ -n "${GOMOD_DIRS}" ]]; then
GOMOD_DIRS_JSON="$(to_json "${GOMOD_DIRS}")"
echo "::debug::Found go.mod directories: ${GOMOD_DIRS_JSON}"
echo "gomod-dirs=${GOMOD_DIRS_JSON}" >> "${GITHUB_OUTPUT}"
fi
# Typescript linting handled separtely from the rest of linting in order to
# shard linting across each package.json file.
PACKAGEJSON_DIRS="$(find_dirs '(package.json$)')"
if [[ -n "${PACKAGEJSON_DIRS}" ]]; then
PACKAGEJSON_DIRS_JSON="$(to_json "${PACKAGEJSON_DIRS}")"
echo "::debug::Found package.json directories: ${PACKAGEJSON_DIRS_JSON}"
echo "packagejson-dirs=${PACKAGEJSON_DIRS_JSON}" >> "${GITHUB_OUTPUT}"
fi
declare -a TARGETS=()
if match_files '.*\.(java)$'; then
TARGETS+=("java")
fi
if match_files '.*\.(js)$'; then
TARGETS+=("javascript")
fi
if match_files '.*\.(sh)$'; then
TARGETS+=("shell")
fi
if match_files '.*\.(tf)$'; then
TARGETS+=("terraform")
fi
if match_files '.*\.(yaml|yml)$'; then
TARGETS+=("yaml")
fi
if match_files '.github/(actions|workflows)/.*\.(yaml|yml)$'; then
TARGETS+=("github" "ratchet")
fi
if match_files '.*(\.dockerfile|Dockerfile)$'; then
TARGETS+=("docker")
fi
LINT_TARGETS="$(jq --compact-output --null-input '$ARGS.positional' --args -- "${TARGETS[@]}")"
echo "::debug::Found lint targets: ${LINT_TARGETS}"
echo "lint-targets=${LINT_TARGETS}" >> "${GITHUB_OUTPUT}"
lint:
runs-on: |-
${{ vars.LINT_RUNS_ON || 'ubuntu-latest' }}
needs:
- 'init'
if: |
needs.init.outputs.lint-targets != '[]' && github.repository != 'abcxyz/actions'
permissions:
contents: 'read'
strategy:
fail-fast: false
max-parallel: 100
matrix:
lint-target: '${{ fromJSON(needs.init.outputs.lint-targets) }}'
env:
##############
## JAVA ######
##############
JAVA_LINT_GOOGLE_JAVA_FORMAT_VERSION: |-
${{ vars.JAVA_LINT_GOOGLE_JAVA_FORMAT_VERSION || '1.25.2' }}
JAVA_LINT_DIRECTORY: |-
${{ vars.JAVA_LINT_DIRECTORY || '.' }}
##############
## SHELL #####
##############
LINT_SHELL_TARGET: |-
${{ vars.LINT_SHELL_TARGET || '.' }}
##############
## TERRAFORM #
##############
TERRAFORM_LINT_TERRAFORM_VERSION: |-
${{ vars.TERRAFORM_LINT_TERRAFORM_VERSION }}
TERRAFORM_LINT_TERRAFORM_LINTER_VERSION: |-
${{ vars.TERRAFORM_LINT_TERRAFORM_LINTER_VERSION || '0.2.0' }}
TERRAFORM_LINT_DIRECTORY: |-
${{ vars.TERRAFORM_LINT_DIRECTORY || '' }}
##############
## YAML ######
##############
# The URL to a yamllint config file. This is only used if no file is found in the local directory.
YAML_LINT_YAMLLINT_URL: |-
${{ vars.YAML_LINT_YAMLLINT_URL || 'https://raw.githubusercontent.com/abcxyz/actions/main/.yamllint.yml' }}
# Version of yamllint linter to use
YAML_LINT_YAMLLINT_VERSION: |-
${{ vars.YAML_LINT_YAMLLINT_VERSION || '1.32.0' }}
# File or directory containing YAML files to lint.
YAML_LINT_TARGET: |-
${{ vars.YAML_LINT_TARGET || '.' }}
##############
## GITHUB ####
##############
# Note, must not start with GITHUB_
# https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables#naming-conventions-for-configuration-variables
ACTIONS_LINT_ACTIONLINT_VERSION: |-
${{ vars.ACTIONS_LINT_ACTIONLINT_VERSION || '1.7.7' }}
##############
## DOCKER ####
##############
DOCKER_LINT_DIRECTORY: |-
${{ vars.DOCKER_LINT_DIRECTORY || '.' }}
DOCKER_LINT_HADOLINT_CONFIG_URL: |-
${{ vars.DOCKER_LINT_HADOLINT_CONFIG_URL || 'https://raw.githubusercontent.com/abcxyz/actions/main/.hadolint.yml' }}
DOCKER_LINT_HADOLINT_VERSION: |-
${{ vars.DOCKER_LINT_HADOLINT_VERSION || '2.12.0' }}
steps:
- name: 'Checkout'
uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # ratchet:actions/checkout@v4
with:
fetch-depth: 1 # shallow clone
- name: '[JAVA] Lint Java'
if: |
matrix.lint-target == 'java'
uses: 'abcxyz/actions/.github/actions/lint-java@main' # ratchet:exclude
with:
google_java_format_version: '${{ env.JAVA_LINT_GOOGLE_JAVA_FORMAT_VERSION }}'
directory: '${{ env.JAVA_LINT_DIRECTORY }}'
github_token: '${{ secrets.GITHUB_TOKEN }}'
- name: '[JAVASCRIPT] Lint Javascript'
if: |
matrix.lint-target == 'javascript'
run: |-
echo "TODO: Lint javascript"
- name: '[TYPESCRIPT] Lint Typescript'
if: |
matrix.lint-target == 'typescript'
run: |-
echo "TODO: Lint typescript"
- name: '[SHELL] Lint Shell'
if: |
matrix.lint-target == 'shell'
uses: 'abcxyz/actions/.github/actions/lint-shell@main' # ratchet:exclude
with:
target: '${{ env.LINT_SHELL_TARGET }}'
- name: '[TERRAFORM] Lint Terraform'
if: |
matrix.lint-target == 'terraform'
uses: 'abcxyz/actions/.github/actions/lint-terraform@main' # ratchet:exclude
with:
terraform_version: '${{ env.TERRAFORM_LINT_TERRAFORM_VERSION }}'
terraform_linter_version: '${{ env.TERRAFORM_LINT_TERRAFORM_LINTER_VERSION }}'
directory: '${{ env.TERRAFORM_LINT_DIRECTORY }}'
- name: '[YAML] lint yaml'
if: |
matrix.lint-target == 'yaml'
uses: 'abcxyz/actions/.github/actions/lint-yaml@main' # ratchet:exclude
with:
yamllint_url: '${{ env.YAML_LINT_YAMLLINT_URL }}'
yamllint_version: '${{ env.YAML_LINT_YAMLLINT_VERSION }}'
target: '${{ env.YAML_LINT_TARGET }}'
- name: '[GITHUB] lint ratchet'
if: |
matrix.lint-target == 'ratchet'
uses: 'sethvargo/ratchet@db1c14407c5a1cac5ff7b956ce3b6fd8cbafd4ef' # ratchet:sethvargo/ratchet@main
with:
files: './.github/actions/**/*.yml ./.github/workflows/*.yml'
- name: '[GITHUB] lint actions'
if: |
matrix.lint-target == 'github'
uses: 'abcxyz/actions/.github/actions/lint-github-actions@main' # ratchet:exclude
with:
actionlint_version: '${{ env.ACTIONS_LINT_ACTIONLINT_VERSION }}'
- name: '[GITHUB] lint docker'
if: |
matrix.lint-target == 'docker'
uses: 'abcxyz/actions/.github/actions/lint-docker@main' # ratchet:exclude
with:
target: '${{ env.DOCKER_LINT_DIRECTORY }}'
hadolint_config_url: '${{ env.DOCKER_LINT_HADOLINT_CONFIG_URL }}'
hadolint_version: '${{ env.DOCKER_LINT_HADOLINT_VERSION }}'
lint-go:
runs-on: |-
${{ vars.LINT_RUNS_ON || 'ubuntu-latest' }}
needs:
- 'init'
if: |
needs.init.outputs.gomod-dirs != '' && needs.init.outputs.gomod-dirs != '[]' && github.repository != 'abcxyz/actions'
permissions:
contents: 'read'
strategy:
fail-fast: false
max-parallel: 100
matrix:
gomod-dir: '${{ fromJSON(needs.init.outputs.gomod-dirs) }}'
env:
##############
## GOLANG ####
##############
# The version of Go to install and use.
GO_LINT_GO_VERSION: |-
${{ vars.GO_LINT_GO_VERSION }}
# Path to the go.mod file to extract a version.
GO_LINT_GOLANGCI_URL: |-
${{ vars.GO_LINT_GOLANGCI_URL || 'https://raw.githubusercontent.com/abcxyz/actions/main/default.golangci.yml' }}
GO_LINT_GOLANGCI_LINT_VERSION: |-
${{ vars.GO_LINT_GOLANGCI_LINT_VERSION || 'v2.5' }}
steps:
- name: 'Checkout'
uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # ratchet:actions/checkout@v4
with:
fetch-depth: 1 # shallow clone
- name: '[GOLANG] Lint Go modules'
if: |
always() && !cancelled()
uses: 'abcxyz/actions/.github/actions/lint-go-modules@main' # ratchet:exclude
with:
go_version: '${{ env.GO_LINT_GO_VERSION }}'
go_version_file: '${{ matrix.gomod-dir }}/go.mod'
golangci_url: '${{ env.GO_LINT_GOLANGCI_URL }}'
directory: '${{ matrix.gomod-dir }}'
golangci_lint_version: '${{ env.GO_LINT_GOLANGCI_LINT_VERSION }}'
- name: '[GOLANG] Lint Go'
if: |
always() && !cancelled()
uses: 'abcxyz/actions/.github/actions/lint-go@main' # ratchet:exclude
with:
go_version: '${{ env.GO_LINT_GO_VERSION }}'
go_version_file: '${{ matrix.gomod-dir }}/go.mod'
golangci_url: '${{ env.GO_LINT_GOLANGCI_URL }}'
directory: '${{ matrix.gomod-dir }}'
golangci_lint_version: '${{ env.GO_LINT_GOLANGCI_LINT_VERSION }}'
lint-js-ts:
runs-on: |-
${{ vars.LINT_RUNS_ON || 'ubuntu-latest' }}
needs:
- 'init'
if: |
needs.init.outputs.packagejson-dirs != '' && needs.init.outputs.packagejson-dirs != '[]' && github.repository != 'abcxyz/actions'
permissions:
contents: 'read'
strategy:
fail-fast: false
max-parallel: 100
matrix:
packagejson-dir: '${{ fromJSON(needs.init.outputs.packagejson-dirs) }}'
steps:
- name: 'Checkout'
uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # ratchet:actions/checkout@v4
with:
fetch-depth: 1 # shallow clone
- name: '[JAVASCRIPT] Lint Javascript and Typescript'
uses: 'abcxyz/actions/.github/actions/lint-javascript@main' # ratchet:exclude
with:
directory: '${{ matrix.packagejson-dir }}'