Merge pull request #29 from clarkbw/maven-auth
Adding maven auth support
This commit is contained in:
		
						commit
						d8ada524fc
					
				
							
								
								
									
										2
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | ||||
| dist/index.js    -diff -merge | ||||
| dist/index.js    linguist-generated=true | ||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -93,3 +93,4 @@ typings/ | ||||
| 
 | ||||
| # DynamoDB Local files | ||||
| .dynamodb/ | ||||
| .vscode/ | ||||
|  | ||||
							
								
								
									
										126
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										126
									
								
								README.md
									
									
									
									
									
								
							| @ -13,7 +13,7 @@ This action sets up a java environment for use in actions by: | ||||
| 
 | ||||
| See [action.yml](action.yml) | ||||
| 
 | ||||
| Basic: | ||||
| ## Basic | ||||
| ```yaml | ||||
| steps: | ||||
| - uses: actions/checkout@v1 | ||||
| @ -25,7 +25,7 @@ steps: | ||||
| - run: java -cp java HelloWorldApp | ||||
| ``` | ||||
| 
 | ||||
| From local file: | ||||
| ## Local file | ||||
| ```yaml | ||||
| steps: | ||||
| - uses: actions/checkout@v1 | ||||
| @ -37,7 +37,7 @@ steps: | ||||
| - run: java -cp java HelloWorldApp | ||||
| ``` | ||||
| 
 | ||||
| Matrix Testing: | ||||
| ## Matrix Testing | ||||
| ```yaml | ||||
| jobs: | ||||
|   build: | ||||
| @ -56,6 +56,126 @@ jobs: | ||||
|       - run: java -cp java HelloWorldApp | ||||
| ``` | ||||
| 
 | ||||
| ## Publishing using Apache Maven | ||||
| ```yaml | ||||
| jobs: | ||||
|   build: | ||||
| 
 | ||||
|     runs-on: ubuntu-latest | ||||
| 
 | ||||
|     steps: | ||||
|     - uses: actions/checkout@v1 | ||||
|     - name: Set up JDK 1.8 | ||||
|       uses: actions/setup-java@v1 | ||||
|       with: | ||||
|         java-version: 1.8 | ||||
| 
 | ||||
|     - name: Build with Maven | ||||
|       run: mvn -B package --file pom.xml | ||||
| 
 | ||||
|     - name: Publish to GitHub Packages Apache Maven | ||||
|       run: mvn deploy | ||||
|       env: | ||||
|         GITHUB_TOKEN: ${{ github.token }} # GITHUB_TOKEN is the default env for the password | ||||
| 
 | ||||
|     - name: Set up Apache Maven Central | ||||
|       uses: actions/setup-java@v1 | ||||
|       with: # running setup-java again overwrites the settings.xml | ||||
|         java-version: 1.8 | ||||
|         server-id: maven # Value of the distributionManagement/repository/id field of the pom.xml | ||||
|         server-username: MAVEN_USERNAME # env variable for username in deploy | ||||
|         server-password: MAVEN_CENTRAL_TOKEN # env variable for token in deploy | ||||
| 
 | ||||
|     - name: Publish to Apache Maven Central | ||||
|       run: mvn deploy  | ||||
|       env: | ||||
|         MAVEN_USERNAME: maven_username123 | ||||
|         MAVEN_CENTRAL_TOKEN: ${{ secrets.MAVEN_CENTRAL_TOKEN }} | ||||
| ``` | ||||
| 
 | ||||
| The two `settings.xml` files created from the above example look like the following. | ||||
| 
 | ||||
| `settings.xml` file created for the first deploy to GitHub Packages | ||||
| ```xml | ||||
| <servers> | ||||
|     <server> | ||||
|       <id>github</id> | ||||
|       <username>${env.GITHUB_ACTOR}</username> | ||||
|       <password>${env.GITHUB_TOKEN}</password> | ||||
|     </server> | ||||
| </servers> | ||||
| ``` | ||||
| 
 | ||||
| `settings.xml` file created for the second deploy to Apache Maven Central | ||||
| ```xml | ||||
| <servers> | ||||
|     <server> | ||||
|       <id>maven</id> | ||||
|       <username>${env.MAVEN_USERNAME}</username> | ||||
|       <password>${env.MAVEN_CENTRAL_TOKEN}</password> | ||||
|     </server> | ||||
| </servers> | ||||
| ``` | ||||
| 
 | ||||
