You've already forked setup-python
							
							
				mirror of
				https://github.com/actions/setup-python.git
				synced 2025-10-31 07:06:25 +07:00 
			
		
		
		
	Enhance reading from .python-version (#787)
* Enhance reading from .python-version * Fix typos * Fix lint * Add built files * Don't use EOL versions in `utils.test.ts` * Fix Prettier * Don't use unreleased versions in `utils.test.ts` * Update versions in `utils.test.ts` again
This commit is contained in:
		| @ -10,7 +10,7 @@ import { | |||||||
|   validatePythonVersionFormatForPyPy, |   validatePythonVersionFormatForPyPy, | ||||||
|   isCacheFeatureAvailable, |   isCacheFeatureAvailable, | ||||||
|   getVersionInputFromFile, |   getVersionInputFromFile, | ||||||
|   getVersionInputFromPlainFile, |   getVersionsInputFromPlainFile, | ||||||
|   getVersionInputFromTomlFile, |   getVersionInputFromTomlFile, | ||||||
|   getNextPageUrl, |   getNextPageUrl, | ||||||
|   isGhes, |   isGhes, | ||||||
| @ -24,10 +24,10 @@ jest.mock('@actions/core'); | |||||||
|  |  | ||||||
| describe('validatePythonVersionFormatForPyPy', () => { | describe('validatePythonVersionFormatForPyPy', () => { | ||||||
|   it.each([ |   it.each([ | ||||||
|     ['3.6', true], |     ['3.12', true], | ||||||
|     ['3.7', true], |     ['3.13', true], | ||||||
|     ['3.6.x', false], |     ['3.12.x', false], | ||||||
|     ['3.7.x', false], |     ['3.13.x', false], | ||||||
|     ['3.x', false], |     ['3.x', false], | ||||||
|     ['3', false] |     ['3', false] | ||||||
|   ])('%s -> %s', (input, expected) => { |   ])('%s -> %s', (input, expected) => { | ||||||
| @ -95,24 +95,52 @@ const tempDir = path.join( | |||||||
| ); | ); | ||||||
|  |  | ||||||
| describe('Version from file test', () => { | describe('Version from file test', () => { | ||||||
|   it.each([getVersionInputFromPlainFile, getVersionInputFromFile])( |   it.each([getVersionsInputFromPlainFile, getVersionInputFromFile])( | ||||||
|     'Version from plain file test', |     'Version from plain file test', | ||||||
|     async _fn => { |     async _fn => { | ||||||
|       await io.mkdirP(tempDir); |       await io.mkdirP(tempDir); | ||||||
|       const pythonVersionFileName = 'python-version.file'; |       const pythonVersionFileName = 'python-version.file'; | ||||||
|       const pythonVersionFilePath = path.join(tempDir, pythonVersionFileName); |       const pythonVersionFilePath = path.join(tempDir, pythonVersionFileName); | ||||||
|       const pythonVersionFileContent = '3.7'; |       const pythonVersionFileContent = '3.13'; | ||||||
|       fs.writeFileSync(pythonVersionFilePath, pythonVersionFileContent); |       fs.writeFileSync(pythonVersionFilePath, pythonVersionFileContent); | ||||||
|       expect(_fn(pythonVersionFilePath)).toEqual([pythonVersionFileContent]); |       expect(_fn(pythonVersionFilePath)).toEqual([pythonVersionFileContent]); | ||||||
|     } |     } | ||||||
|   ); |   ); | ||||||
|  |   it.each([getVersionsInputFromPlainFile, getVersionInputFromFile])( | ||||||
|  |     'Versions from multiline plain file test', | ||||||
|  |     async _fn => { | ||||||
|  |       await io.mkdirP(tempDir); | ||||||
|  |       const pythonVersionFileName = 'python-version.file'; | ||||||
|  |       const pythonVersionFilePath = path.join(tempDir, pythonVersionFileName); | ||||||
|  |       const pythonVersionFileContent = '3.13\r\n3.12'; | ||||||
|  |       fs.writeFileSync(pythonVersionFilePath, pythonVersionFileContent); | ||||||
|  |       expect(_fn(pythonVersionFilePath)).toEqual(['3.13', '3.12']); | ||||||
|  |     } | ||||||
|  |   ); | ||||||
|  |   it.each([getVersionsInputFromPlainFile, getVersionInputFromFile])( | ||||||
|  |     'Version from complex plain file test', | ||||||
|  |     async _fn => { | ||||||
|  |       await io.mkdirP(tempDir); | ||||||
|  |       const pythonVersionFileName = 'python-version.file'; | ||||||
|  |       const pythonVersionFilePath = path.join(tempDir, pythonVersionFileName); | ||||||
|  |       const pythonVersionFileContent = | ||||||
|  |         '3.13/envs/virtualenv\r# 3.12\n3.11\r\n3.10\r\n 3.9 \r\n'; | ||||||
|  |       fs.writeFileSync(pythonVersionFilePath, pythonVersionFileContent); | ||||||
|  |       expect(_fn(pythonVersionFilePath)).toEqual([ | ||||||
|  |         '3.13', | ||||||
|  |         '3.11', | ||||||
|  |         '3.10', | ||||||
|  |         '3.9' | ||||||
|  |       ]); | ||||||
|  |     } | ||||||
|  |   ); | ||||||
|   it.each([getVersionInputFromTomlFile, getVersionInputFromFile])( |   it.each([getVersionInputFromTomlFile, getVersionInputFromFile])( | ||||||
|     'Version from standard pyproject.toml test', |     'Version from standard pyproject.toml test', | ||||||
|     async _fn => { |     async _fn => { | ||||||
|       await io.mkdirP(tempDir); |       await io.mkdirP(tempDir); | ||||||
|       const pythonVersionFileName = 'pyproject.toml'; |       const pythonVersionFileName = 'pyproject.toml'; | ||||||
|       const pythonVersionFilePath = path.join(tempDir, pythonVersionFileName); |       const pythonVersionFilePath = path.join(tempDir, pythonVersionFileName); | ||||||
|       const pythonVersion = '>=3.7.0'; |       const pythonVersion = '>=3.13.0'; | ||||||
|       const pythonVersionFileContent = `[project]\nrequires-python = "${pythonVersion}"`; |       const pythonVersionFileContent = `[project]\nrequires-python = "${pythonVersion}"`; | ||||||
|       fs.writeFileSync(pythonVersionFilePath, pythonVersionFileContent); |       fs.writeFileSync(pythonVersionFilePath, pythonVersionFileContent); | ||||||
|       expect(_fn(pythonVersionFilePath)).toEqual([pythonVersion]); |       expect(_fn(pythonVersionFilePath)).toEqual([pythonVersion]); | ||||||
| @ -124,7 +152,7 @@ describe('Version from file test', () => { | |||||||
|       await io.mkdirP(tempDir); |       await io.mkdirP(tempDir); | ||||||
|       const pythonVersionFileName = 'pyproject.toml'; |       const pythonVersionFileName = 'pyproject.toml'; | ||||||
|       const pythonVersionFilePath = path.join(tempDir, pythonVersionFileName); |       const pythonVersionFilePath = path.join(tempDir, pythonVersionFileName); | ||||||
|       const pythonVersion = '>=3.7.0'; |       const pythonVersion = '>=3.13.0'; | ||||||
|       const pythonVersionFileContent = `[tool.poetry.dependencies]\npython = "${pythonVersion}"`; |       const pythonVersionFileContent = `[tool.poetry.dependencies]\npython = "${pythonVersion}"`; | ||||||
|       fs.writeFileSync(pythonVersionFilePath, pythonVersionFileContent); |       fs.writeFileSync(pythonVersionFilePath, pythonVersionFileContent); | ||||||
|       expect(_fn(pythonVersionFilePath)).toEqual([pythonVersion]); |       expect(_fn(pythonVersionFilePath)).toEqual([pythonVersion]); | ||||||
| @ -145,9 +173,9 @@ describe('Version from file test', () => { | |||||||
|     async _fn => { |     async _fn => { | ||||||
|       const toolVersionFileName = '.tool-versions'; |       const toolVersionFileName = '.tool-versions'; | ||||||
|       const toolVersionFilePath = path.join(tempDir, toolVersionFileName); |       const toolVersionFilePath = path.join(tempDir, toolVersionFileName); | ||||||
|       const toolVersionContent = 'python 3.9.10\nnodejs 16'; |       const toolVersionContent = 'python 3.13.2\nnodejs 16'; | ||||||
|       fs.writeFileSync(toolVersionFilePath, toolVersionContent); |       fs.writeFileSync(toolVersionFilePath, toolVersionContent); | ||||||
|       expect(_fn(toolVersionFilePath)).toEqual(['3.9.10']); |       expect(_fn(toolVersionFilePath)).toEqual(['3.13.2']); | ||||||
|     } |     } | ||||||
|   ); |   ); | ||||||
|  |  | ||||||
| @ -156,9 +184,9 @@ describe('Version from file test', () => { | |||||||
|     async _fn => { |     async _fn => { | ||||||
|       const toolVersionFileName = '.tool-versions'; |       const toolVersionFileName = '.tool-versions'; | ||||||
|       const toolVersionFilePath = path.join(tempDir, toolVersionFileName); |       const toolVersionFilePath = path.join(tempDir, toolVersionFileName); | ||||||
|       const toolVersionContent = '# python 3.8\npython 3.9'; |       const toolVersionContent = '# python 3.13\npython 3.12'; | ||||||
|       fs.writeFileSync(toolVersionFilePath, toolVersionContent); |       fs.writeFileSync(toolVersionFilePath, toolVersionContent); | ||||||
|       expect(_fn(toolVersionFilePath)).toEqual(['3.9']); |       expect(_fn(toolVersionFilePath)).toEqual(['3.12']); | ||||||
|     } |     } | ||||||
|   ); |   ); | ||||||
|  |  | ||||||
| @ -167,9 +195,9 @@ describe('Version from file test', () => { | |||||||
|     async _fn => { |     async _fn => { | ||||||
|       const toolVersionFileName = '.tool-versions'; |       const toolVersionFileName = '.tool-versions'; | ||||||
|       const toolVersionFilePath = path.join(tempDir, toolVersionFileName); |       const toolVersionFilePath = path.join(tempDir, toolVersionFileName); | ||||||
|       const toolVersionContent = '  python   3.10  '; |       const toolVersionContent = '  python   3.13  '; | ||||||
|       fs.writeFileSync(toolVersionFilePath, toolVersionContent); |       fs.writeFileSync(toolVersionFilePath, toolVersionContent); | ||||||
|       expect(_fn(toolVersionFilePath)).toEqual(['3.10']); |       expect(_fn(toolVersionFilePath)).toEqual(['3.13']); | ||||||
|     } |     } | ||||||
|   ); |   ); | ||||||
|  |  | ||||||
| @ -178,9 +206,9 @@ describe('Version from file test', () => { | |||||||
|     async _fn => { |     async _fn => { | ||||||
|       const toolVersionFileName = '.tool-versions'; |       const toolVersionFileName = '.tool-versions'; | ||||||
|       const toolVersionFilePath = path.join(tempDir, toolVersionFileName); |       const toolVersionFilePath = path.join(tempDir, toolVersionFileName); | ||||||
|       const toolVersionContent = 'python v3.9.10'; |       const toolVersionContent = 'python v3.13.2'; | ||||||
|       fs.writeFileSync(toolVersionFilePath, toolVersionContent); |       fs.writeFileSync(toolVersionFilePath, toolVersionContent); | ||||||
|       expect(_fn(toolVersionFilePath)).toEqual(['3.9.10']); |       expect(_fn(toolVersionFilePath)).toEqual(['3.13.2']); | ||||||
|     } |     } | ||||||
|   ); |   ); | ||||||
|  |  | ||||||
| @ -189,9 +217,9 @@ describe('Version from file test', () => { | |||||||
|     async _fn => { |     async _fn => { | ||||||
|       const toolVersionFileName = '.tool-versions'; |       const toolVersionFileName = '.tool-versions'; | ||||||
|       const toolVersionFilePath = path.join(tempDir, toolVersionFileName); |       const toolVersionFilePath = path.join(tempDir, toolVersionFileName); | ||||||
|       const toolVersionContent = 'python pypy3.10-7.3.14'; |       const toolVersionContent = 'python pypy3.10-7.3.19'; | ||||||
|       fs.writeFileSync(toolVersionFilePath, toolVersionContent); |       fs.writeFileSync(toolVersionFilePath, toolVersionContent); | ||||||
|       expect(_fn(toolVersionFilePath)).toEqual(['pypy3.10-7.3.14']); |       expect(_fn(toolVersionFilePath)).toEqual(['pypy3.10-7.3.19']); | ||||||
|     } |     } | ||||||
|   ); |   ); | ||||||
|  |  | ||||||
|  | |||||||
							
								
								
									
										37
									
								
								dist/setup/index.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										37
									
								
								dist/setup/index.js
									
									
									
									
										vendored
									
									
								
							| @ -96929,7 +96929,7 @@ function cacheDependencies(cache, pythonVersion) { | |||||||
| } | } | ||||||
| function resolveVersionInputFromDefaultFile() { | function resolveVersionInputFromDefaultFile() { | ||||||
|     const couples = [ |     const couples = [ | ||||||
|         ['.python-version', utils_1.getVersionInputFromPlainFile] |         ['.python-version', utils_1.getVersionsInputFromPlainFile] | ||||||
|     ]; |     ]; | ||||||
|     for (const [versionFile, _fn] of couples) { |     for (const [versionFile, _fn] of couples) { | ||||||
|         (0, utils_1.logWarning)(`Neither 'python-version' nor 'python-version-file' inputs were supplied. Attempting to find '${versionFile}' file.`); |         (0, utils_1.logWarning)(`Neither 'python-version' nor 'python-version-file' inputs were supplied. Attempting to find '${versionFile}' file.`); | ||||||
| @ -97066,7 +97066,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) { | |||||||
|     return (mod && mod.__esModule) ? mod : { "default": mod }; |     return (mod && mod.__esModule) ? mod : { "default": mod }; | ||||||
| }; | }; | ||||||
| Object.defineProperty(exports, "__esModule", ({ value: true })); | Object.defineProperty(exports, "__esModule", ({ value: true })); | ||||||
| exports.getDownloadFileName = exports.getNextPageUrl = exports.getBinaryDirectory = exports.getVersionInputFromFile = exports.getVersionInputFromToolVersions = exports.getVersionInputFromPlainFile = exports.getVersionInputFromTomlFile = exports.getOSInfo = exports.getLinuxInfo = exports.logWarning = exports.isCacheFeatureAvailable = exports.isGhes = exports.validatePythonVersionFormatForPyPy = exports.writeExactPyPyVersionFile = exports.readExactPyPyVersionFile = exports.getPyPyVersionFromPath = exports.isNightlyKeyword = exports.validateVersion = exports.createSymlinkInFolder = exports.WINDOWS_PLATFORMS = exports.WINDOWS_ARCHS = exports.IS_MAC = exports.IS_LINUX = exports.IS_WINDOWS = void 0; | exports.getDownloadFileName = exports.getNextPageUrl = exports.getBinaryDirectory = exports.getVersionInputFromFile = exports.getVersionInputFromToolVersions = exports.getVersionsInputFromPlainFile = exports.getVersionInputFromTomlFile = exports.getOSInfo = exports.getLinuxInfo = exports.logWarning = exports.isCacheFeatureAvailable = exports.isGhes = exports.validatePythonVersionFormatForPyPy = exports.writeExactPyPyVersionFile = exports.readExactPyPyVersionFile = exports.getPyPyVersionFromPath = exports.isNightlyKeyword = exports.validateVersion = exports.createSymlinkInFolder = exports.WINDOWS_PLATFORMS = exports.WINDOWS_ARCHS = exports.IS_MAC = exports.IS_LINUX = exports.IS_WINDOWS = void 0; | ||||||
| /* eslint no-unsafe-finally: "off" */ | /* eslint no-unsafe-finally: "off" */ | ||||||
| const cache = __importStar(__nccwpck_require__(5116)); | const cache = __importStar(__nccwpck_require__(5116)); | ||||||
| const core = __importStar(__nccwpck_require__(7484)); | const core = __importStar(__nccwpck_require__(7484)); | ||||||
| @ -97247,7 +97247,7 @@ function extractValue(obj, keys) { | |||||||
|  * If none is present, returns an empty list. |  * If none is present, returns an empty list. | ||||||
|  */ |  */ | ||||||
| function getVersionInputFromTomlFile(versionFile) { | function getVersionInputFromTomlFile(versionFile) { | ||||||
|     core.debug(`Trying to resolve version form ${versionFile}`); |     core.debug(`Trying to resolve version from ${versionFile}`); | ||||||
|     let pyprojectFile = fs_1.default.readFileSync(versionFile, 'utf8'); |     let pyprojectFile = fs_1.default.readFileSync(versionFile, 'utf8'); | ||||||
|     // Normalize the line endings in the pyprojectFile
 |     // Normalize the line endings in the pyprojectFile
 | ||||||
|     pyprojectFile = pyprojectFile.replace(/\r\n/g, '\n'); |     pyprojectFile = pyprojectFile.replace(/\r\n/g, '\n'); | ||||||
| @ -97280,15 +97280,30 @@ function getVersionInputFromTomlFile(versionFile) { | |||||||
| } | } | ||||||
| exports.getVersionInputFromTomlFile = getVersionInputFromTomlFile; | exports.getVersionInputFromTomlFile = getVersionInputFromTomlFile; | ||||||
| /** | /** | ||||||
|  * Python version extracted from a plain text file. |  * Python versions extracted from a plain text file. | ||||||
|  |  * - Resolves multiple versions from multiple lines. | ||||||
|  |  * - Handles pyenv-virtualenv pointers (e.g. `3.10/envs/virtualenv`). | ||||||
|  |  * - Ignores empty lines and lines starting with `#` | ||||||
|  |  * - Trims whitespace. | ||||||
|  */ |  */ | ||||||
| function getVersionInputFromPlainFile(versionFile) { | function getVersionsInputFromPlainFile(versionFile) { | ||||||
|     core.debug(`Trying to resolve version form ${versionFile}`); |     core.debug(`Trying to resolve versions from ${versionFile}`); | ||||||
|     const version = fs_1.default.readFileSync(versionFile, 'utf8').trim(); |     const content = fs_1.default.readFileSync(versionFile, 'utf8').trim(); | ||||||
|     core.info(`Resolved ${versionFile} as ${version}`); |     const lines = content.split(/\r\n|\r|\n/); | ||||||
|     return [version]; |     const versions = lines | ||||||
|  |         .map(line => { | ||||||
|  |         if (line.startsWith('#') || line.trim() === '') { | ||||||
|  |             return undefined; | ||||||
|  |         } | ||||||
|  |         let version = line.trim(); | ||||||
|  |         version = version.split('/')[0]; | ||||||
|  |         return version; | ||||||
|  |     }) | ||||||
|  |         .filter(version => version !== undefined); | ||||||
|  |     core.info(`Resolved ${versionFile} as ${versions.join(', ')}`); | ||||||
|  |     return versions; | ||||||
| } | } | ||||||
| exports.getVersionInputFromPlainFile = getVersionInputFromPlainFile; | exports.getVersionsInputFromPlainFile = getVersionsInputFromPlainFile; | ||||||
| /** | /** | ||||||
|  * Python version extracted from a .tool-versions file. |  * Python version extracted from a .tool-versions file. | ||||||
|  */ |  */ | ||||||
| @ -97331,7 +97346,7 @@ function getVersionInputFromFile(versionFile) { | |||||||
|         return getVersionInputFromToolVersions(versionFile); |         return getVersionInputFromToolVersions(versionFile); | ||||||
|     } |     } | ||||||
|     else { |     else { | ||||||
|         return getVersionInputFromPlainFile(versionFile); |         return getVersionsInputFromPlainFile(versionFile); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| exports.getVersionInputFromFile = getVersionInputFromFile; | exports.getVersionInputFromFile = getVersionInputFromFile; | ||||||
|  | |||||||
| @ -11,7 +11,7 @@ import { | |||||||
|   logWarning, |   logWarning, | ||||||
|   IS_MAC, |   IS_MAC, | ||||||
|   getVersionInputFromFile, |   getVersionInputFromFile, | ||||||
|   getVersionInputFromPlainFile |   getVersionsInputFromPlainFile | ||||||
| } from './utils'; | } from './utils'; | ||||||
|  |  | ||||||
| function isPyPyVersion(versionSpec: string) { | function isPyPyVersion(versionSpec: string) { | ||||||
| @ -35,7 +35,7 @@ async function cacheDependencies(cache: string, pythonVersion: string) { | |||||||
|  |  | ||||||
| function resolveVersionInputFromDefaultFile(): string[] { | function resolveVersionInputFromDefaultFile(): string[] { | ||||||
|   const couples: [string, (versionFile: string) => string[]][] = [ |   const couples: [string, (versionFile: string) => string[]][] = [ | ||||||
|     ['.python-version', getVersionInputFromPlainFile] |     ['.python-version', getVersionsInputFromPlainFile] | ||||||
|   ]; |   ]; | ||||||
|   for (const [versionFile, _fn] of couples) { |   for (const [versionFile, _fn] of couples) { | ||||||
|     logWarning( |     logWarning( | ||||||
|  | |||||||
							
								
								
									
										31
									
								
								src/utils.ts
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								src/utils.ts
									
									
									
									
									
								
							| @ -228,7 +228,7 @@ function extractValue(obj: any, keys: string[]): string | undefined { | |||||||
|  * If none is present, returns an empty list. |  * If none is present, returns an empty list. | ||||||
|  */ |  */ | ||||||
| export function getVersionInputFromTomlFile(versionFile: string): string[] { | export function getVersionInputFromTomlFile(versionFile: string): string[] { | ||||||
|   core.debug(`Trying to resolve version form ${versionFile}`); |   core.debug(`Trying to resolve version from ${versionFile}`); | ||||||
|  |  | ||||||
|   let pyprojectFile = fs.readFileSync(versionFile, 'utf8'); |   let pyprojectFile = fs.readFileSync(versionFile, 'utf8'); | ||||||
|   // Normalize the line endings in the pyprojectFile |   // Normalize the line endings in the pyprojectFile | ||||||
| @ -269,13 +269,28 @@ export function getVersionInputFromTomlFile(versionFile: string): string[] { | |||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Python version extracted from a plain text file. |  * Python versions extracted from a plain text file. | ||||||
|  |  * - Resolves multiple versions from multiple lines. | ||||||
|  |  * - Handles pyenv-virtualenv pointers (e.g. `3.10/envs/virtualenv`). | ||||||
|  |  * - Ignores empty lines and lines starting with `#` | ||||||
|  |  * - Trims whitespace. | ||||||
|  */ |  */ | ||||||
| export function getVersionInputFromPlainFile(versionFile: string): string[] { | export function getVersionsInputFromPlainFile(versionFile: string): string[] { | ||||||
|   core.debug(`Trying to resolve version form ${versionFile}`); |   core.debug(`Trying to resolve versions from ${versionFile}`); | ||||||
|   const version = fs.readFileSync(versionFile, 'utf8').trim(); |   const content = fs.readFileSync(versionFile, 'utf8').trim(); | ||||||
|   core.info(`Resolved ${versionFile} as ${version}`); |   const lines = content.split(/\r\n|\r|\n/); | ||||||
|   return [version]; |   const versions = lines | ||||||
|  |     .map(line => { | ||||||
|  |       if (line.startsWith('#') || line.trim() === '') { | ||||||
|  |         return undefined; | ||||||
|  |       } | ||||||
|  |       let version: string = line.trim(); | ||||||
|  |       version = version.split('/')[0]; | ||||||
|  |       return version; | ||||||
|  |     }) | ||||||
|  |     .filter(version => version !== undefined) as string[]; | ||||||
|  |   core.info(`Resolved ${versionFile} as ${versions.join(', ')}`); | ||||||
|  |   return versions; | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @ -319,7 +334,7 @@ export function getVersionInputFromFile(versionFile: string): string[] { | |||||||
|   } else if (versionFile.match('.tool-versions')) { |   } else if (versionFile.match('.tool-versions')) { | ||||||
|     return getVersionInputFromToolVersions(versionFile); |     return getVersionInputFromToolVersions(versionFile); | ||||||
|   } else { |   } else { | ||||||
|     return getVersionInputFromPlainFile(versionFile); |     return getVersionsInputFromPlainFile(versionFile); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Kryštof Korb
					Kryštof Korb