mirror of
https://github.com/erlef/setup-beam.git
synced 2026-07-22 22:56:07 +00:00
Minor maintenance updates (#336)
This commit is contained in:
committed by
GitHub
parent
220876a6da
commit
e1b020163b
@@ -1,19 +0,0 @@
|
|||||||
---
|
|
||||||
env:
|
|
||||||
node: true
|
|
||||||
es2022: true
|
|
||||||
extends:
|
|
||||||
- eslint:recommended
|
|
||||||
parserOptions:
|
|
||||||
ecmaVersion: 2022
|
|
||||||
rules:
|
|
||||||
indent: [warn, 2, {SwitchCase: 1}]
|
|
||||||
max-len: [warn, 100]
|
|
||||||
no-use-before-define: 0
|
|
||||||
operator-linebreak: 0
|
|
||||||
semi: 0
|
|
||||||
implicit-arrow-linebreak: 0
|
|
||||||
|
|
||||||
settings:
|
|
||||||
react:
|
|
||||||
version: 999.999.999
|
|
||||||
@@ -52,6 +52,16 @@ jobs:
|
|||||||
- name: Check if build left artifacts
|
- name: Check if build left artifacts
|
||||||
run: git diff --exit-code --ignore-space-at-eol
|
run: git diff --exit-code --ignore-space-at-eol
|
||||||
|
|
||||||
|
check_action:
|
||||||
|
name: Action
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.ref != 'refs/heads/main'
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: raven-actions/actionlint@v2
|
||||||
|
|
||||||
unit_tests_ubuntu:
|
unit_tests_ubuntu:
|
||||||
name: Unit tests (Ubuntu)
|
name: Unit tests (Ubuntu)
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
@@ -64,6 +64,8 @@ jobs:
|
|||||||
rebar3-version: '3.18.0'
|
rebar3-version: '3.18.0'
|
||||||
os: 'macos-latest'
|
os: 'macos-latest'
|
||||||
version-type: 'strict'
|
version-type: 'strict'
|
||||||
|
escript_packages: 'hex protobuf'
|
||||||
|
escript_script: 'protoc-gen-elixir --version'
|
||||||
- otp-version: 'latest'
|
- otp-version: 'latest'
|
||||||
rebar3-version: 'latest'
|
rebar3-version: 'latest'
|
||||||
os: 'macos-latest'
|
os: 'macos-latest'
|
||||||
@@ -132,6 +134,6 @@ jobs:
|
|||||||
- run: env
|
- run: env
|
||||||
- name: Check environment variables
|
- name: Check environment variables
|
||||||
run: |
|
run: |
|
||||||
${INSTALL_DIR_FOR_ELIXIR}/bin/elixir -v
|
"${INSTALL_DIR_FOR_ELIXIR}"/bin/elixir -v
|
||||||
${INSTALL_DIR_FOR_OTP}/bin/erl -version
|
"${INSTALL_DIR_FOR_OTP}"/bin/erl -version
|
||||||
${INSTALL_DIR_FOR_REBAR3}/bin/rebar3 version
|
"${INSTALL_DIR_FOR_REBAR3}"/bin/rebar3 version
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ jobs:
|
|||||||
- run: env
|
- run: env
|
||||||
- name: Check environment variables
|
- name: Check environment variables
|
||||||
run: |
|
run: |
|
||||||
${INSTALL_DIR_FOR_ELIXIR}/bin/elixir -v
|
"${INSTALL_DIR_FOR_ELIXIR}"/bin/elixir -v
|
||||||
${INSTALL_DIR_FOR_GLEAM}/bin/gleam --version
|
"${INSTALL_DIR_FOR_GLEAM}"/bin/gleam --version
|
||||||
${INSTALL_DIR_FOR_OTP}/bin/erl -version
|
"${INSTALL_DIR_FOR_OTP}"/bin/erl -version
|
||||||
${INSTALL_DIR_FOR_REBAR3}/bin/rebar3 version
|
"${INSTALL_DIR_FOR_REBAR3}"/bin/rebar3 version
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ name: Update 3rd party licenses (automation)
|
|||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 12 * * *'
|
- cron: '0 12 * * *'
|
||||||
workflow_dispatch:
|
workflow_dispatch: {}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
update:
|
update:
|
||||||
|
|||||||
@@ -145,3 +145,4 @@ jobs:
|
|||||||
& "$Env:INSTALL_DIR_FOR_OTP/bin/erl.exe" "+V"
|
& "$Env:INSTALL_DIR_FOR_OTP/bin/erl.exe" "+V"
|
||||||
& "$Env:INSTALL_DIR_FOR_REBAR3/bin/rebar3.cmd" "version"
|
& "$Env:INSTALL_DIR_FOR_REBAR3/bin/rebar3.cmd" "version"
|
||||||
& "$Env:INSTALL_DIR_FOR_REBAR3/bin/rebar3.ps1" "version"
|
& "$Env:INSTALL_DIR_FOR_REBAR3/bin/rebar3.ps1" "version"
|
||||||
|
shell: pwsh
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
# Elixir Problem Matchers
|
# Elixir Problem Matchers
|
||||||
|
|
||||||
Elixir Problem Matchers in [elixir-matchers.json](matchers/elixir-matchers.json)
|
Elixir Problem Matchers in [elixir-matchers.json](matchers/elixir-matchers.json)
|
||||||
are adapted from [here](https://github.com/fr1zle/vscode-elixir/blob/45eddb589acd7ac98e0c7305d1c2b24668ca709a/package.json#L70-L118),
|
are adapted from [vscode-elixir/package.json](https://github.com/fr1zle/vscode-elixir/blob/45eddb589acd7ac98e0c7305d1c2b24668ca709a/package.json#L70-L118),
|
||||||
available under the [MIT license](https://github.com/fr1zle/vscode-elixir/blob/45eddb589acd7ac98e0c7305d1c2b24668ca709a/LICENSE.md):
|
available under the [MIT license](https://github.com/fr1zle/vscode-elixir/blob/45eddb589acd7ac98e0c7305d1c2b24668ca709a/LICENSE.md):
|
||||||
|
|
||||||
MIT License
|
MIT License
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ workflow by:
|
|||||||
- optionally, installing [Elixir](https://elixir-lang.org/)
|
- optionally, installing [Elixir](https://elixir-lang.org/)
|
||||||
- optionally, installing [Gleam](https://gleam.run/)
|
- optionally, installing [Gleam](https://gleam.run/)
|
||||||
- optionally, installing [`rebar3`](https://www.rebar3.org/)
|
- optionally, installing [`rebar3`](https://www.rebar3.org/)
|
||||||
- optionally, installing [`hex`](https://hex.pm/)
|
- optionally, installing [`local.hex`](https://hex.pm/)
|
||||||
|
- optionally, installing [`local.rebar`](https://www.rebar3.org/)
|
||||||
- optionally, opting for strict or loose version matching
|
- optionally, opting for strict or loose version matching
|
||||||
- optionally, having
|
- optionally, having
|
||||||
[problem matchers](https://github.com/actions/toolkit/blob/main/docs/problem-matchers.md) show
|
[problem matchers](https://github.com/actions/toolkit/blob/main/docs/problem-matchers.md) show
|
||||||
@@ -230,7 +231,7 @@ are found (i.e. `erl`, `erl.exe`, `rebar3`, `rebar3.exe`, ...).
|
|||||||
### Elixir Problem Matchers
|
### Elixir Problem Matchers
|
||||||
|
|
||||||
The Elixir Problem Matchers in this repository are adapted from
|
The Elixir Problem Matchers in this repository are adapted from
|
||||||
[here](https://github.com/fr1zle/vscode-elixir/blob/45eddb589acd7ac98e0c7305d1c2b24668ca709a/package.json#L70-L118).
|
[vscode-elixir/package.json](https://github.com/fr1zle/vscode-elixir/blob/45eddb589acd7ac98e0c7305d1c2b24668ca709a/package.json#L70-L118).
|
||||||
See [MATCHER_NOTICE](MATCHER_NOTICE.md) for license details.
|
See [MATCHER_NOTICE](MATCHER_NOTICE.md) for license details.
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|||||||
+33
@@ -1,11 +1,15 @@
|
|||||||
---
|
---
|
||||||
name: setup-beam
|
name: setup-beam
|
||||||
|
|
||||||
description: >
|
description: >
|
||||||
Set up a BEAM-based CI environment, supporting languages and tools such as Erlang/OTP, Elixir, Gleam, `rebar3`, and `hex`.
|
Set up a BEAM-based CI environment, supporting languages and tools such as Erlang/OTP, Elixir, Gleam, `rebar3`, and `hex`.
|
||||||
|
|
||||||
author: Erlang Ecosystem Foundation
|
author: Erlang Ecosystem Foundation
|
||||||
|
|
||||||
branding:
|
branding:
|
||||||
color: blue
|
color: blue
|
||||||
icon: code
|
icon: code
|
||||||
|
|
||||||
inputs:
|
inputs:
|
||||||
github-token:
|
github-token:
|
||||||
description: >
|
description: >
|
||||||
@@ -16,52 +20,81 @@ inputs:
|
|||||||
have to manually pass an automatically generated token via their environment settings within a workflow.
|
have to manually pass an automatically generated token via their environment settings within a workflow.
|
||||||
[Learn more about automatically generated tokens](https://docs.github.com/en/actions/security-guides/automatic-token-authentication)
|
[Learn more about automatically generated tokens](https://docs.github.com/en/actions/security-guides/automatic-token-authentication)
|
||||||
default: ${{ github.token }}
|
default: ${{ github.token }}
|
||||||
|
required: false
|
||||||
|
|
||||||
otp-version:
|
otp-version:
|
||||||
description: Version range or exact version of Erlang/OTP to use,
|
description: Version range or exact version of Erlang/OTP to use,
|
||||||
or false when installing only Gleam without OTP
|
or false when installing only Gleam without OTP
|
||||||
|
required: false
|
||||||
|
|
||||||
otp-architecture:
|
otp-architecture:
|
||||||
description: 32 or 64, to specify the architecture of the OTP to install. Only applies to Windows.
|
description: 32 or 64, to specify the architecture of the OTP to install. Only applies to Windows.
|
||||||
default: 64
|
default: 64
|
||||||
|
required: false
|
||||||
|
|
||||||
elixir-version:
|
elixir-version:
|
||||||
description: Version range or exact version of Elixir to use
|
description: Version range or exact version of Elixir to use
|
||||||
|
required: false
|
||||||
|
|
||||||
gleam-version:
|
gleam-version:
|
||||||
description: Version range or exact version of Gleam to use
|
description: Version range or exact version of Gleam to use
|
||||||
|
required: false
|
||||||
|
|
||||||
install-hex:
|
install-hex:
|
||||||
description: Whether to install Hex (with mix local.hex
|
description: Whether to install Hex (with mix local.hex
|
||||||
when installing Elixir)
|
when installing Elixir)
|
||||||
default: true
|
default: true
|
||||||
|
required: false
|
||||||
|
|
||||||
install-rebar:
|
install-rebar:
|
||||||
description: Whether to install Rebar (with mix local.rebar
|
description: Whether to install Rebar (with mix local.rebar
|
||||||
when installing Elixir)
|
when installing Elixir)
|
||||||
default: true
|
default: true
|
||||||
|
required: false
|
||||||
|
|
||||||
rebar3-version:
|
rebar3-version:
|
||||||
description: Version range or exact version of rebar3 to use (or nightly)
|
description: Version range or exact version of rebar3 to use (or nightly)
|
||||||
|
required: false
|
||||||
|
|
||||||
version-type:
|
version-type:
|
||||||
description: strict means the versions are take as-are; loose means we try
|
description: strict means the versions are take as-are; loose means we try
|
||||||
to guess versions based on semver rules
|
to guess versions based on semver rules
|
||||||
default: loose
|
default: loose
|
||||||
|
required: false
|
||||||
|
|
||||||
disable_problem_matchers:
|
disable_problem_matchers:
|
||||||
description: whether to have the problem matchers present in the results
|
description: whether to have the problem matchers present in the results
|
||||||
(or not)
|
(or not)
|
||||||
default: false
|
default: false
|
||||||
|
required: false
|
||||||
|
|
||||||
version-file:
|
version-file:
|
||||||
description: a versions file (e.g. as used by `asdf`), which defines inputs
|
description: a versions file (e.g. as used by `asdf`), which defines inputs
|
||||||
default: ''
|
default: ''
|
||||||
|
required: false
|
||||||
|
|
||||||
hexpm-mirrors:
|
hexpm-mirrors:
|
||||||
description: mirror(s) for hex.pm, one per line
|
description: mirror(s) for hex.pm, one per line
|
||||||
default: |
|
default: |
|
||||||
https://builds.hex.pm
|
https://builds.hex.pm
|
||||||
|
required: false
|
||||||
|
|
||||||
outputs:
|
outputs:
|
||||||
elixir-version:
|
elixir-version:
|
||||||
description: Exact version of Elixir that was installed
|
description: Exact version of Elixir that was installed
|
||||||
|
|
||||||
otp-version:
|
otp-version:
|
||||||
description: Exact version of Erlang/OTP that was installed
|
description: Exact version of Erlang/OTP that was installed
|
||||||
|
|
||||||
gleam-version:
|
gleam-version:
|
||||||
description: Exact version of Gleam that was installed
|
description: Exact version of Gleam that was installed
|
||||||
|
|
||||||
rebar3-version:
|
rebar3-version:
|
||||||
description: Exact version of rebar3 that was installed
|
description: Exact version of rebar3 that was installed
|
||||||
|
|
||||||
setup-beam-version:
|
setup-beam-version:
|
||||||
description: The commit unique id of the execution action version
|
description: The commit unique id of the execution action version
|
||||||
|
|
||||||
runs:
|
runs:
|
||||||
using: node20
|
using: node20
|
||||||
main: dist/index.js
|
main: dist/index.js
|
||||||
|
|||||||
Vendored
+17900
-1107
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,30 @@
|
|||||||
|
import js from '@eslint/js'
|
||||||
|
import globals from 'globals'
|
||||||
|
import { defineConfig } from 'eslint/config'
|
||||||
|
import eslintPluginYml from 'eslint-plugin-yml'
|
||||||
|
|
||||||
|
export default defineConfig([
|
||||||
|
...eslintPluginYml.configs['flat/recommended'],
|
||||||
|
{
|
||||||
|
extends: ['js/recommended'],
|
||||||
|
plugins: {
|
||||||
|
js,
|
||||||
|
},
|
||||||
|
languageOptions: {
|
||||||
|
ecmaVersion: 2022,
|
||||||
|
globals: {
|
||||||
|
...globals.node,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
extends: eslintPluginYml.configs['flat/recommended'],
|
||||||
|
files: ['*.yml'],
|
||||||
|
languageOptions: {
|
||||||
|
parserOptions: {
|
||||||
|
parser: 'yaml-eslint-parser',
|
||||||
|
defaultYAMLVersion: '1.2',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
Generated
+1329
-820
File diff suppressed because it is too large
Load Diff
+17
-14
@@ -4,32 +4,35 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "ncc build src/setup-beam.js --no-cache",
|
"build": "ncc build src/setup-beam.js --no-cache",
|
||||||
"format": "prettier src/**/*.js --write && prettier test/**/*.js --write",
|
"format": "prettier src/**/*.js test/**/*.js *.mjs --write",
|
||||||
"jslint": "eslint src/**/*.js && eslint test/**/*.js",
|
"eslint": "eslint src/**/*.js test/**/*.js *.mjs",
|
||||||
"licenses": "yarn licenses generate-disclaimer > 3RD_PARTY_LICENSES",
|
"licenses": "yarn licenses generate-disclaimer > 3RD_PARTY_LICENSES",
|
||||||
"markdownlint": "markdownlint *.md ./github/**/*.md",
|
"markdownlint": "markdownlint *.md ./github/**/*.md",
|
||||||
"shellcheck": "shellcheck .github/workflows/*.sh",
|
"shellcheck": "shellcheck .github/workflows/*.sh",
|
||||||
"test": "node --test --test-reporter=spec",
|
"test": "node --test --test-reporter=spec",
|
||||||
"yamllint": "yamllint .github/workflows/**.yml && yamllint .*.yml && yamllint *.yml",
|
"yamllint": "eslint .github/workflows/**.yml .*.yml *.yml",
|
||||||
"clean-dist": "rm -rf ./dist",
|
"clean-dist": "rm -rf ./dist",
|
||||||
"lint": "npm run markdownlint && npm run shellcheck && npm run yamllint && npm run jslint",
|
"lint": "npm run markdownlint && npm run shellcheck && npm run yamllint && npm run eslint",
|
||||||
"build-dist": "npm run clean-dist && npm install && npm run build && npm run format && npm run lint"
|
"build-dist": "npm run clean-dist && npm install && npm run build && npm run format && npm run lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "1.10.0",
|
"@actions/core": "1.11.1",
|
||||||
"@actions/exec": "1.1.1",
|
"@actions/exec": "1.1.1",
|
||||||
"@actions/tool-cache": "2.0.1",
|
"@actions/tool-cache": "2.0.2",
|
||||||
"csv-parse": "5.6.0",
|
"csv-parse": "5.6.0",
|
||||||
"semver": "7.6.2"
|
"semver": "7.7.2",
|
||||||
|
"lodash": "4.17.21"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vercel/ncc": "0.36.1",
|
"@vercel/ncc": "0.38.3",
|
||||||
"eslint": "8.43.0",
|
"eslint": "9.27.0",
|
||||||
"markdownlint-cli": "0.35.0",
|
"@eslint/js": "9.27.0",
|
||||||
"prettier": "2.8.8",
|
"globals": "16.2.0",
|
||||||
"shellcheck": "2.2.0",
|
"markdownlint-cli": "0.45.0",
|
||||||
"yaml-lint": "1.7.0",
|
"prettier": "3.5.3",
|
||||||
"yarn": "1.22.19"
|
"shellcheck": "3.1.0",
|
||||||
|
"eslint-plugin-yml": "1.18.0",
|
||||||
|
"yarn": "1.22.22"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20"
|
"node": ">=20"
|
||||||
|
|||||||
+19
-13
@@ -6,6 +6,7 @@ const semver = require('semver')
|
|||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const os = require('os')
|
const os = require('os')
|
||||||
const csv = require('csv-parse/sync')
|
const csv = require('csv-parse/sync')
|
||||||
|
const _ = require('lodash')
|
||||||
|
|
||||||
const MAX_HTTP_RETRIES = 3
|
const MAX_HTTP_RETRIES = 3
|
||||||
|
|
||||||
@@ -168,9 +169,8 @@ async function maybeInstallRebar3(rebar3Spec) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function getOTPVersion(otpSpec0, osVersion) {
|
async function getOTPVersion(otpSpec0, osVersion) {
|
||||||
const [otpVersions, originListing, hexMirrors] = await getOTPVersions(
|
const [otpVersions, originListing, hexMirrors] =
|
||||||
osVersion,
|
await getOTPVersions(osVersion)
|
||||||
)
|
|
||||||
let spec = otpSpec0.replace(/^OTP-/, '')
|
let spec = otpSpec0.replace(/^OTP-/, '')
|
||||||
const versions = otpVersions
|
const versions = otpVersions
|
||||||
const otpVersion = getVersionFromSpec(spec, versions)
|
const otpVersion = getVersionFromSpec(spec, versions)
|
||||||
@@ -266,6 +266,10 @@ async function getRebar3Version(r3Spec) {
|
|||||||
return rebar3Version
|
return rebar3Version
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function otpArchitecture() {
|
||||||
|
return getInput('otp-architecture', false)
|
||||||
|
}
|
||||||
|
|
||||||
async function getOTPVersions(osVersion) {
|
async function getOTPVersions(osVersion) {
|
||||||
let otpVersionsListings
|
let otpVersionsListings
|
||||||
let originListing
|
let originListing
|
||||||
@@ -321,8 +325,9 @@ async function getOTPVersions(osVersion) {
|
|||||||
otpVersions[otpVersion] = otpVersionOrig // we keep the original for later reference
|
otpVersions[otpVersion] = otpVersionOrig // we keep the original for later reference
|
||||||
})
|
})
|
||||||
} else if (process.platform === 'win32') {
|
} else if (process.platform === 'win32') {
|
||||||
|
const otpArch = otpArchitecture()
|
||||||
const file_regex = new RegExp(
|
const file_regex = new RegExp(
|
||||||
`^otp_win${getInput('otp-architecture')}_(.*).exe$`,
|
`^otp_win${_.escapeRegExp(otpArch)}_(.*).exe$`,
|
||||||
)
|
)
|
||||||
otpVersionsListings.forEach((otpVersionsListing) => {
|
otpVersionsListings.forEach((otpVersionsListing) => {
|
||||||
otpVersionsListing
|
otpVersionsListing
|
||||||
@@ -855,11 +860,13 @@ async function install(toolName, opts) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
win32: {
|
win32: {
|
||||||
downloadToolURL: () =>
|
downloadToolURL: () => {
|
||||||
|
const otpArch = otpArchitecture()
|
||||||
|
return (
|
||||||
'https://github.com/erlang/otp/releases/download/' +
|
'https://github.com/erlang/otp/releases/download/' +
|
||||||
`OTP-${toolVersion}/otp_win${getInput(
|
`OTP-${toolVersion}/otp_win${_.escapeRegExp(otpArch)}_${toolVersion}.exe`
|
||||||
'otp-architecture',
|
)
|
||||||
)}_${toolVersion}.exe`,
|
},
|
||||||
extract: async () => ['file', 'otp.exe'],
|
extract: async () => ['file', 'otp.exe'],
|
||||||
postExtract: async (cachePath) => {
|
postExtract: async (cachePath) => {
|
||||||
const cmd = path.join(cachePath, 'otp.exe')
|
const cmd = path.join(cachePath, 'otp.exe')
|
||||||
@@ -1140,16 +1147,15 @@ async function installTool(opts) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function checkOtpArchitecture() {
|
function checkOtpArchitecture() {
|
||||||
if (process.platform !== 'win32' && getInput('otp-architecture') == '32') {
|
const otpArch = otpArchitecture()
|
||||||
|
|
||||||
|
if (process.platform !== 'win32' && otpArch == '32') {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'@erlef/setup-beam only supports otp-architecture=32 on Windows',
|
'@erlef/setup-beam only supports otp-architecture=32 on Windows',
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (!['32', '64'].includes(otpArch)) {
|
||||||
getInput('otp-architecture') !== '32' &&
|
|
||||||
getInput('otp-architecture') !== '64'
|
|
||||||
) {
|
|
||||||
throw new Error('otp-architecture must be 32 or 64')
|
throw new Error('otp-architecture must be 32 or 64')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user