| ***NOTE: The `settings.xml` file is created in the Actions $HOME directory. If you have an existing `settings.xml` file at that location, it will be overwritten. See below for using the `settings-path` to change your `settings.xml` file location.***	 | ||||
| 
 | ||||
| See the help docs on [Publishing a Package](https://help.github.com/en/github/managing-packages-with-github-packages/configuring-apache-maven-for-use-with-github-packages#publishing-a-package) for more information on the `pom.xml` file. | ||||
| 
 | ||||
| ## Publishing using Gradle | ||||
| ```yaml | ||||
| jobs: | ||||
| 
 | ||||
|   build: | ||||
|     runs-on: ubuntu-latest | ||||
| 
 | ||||
|     steps: | ||||
|     - uses: actions/checkout@v1 | ||||
| 
 | ||||
|     - name: Set up JDK 1.8 | ||||
|       uses: actions/setup-java@v1 | ||||
| 
 | ||||
|     - name: Build with Gradle | ||||
|       run: gradle build | ||||
| 
 | ||||
|     - name: Publish to GitHub Packages | ||||
|       run: gradle publish | ||||
|       env: | ||||
|         USERNAME: ${{ github.actor }} | ||||
|         PASSWORD: ${{ secrets.GITHUB_TOKEN }} | ||||
| ``` | ||||
| 
 | ||||
| ***NOTE: The `USERNAME` and `PASSWORD` need to correspond to the credentials environment variables used in the publishing section of your `build.gradle`.***	 | ||||
| 
 | ||||
| See the help docs on [Publishing a Package with Gradle](https://help.github.com/en/github/managing-packages-with-github-packages/configuring-gradle-for-use-with-github-packages#example-using-gradle-groovy-for-a-single-package-in-a-repository) for more information on the `build.gradle` configuration file. | ||||
| 
 | ||||
| ## Apache Maven with a settings path | ||||
| 
 | ||||
| When using an Actions self-hosted runner with multiple shared runners the default `$HOME` directory can be shared by a number runners at the same time which could overwrite existing settings file. Setting the `settings-path` variable allows you to choose a unique location for your settings file. | ||||
| 
 | ||||
| ```yaml | ||||
| jobs: | ||||
|   build: | ||||
| 
 | ||||
|     runs-on: ubuntu-latest | ||||
| 
 | ||||
|     steps: | ||||
|     - uses: actions/checkout@v1 | ||||
|     - name: Set up JDK 1.8 for Shared Runner | ||||
|       uses: actions/setup-java@v1 | ||||
|       with: | ||||
|         java-version: 1.8 | ||||
|         server-id: github # Value of the distributionManagement/repository/id field of the pom.xml | ||||
|         settings-path: ${{ github.workspace }} # location for the settings.xml file | ||||
| 
 | ||||
|     - name: Build with Maven | ||||
|       run: mvn -B package --file pom.xml | ||||
| 
 | ||||
|     - name: Publish to GitHub Packages Apache Maven | ||||
|       run: mvn deploy -s $GITHUB_WORKSPACE/settings.xml | ||||
|       env: | ||||
|         GITHUB_TOKEN: ${{ github.token }} | ||||
| ``` | ||||
| 
 | ||||
| # License | ||||
| 
 | ||||
| The scripts and documentation in this project are released under the [MIT License](LICENSE) | ||||
|  | ||||
							
								
								
									
										144
									
								
								__tests__/auth.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								__tests__/auth.test.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,144 @@ | ||||
| import io = require('@actions/io'); | ||||
| import fs = require('fs'); | ||||
| import os = require('os'); | ||||
| import path = require('path'); | ||||
| 
 | ||||
| // make the os.homedir() call be local to the tests
 | ||||
| jest.doMock('os', () => { | ||||
|   return { | ||||
|     homedir: jest.fn(() => __dirname) | ||||
|   }; | ||||
| }); | ||||
| 
 | ||||
| import * as auth from '../src/auth'; | ||||
| 
 | ||||
| const m2Dir = path.join(__dirname, auth.M2_DIR); | ||||
| const settingsFile = path.join(m2Dir, auth.SETTINGS_FILE); | ||||
| 
 | ||||
| describe('auth tests', () => { | ||||
|   beforeEach(async () => { | ||||
|     await io.rmRF(m2Dir); | ||||
|   }, 300000); | ||||
| 
 | ||||
|   afterAll(async () => { | ||||
|     try { | ||||
|       await io.rmRF(m2Dir); | ||||
|     } catch { | ||||
|       console.log('Failed to remove test directories'); | ||||
|     } | ||||
|   }, 100000); | ||||
| 
 | ||||
|   it('creates settings.xml in alternate locations', async () => { | ||||
|     const id = 'packages'; | ||||
|     const username = 'UNAMI'; | ||||
|     const password = 'TOLKIEN'; | ||||
| 
 | ||||
|     const altHome = path.join(__dirname, 'runner', 'settings'); | ||||
|     const altSettingsFile = path.join(altHome, auth.SETTINGS_FILE); | ||||
|     process.env[`INPUT_SETTINGS-PATH`] = altHome; | ||||
|     await io.rmRF(altHome); // ensure it doesn't already exist
 | ||||
| 
 | ||||
|     await auth.configAuthentication(id, username, password); | ||||
| 
 | ||||
|     expect(fs.existsSync(m2Dir)).toBe(false); | ||||
|     expect(fs.existsSync(settingsFile)).toBe(false); | ||||
| 
 | ||||
|     expect(fs.existsSync(altHome)).toBe(true); | ||||
|     expect(fs.existsSync(altSettingsFile)).toBe(true); | ||||
|     expect(fs.readFileSync(altSettingsFile, 'utf-8')).toEqual( | ||||
|       auth.generate(id, username, password) | ||||
|     ); | ||||
| 
 | ||||
|     delete process.env[`INPUT_SETTINGS-PATH`]; | ||||
|     await io.rmRF(altHome); | ||||
|   }, 100000); | ||||
| 
 | ||||
|   it('creates settings.xml with username and password', async () => { | ||||
|     const id = 'packages'; | ||||
|     const username = 'UNAME'; | ||||
|     const password = 'TOKEN'; | ||||
| 
 | ||||
|     await auth.configAuthentication(id, username, password); | ||||
| 
 | ||||
|     expect(fs.existsSync(m2Dir)).toBe(true); | ||||
|     expect(fs.existsSync(settingsFile)).toBe(true); | ||||
|     expect(fs.readFileSync(settingsFile, 'utf-8')).toEqual( | ||||
|       auth.generate(id, username, password) | ||||
|     ); | ||||
|   }, 100000); | ||||
| 
 | ||||
|   it('overwrites existing settings.xml files', async () => { | ||||
|     const id = 'packages'; | ||||
|     const username = 'USERNAME'; | ||||
|     const password = 'PASSWORD'; | ||||
| 
 | ||||
|     fs.mkdirSync(m2Dir, {recursive: true}); | ||||
|     fs.writeFileSync(settingsFile, 'FAKE FILE'); | ||||
|     expect(fs.existsSync(m2Dir)).toBe(true); | ||||
|     expect(fs.existsSync(settingsFile)).toBe(true); | ||||
| 
 | ||||
|     await auth.configAuthentication(id, username, password); | ||||
| 
 | ||||
|     expect(fs.existsSync(m2Dir)).toBe(true); | ||||
|     expect(fs.existsSync(settingsFile)).toBe(true); | ||||
|     expect(fs.readFileSync(settingsFile, 'utf-8')).toEqual( | ||||
|       auth.generate(id, username, password) | ||||
|     ); | ||||
|   }, 100000); | ||||
| 
 | ||||
|   it('does not create settings.xml without required parameters', async () => { | ||||
|     await auth.configAuthentication('FOO'); | ||||
| 
 | ||||
|     expect(fs.existsSync(m2Dir)).toBe(true); | ||||
|     expect(fs.existsSync(settingsFile)).toBe(true); | ||||
|     expect(fs.readFileSync(settingsFile, 'utf-8')).toEqual( | ||||
|       auth.generate('FOO', auth.DEFAULT_USERNAME, auth.DEFAULT_PASSWORD) | ||||
|     ); | ||||
| 
 | ||||
|     await auth.configAuthentication(undefined, 'BAR', undefined); | ||||
| 
 | ||||
|     expect(fs.existsSync(m2Dir)).toBe(true); | ||||
|     expect(fs.existsSync(settingsFile)).toBe(true); | ||||
|     expect(fs.readFileSync(settingsFile, 'utf-8')).toEqual( | ||||
|       auth.generate(auth.DEFAULT_ID, 'BAR', auth.DEFAULT_PASSWORD) | ||||
|     ); | ||||
| 
 | ||||
|     await auth.configAuthentication(undefined, undefined, 'BAZ'); | ||||
| 
 | ||||
|     expect(fs.existsSync(m2Dir)).toBe(true); | ||||
|     expect(fs.existsSync(settingsFile)).toBe(true); | ||||
|     expect(fs.readFileSync(settingsFile, 'utf-8')).toEqual( | ||||
|       auth.generate(auth.DEFAULT_ID, auth.DEFAULT_USERNAME, 'BAZ') | ||||
|     ); | ||||
| 
 | ||||
|     await auth.configAuthentication(); | ||||
| 
 | ||||
|     expect(fs.existsSync(m2Dir)).toBe(true); | ||||
|     expect(fs.existsSync(settingsFile)).toBe(true); | ||||
|     expect(fs.readFileSync(settingsFile, 'utf-8')).toEqual( | ||||
|       auth.generate( | ||||
|         auth.DEFAULT_ID, | ||||
|         auth.DEFAULT_USERNAME, | ||||
|         auth.DEFAULT_PASSWORD | ||||
|       ) | ||||
|     ); | ||||
|   }, 100000); | ||||
| 
 | ||||
|   it('escapes invalid XML inputs', () => { | ||||
|     const id = 'packages'; | ||||
|     const username = 'USER'; | ||||
|     const password = '&<>"\'\'"><&'; | ||||
| 
 | ||||
|     expect(auth.generate(id, username, password)).toEqual(` | ||||
|   <settings> | ||||
|       <servers> | ||||
|         <server> | ||||
|           <id>${id}</id> | ||||
|           <username>\${env.${username}}</username> | ||||
|           <password>\${env.&<>"''"><&}</password> | ||||
|         </server> | ||||
|       </servers> | ||||
|   </settings> | ||||
|   `);
 | ||||
|   }); | ||||
| }); | ||||
							
								
								
									
										26
									
								
								action.yml
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								action.yml
									
									
									
									
									
								
							| @ -1,9 +1,11 @@ | ||||
| name: 'Setup Java JDK' | ||||
| description: 'Set up a specific version of the Java JDK and add the command-line tools to the PATH' | ||||
| description: 'Set up a specific version of the Java JDK and add the | ||||
|    command-line tools to the PATH' | ||||
| author: 'GitHub' | ||||
| inputs:  | ||||
| inputs: | ||||
|   java-version: | ||||
|     description: 'The Java version to make available on the path. Takes a whole or semver Java version, or 1.x syntax (e.g. 1.8 => Java 8.x)' | ||||
|     description: 'The Java version to make available on the path. Takes a whole | ||||
|        or semver Java version, or 1.x syntax (e.g. 1.8 => Java 8.x)' | ||||
|     required: true | ||||
|   java-package: | ||||
|     description: 'The package type (jre, jdk, jdk+fx)' | ||||
| @ -14,7 +16,23 @@ inputs: | ||||
|     required: false | ||||
|     default: 'x64' | ||||
|   jdkFile: | ||||
|     description: 'Path to where the compressed JDK is located. The path could be in your source repository or a local path on the agent.' | ||||
|     description: 'Path to where the compressed JDK is located. The path could | ||||
|        be in your source repository or a local path on the agent.' | ||||
|     required: false | ||||
|   server-id: | ||||
|     description: 'ID of the distributionManagement repository in the pom.xml | ||||
|        file. Default is `github`' | ||||
|     required: false | ||||
|   server-username: | ||||
|     description: 'Environment variable name for the username for authentication | ||||
|        to the Apache Maven repository. Default is $GITHUB_ACTOR' | ||||
|     required: false | ||||
|   server-password: | ||||
|     description: 'Environment variable name for password or token for | ||||
|        authentication to the Apache Maven repository. Default is $GITHUB_TOKEN' | ||||
|     required: false | ||||
|   settings-path: | ||||
|     description: 'Path to where the settings.xml file will be written. Default is ~/.m2.' | ||||
|     required: false | ||||
| runs: | ||||
|   using: 'node12' | ||||
|  | ||||
							
								
								
									
										
											BIN
										
									
								
								dist/index.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								dist/index.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											Binary file not shown.
										
									
								
							| @ -5,10 +5,11 @@ | ||||
|   "description": "setup java action", | ||||
|   "main": "dist/index.js", | ||||
|   "scripts": { | ||||
|     "build": "tsc", | ||||
|     "build": "ncc build src/setup-java.ts", | ||||
|     "format": "prettier --write **/*.ts", | ||||
|     "format-check": "prettier --check **/*.ts", | ||||
|     "release": "ncc build && git add -f dist/", | ||||
|     "prerelease": "npm run-script build", | ||||
|     "release": "git add -f dist/index.js", | ||||
|     "test": "jest" | ||||
|   }, | ||||
|   "repository": { | ||||
|  | ||||
							
								
								
									
										74
									
								
								src/auth.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								src/auth.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,74 @@ | ||||
| import * as fs from 'fs'; | ||||
| import * as os from 'os'; | ||||
| import * as path from 'path'; | ||||
| import * as core from '@actions/core'; | ||||
| import * as io from '@actions/io'; | ||||
| 
 | ||||
| export const M2_DIR = '.m2'; | ||||
| export const SETTINGS_FILE = 'settings.xml'; | ||||
| 
 | ||||
| export const DEFAULT_ID = 'github'; | ||||
| export const DEFAULT_USERNAME = 'GITHUB_ACTOR'; | ||||
| export const DEFAULT_PASSWORD = 'GITHUB_TOKEN'; | ||||
| 
 | ||||
| export async function configAuthentication( | ||||
|   id = DEFAULT_ID, | ||||
|   username = DEFAULT_USERNAME, | ||||
|   password = DEFAULT_PASSWORD | ||||
| ) { | ||||
|   console.log( | ||||
|     `creating ${SETTINGS_FILE} with server-id: ${id};`, | ||||
|     `environment variables: username=\$${username} and password=\$${password}` | ||||
|   ); | ||||
|   // when an alternate m2 location is specified use only that location (no .m2 directory)
 | ||||
|   // otherwise use the home/.m2/ path
 | ||||
|   const directory: string = path.join( | ||||
|     core.getInput('settings-path') || os.homedir(), | ||||
|     core.getInput('settings-path') ? '' : M2_DIR | ||||
|   ); | ||||
|   await io.mkdirP(directory); | ||||
|   core.debug(`created directory ${directory}`); | ||||
|   await write(directory, generate(id, username, password)); | ||||
| } | ||||
| 
 | ||||
| function escapeXML(value: string) { | ||||
|   return value | ||||
|     .replace(/&/g, '&') | ||||
|     .replace(/</g, '<') | ||||
|     .replace(/>/g, '>') | ||||
|     .replace(/"/g, '"') | ||||
|     .replace(/'/g, '''); | ||||
| } | ||||
| 
 | ||||
| // only exported for testing purposes
 | ||||
| export function generate( | ||||
|   id = DEFAULT_ID, | ||||
|   username = DEFAULT_USERNAME, | ||||
|   password = DEFAULT_PASSWORD | ||||
| ) { | ||||
|   return ` | ||||
|   <settings> | ||||
|       <servers> | ||||
|         <server> | ||||
|           <id>${escapeXML(id)}</id> | ||||
|           <username>\${env.${escapeXML(username)}}</username> | ||||
|           <password>\${env.${escapeXML(password)}}</password> | ||||
|         </server> | ||||
|       </servers> | ||||
|   </settings> | ||||
|   `;
 | ||||
| } | ||||
| 
 | ||||
| async function write(directory: string, settings: string) { | ||||
|   const location = path.join(directory, SETTINGS_FILE); | ||||
|   if (fs.existsSync(location)) { | ||||
|     console.warn(`overwriting existing file ${location}`); | ||||
|   } else { | ||||
|     console.log(`writing ${location}`); | ||||
|   } | ||||
| 
 | ||||
|   return fs.writeFileSync(location, settings, { | ||||
|     encoding: 'utf-8', | ||||
|     flag: 'w' | ||||
|   }); | ||||
| } | ||||
| @ -1,5 +1,6 @@ | ||||
| import * as core from '@actions/core'; | ||||
| import * as installer from './installer'; | ||||
| import * as auth from './auth'; | ||||
| import * as path from 'path'; | ||||
| 
 | ||||
| async function run() { | ||||
| @ -16,6 +17,14 @@ async function run() { | ||||
| 
 | ||||
|     const matchersPath = path.join(__dirname, '..', '.github'); | ||||
|     console.log(`##[add-matcher]${path.join(matchersPath, 'java.json')}`); | ||||
| 
 | ||||
|     const id = core.getInput('server-id', {required: false}) || undefined; | ||||
|     const username = | ||||
|       core.getInput('server-username', {required: false}) || undefined; | ||||
|     const password = | ||||
|       core.getInput('server-password', {required: false}) || undefined; | ||||
| 
 | ||||
|     await auth.configAuthentication(id, username, password); | ||||
|   } catch (error) { | ||||
|     core.setFailed(error.message); | ||||
|   } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user