require 'errors' require 'faraday' require 'faraday_middleware' # Converts a_snake_case to aSnakCase # # Allows for Ruby classes to have the typical snake_case case handling, but # use camelCase styles for JSON. def camelize(s) s.split('_').inject([]){ |buffer,e| buffer.push(buffer.empty? ? e : e.capitalize) }.join end # Converts aCamelCase to a_camel_case # # Used to convert from JSON key names to Ruby snake case conventions def to_snake_case(s) s.gsub!(/(.)([A-Z])/, '\1_\2').downcase end # Will optionally wrap a string in quotes, escaping any quote chars def quotify(s) if s.include?(' ') "'#{depotPath.gsub(/'/, "\\'")}'" else s end end require 'helix_web_services_client/models' require 'helix_web_services_client/version' require 'json' class HelixWebServicesClient # Once authenticated, the `user` and `session_token` values are accessible # on the client object. attr_accessor :session_user, :session_token attr_accessor :prefix # Some values to initialize are only used by this class, and are not passed # on to the Faraday initializer INITIALIZE_LOCAL_OPTIONS = [:user, :password, :prefix] # The host_url is just the method and host, e.g., http://example.com/ # # The P4 Web API context should be set if you don't access URLs like # POST http://example.com/p4/v1/sessions. # # Any client created via new should take care to call close(). # # TODO specify the def initialize(options) # Filter out options we pass to Faraday faraday_options = options.select { |k| !INITIALIZE_LOCAL_OPTIONS.include?(k) } @conn = Faraday.new(faraday_options) do |conn| conn.request :multipart conn.request :url_encoded conn.response :logger conn.adapter :net_http end @session_user = nil @session_token = nil @prefix = options.key?(:prefix) ? options[:prefix] : '' if options.key?(:user) @session_user = options[:user] # When we're not initialized with a password, we may be on a insecure # server, so don't even log in. if options[:password] && !p4_ticket?(options[:password]) response = @conn.post(path_for('/auth/v1/sessions'), user: @session_user, password: options[:password]) assert_ok(response) @session_token = response.body else # When the password looks like a p4 ticket (or maybe it's empty), # we don't generate the session token, we just use this password @session_token = options[:password] || '' end set_auth(session_user, session_token) end end def close run_method_no_body(:delete, "/auth/v1/sessions/#{session_token}") end # Provides standard I/O style interface, where when called in a block, # will automatically close() the client when done. Otherwise, your code # should call client.close() manually. def self.open(connection) client = Client.new(connection) if block_given? yield client else return client end ensure client.close if block_given? && client end # Note: this class is really just common implementation. Methods are # generally defined in other files that reopen this class. def set_auth(user, token) @conn.basic_auth(user, token) end def p4_ticket?(str) /^[a-zA-Z0-9]{32,}$/.match(str) != nil end def execute_method_no_body(method, path, params = nil) response = run_method_no_body(method, path, params) JSON.parse(response.body) if response.body && !response.body.empty? end def execute_method_with_body(method, path, params = nil, body = nil) response = run_method_with_body(method, path, params, body) JSON.parse(response.body) if response.body && !response.body.empty? end def run_method_no_body(method, path, params = nil) path = path_for(path) response = @conn.send(method, path, params) assert_ok(response) response end def run_method_with_body(method, path, params = nil, body = nil) if !body && params body = params params = nil end path = path_for(path) if params params_hash = Faraday::Utils::ParamsHash.new params_hash.merge!(params) path += "?#{params_hash.to_query}" end response = @conn.send(method, path, body) assert_ok(response) response end # Basically just prepends the pr`efix to our subpath, typically, '/p4'. def path_for(subpath) if @prefix.nil? || @prefix.empty? subpath elsif subpath.nil? or subpath.empty? @prefix else File.join(@prefix, subpath) end end # Raises an error when the response is not 200. Some errors may have # diagnostic information in the response body, so we pass that on as well def assert_ok(response) return unless response.status >= 400 if response.status == 403 fail Errors::Unauthenticated.new, 'Illegal login or password' elsif response.status == 404 fail Errors::ResourceNotFound.new, 'Required resource not found' elsif response.status == 500 && response.body messages = nil begin messages = JSON.parse(response.body) rescue Exception => e messages = response.body end fail Errors::PerforceProblem.new(messages), 'Unknown issue from the Perforce server' else fail Errors::ServerError.new, "Unknown problem. Response code: #{response.status}" end end end require 'helix_web_services_client/branches' require 'helix_web_services_client/changes' require 'helix_web_services_client/clients' require 'helix_web_services_client/commands' require 'helix_web_services_client/depots' require 'helix_web_services_client/files' require 'helix_web_services_client/groups' require 'helix_web_services_client/jobs' require 'helix_web_services_client/labels' require 'helix_web_services_client/protections' require 'helix_web_services_client/servers' require 'helix_web_services_client/streams' require 'helix_web_services_client/sync_projects' require 'helix_web_services_client/triggers' require 'helix_web_services_client/users'
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#29 | 15622 | tjuricek |
Move source code to 'source/' subdirectory of branch. build/ will remain where it is. |
||
#28 | 15617 | tjuricek | Add P4PORT variable to 'remotetest' task, add 'debug' option to client. | ||
#27 | 15479 | tjuricek | Added a basic "HVE project" implementation for creating clients. | ||
#26 | 15461 | tjuricek |
Allow the settings to be specified on initialization of the client, and deal with Nginx issues and header keys. Nginx, by default, blocks all headers with underscores. Rack, on the other hand, convert hyphens to underscores. |
||
#25 | 15437 | tjuricek |
Basic "HVE Project" implementation. This will allow directories in a HVE instance to host 'projects' for use by helix sync. There are no methods defined for creating the projects, however. This does not include any specialization or testing in the Qt API yet. I may investigate creating a "higher level" interface for Qt client apps. |
||
#24 | 15297 | tjuricek |
Implement of 'cluster services' configuration. The configuration will be stored in a local JSON file, which is expected to be maintained by the systems admin. Eventually, it's expected to have this sort of thing implemented via Helix Admin. |
||
#23 | 15240 | tjuricek |
Set api level via request path on all Helix Versioning Engine methods. This will allow migration of applications to different P4D versions. Our internal methods (like project API) should attempt to handle backward compatibility similarly. P4WEBAPI-118 |
||
#22 | 15228 | tjuricek | Revise triggers implementation, tests, and documentation. | ||
#21 | 15227 | tjuricek |
Revise implementation, tests, and documentation for protections management. Remove some specs I will not be revising from the helix_web_services project. |
||
#20 | 15225 | tjuricek |
Revise counter implementation, tests, and documentation Wasn't available in the Ruby client before, so, it's now available. |
||
#19 | 15222 | tjuricek |
Revise server specs testing and documentation. Note: also fixed issues with setting P4PORT via headers. For whatever reason, the host setting doesn't seem to work like I expect it to, though P4PORT works just fine. |
||
#18 | 15211 | tjuricek | Implement tests and documentation for label spec management. | ||
#17 | 15210 | tjuricek | Implement tests and documentation for job spec management. | ||
#16 | 15209 | tjuricek | Implement tests and documentation for group spec management. | ||
#15 | 15208 | tjuricek |
Revise 'command' implementation, tests, and documentaiton. This includes a change from a command blacklist to a whitelist. See P4WEBAPI-21 |
||
#14 | 15205 | tjuricek | Implemented tests and documentation for depot spec editing. | ||
#13 | 15185 | tjuricek | Update user spec management implementation, tests, and documentation. | ||
#12 | 15132 | tjuricek | Provde a basic submit -e mechanism on classic perforce workspaces. | ||
#11 | 15110 | tjuricek | Revise changes methods for new p4 connection handling, add server specs, remove model references in client, and update asciidoc documentation. | ||
#10 | 15090 | tjuricek |
Update _proposed_ API for project services. This is *very likely* to change, and will not be implemented until reviewed. |
||
#9 | 15078 | tjuricek |
clients spec method revisions Updated some other documentation. |
||
#8 | 15077 | tjuricek |
Add new 'model' technique, revised branch spec operations, test Auth::Middleware. The Ruby client now does *not* strictly type anything, but extends OpenStruct with helper methods to help deal with inconsistent data formats. See the OpenModel class documentation for more details. The Auth::Middleware class is also *finally* implemented as well. This does not take into account all possible variations of server behavior (yet), but that will happen in follow-up work. |
||
#7 | 15059 | tjuricek | Tested authentication of the core /auth/v1/login method. | ||
#6 | 15053 | tjuricek |
Revise the client API to use the new login method. The current specs will need to be revised since data normalization is moving out of the server and into the client. |
||
#5 | 15038 | tjuricek | Document 'login' auth method and client programming overview. | ||
#4 | 13941 | tjuricek |
Re-implemented the sync project methods at the HTTP level. The Qt API is missing the "members" concept, but it's likely not quite usable just yet. It's existing logic does work, however. |
||
#3 | 13839 | tjuricek |
Conversion of the p4_project_service microservice to new monolithic system. This may not have an HTTP front end in the monolithic system. Project services are really just about how the core object model is structured. It's likely that each application will add their own wrinkles and extensions to the system, so it's unlikely we'll need a generic "project model". Exactly how extensions are registered and used is still a bit TBD at the moment. Previously they were to be registered webhooks, that model may change. Does not include tests yet. |
||
#2 | 13808 | tjuricek | Finish converting most of the core p4d API into the new monolithic system. | ||
#1 | 13799 | tjuricek |
Start with branch specs hosting in a new monolithic 'helix web services' project. Converting from a microservice to a monolithic architecture due to resource constraints at getting a deployable system running. Additionally, since it's not expected that people will upgrade often, the major benefit of microservices - being able to add services individually without affecting others - is not really a major benefit. The Ruby SDK will be consolidated into a single 'helix web services client' project. It may end up being distributed via Rubygems. This only runs branch specs at the moment. I want to get a CD pipeline setup for the monolithic server before revising more methods. |