Skip to content
This repository has been archived by the owner on Sep 6, 2022. It is now read-only.

Commit

Permalink
Merge branch 'master' into project-det
Browse files Browse the repository at this point in the history
  • Loading branch information
nakhbari committed Jun 26, 2018
2 parents 83c8e86 + 837bc9a commit da83ac8
Show file tree
Hide file tree
Showing 19 changed files with 168 additions and 57 deletions.
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ GIT

GIT
remote: https://github.com/fastlane/ruby-git
revision: d595bf802aa9d95fdb62e1b5be03c05560bf85ed
revision: fcbf92632e47c8a4a57061877c839a805c07cd54
specs:
git (1.4.0)

Expand Down
2 changes: 0 additions & 2 deletions PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
```
- [ ] I have run `rspec` and corrected all errors
- [ ] I have run `rubocop` and corrected all errors
- [ ] I have run `npm run test` and corrected all errors
- [ ] I have tested this change locally and tried to launch the server as well as access a project, and with that at least one build
- [ ] If there is an existing issue, make sure to add `Fixes ...` as part of the PR body to reference the issue you're solving
```
2 changes: 2 additions & 0 deletions app/features-json/build_json_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ module FastlaneCI
class BuildJSONController < APIController
HOME = "/data/projects/:project_id/build"

use(FastlaneCI::BuildWebsocketBackend)

get "#{HOME}/:build_number" do |project_id, build_number|
build = current_project.builds.find { |b| b.number == build_number.to_i }
if build.nil?
Expand Down
2 changes: 1 addition & 1 deletion app/features-json/project_json_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ class ProjectJSONController < APIController
# to the project details only when this task is finished.
repo = GitRepo.new(
git_config: repo_config,
provider_credential: provider_credential,
provider_credential: current_user_provider_credential,
local_folder: project.local_repo_path,
async_start: false,
notification_service: FastlaneCI::Services.notification_service
Expand Down
22 changes: 6 additions & 16 deletions app/features/build/build_websocket_backend.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,6 @@ def initialize(app)
self.websocket_clients = {}
end

def fetch_build_details(event)
url = event.target.url
parameters = Rack::Utils.parse_query(url)

return {
project_id: parameters["project"],
build_number: parameters["build"].to_i
}
end

def call(env)
unless Faye::WebSocket.websocket?(env)
# This is a regular HTTP call (no socket connection)
Expand All @@ -48,9 +38,9 @@ def call(env)
ws.on(:open) do |event|
logger.debug([:open, ws.object_id])

url_details = fetch_build_details(event)
build_number = url_details[:build_number]
project_id = url_details[:project_id]
request_params = Rack::Request.new(env).params
build_number = request_params["build_number"].to_i
project_id = request_params["project_id"]

websocket_clients[project_id] ||= {}
websocket_clients[project_id][build_number] ||= []
Expand All @@ -75,9 +65,9 @@ def call(env)
ws.on(:close) do |event|
logger.debug([:close, ws.object_id, event.code, event.reason])

url_details = fetch_build_details(event)
build_number = url_details[:build_number]
project_id = url_details[:project_id]
request_params = Rack::Request.new(env).params
build_number = request_params["build_number"].to_i
project_id = request_params["project_id"]

websocket_clients[project_id][build_number].delete(ws)
web_socket_build_runner_change_listener.connection_closed
Expand Down
2 changes: 1 addition & 1 deletion app/features/build/views/build.erb
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@
document.addEventListener("DOMContentLoaded", function(event) {
var scheme = "ws://"
var uri = scheme + window.document.location.host
uri += "/?&project=<%= project.id %>&build=<%= build.number %>"; // we add that extra & to make the Ruby URI parser work
uri += "/?&project_id=<%= project.id %>&build_number=<%= build.number %>"; // we add that extra & to make the Ruby URI parser work
var ws = new WebSocket(uri);
console.log("Listening to web socket connection now for URL " + uri + "...")
var firstMessageReceived = <%= existing_rows.to_s.length == 0 ? false : true %>;
Expand Down
2 changes: 1 addition & 1 deletion app/shared/models/git_repo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -666,7 +666,7 @@ def switch_to_ref(git_fork_config:, local_branch_name:, use_global_git_mutex: fa
begin
ref = "#{git_fork_config.ref}:#{local_branch_name}"
logger.debug("Switching to new branch from ref #{ref} (pulling into #{local_branch_name})")
git.fetch(GitRepo::DEFAULT_REMOTE, ref, {})
git.fetch(GitRepo::DEFAULT_REMOTE, { ref: ref })
git.branch(local_branch_name)
git.checkout(local_branch_name)
return true
Expand Down
20 changes: 20 additions & 0 deletions docs/Projects.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Projects

A project in fastlane.ci is defined as a combination of a git repo + a trigger + parameters.

- A git repo can have any number of projects associated
- You can have any number of projects using the same git repo and trigger **type**
- fastlane.ci support multiple [trigger types](https://github.com/fastlane/ci/blob/master/docs/Triggers.md), each of which takes parameters (e.g. what times to run, what branches to build)

Example projects would be

- `Bike App test PRs` (Run unit tests for every PR)
- `Bike App nightly builds` (build a new internal beta every day at 5pm)
- `Bike App weekly public beta` (build a new beta every Friday for external testers)
- `Bike App App Store release` (Manually triggered whenever team wants to ship)

As you can see, the `Bike App` has 4 jobs associated, a total of 3 trigger types.

For each project, the developer selects a `lane` to run for the given project.
A `lane` is a concept of [fastlane](https://fastlane.tools) that basically defines a build/deploy environment.
Common lanes are `run_tests`, `distribute_beta` or `deploy_to_app_store`.
15 changes: 13 additions & 2 deletions web/app/build/build.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,17 @@
<span *ngIf="build && build.description" class="fci-build-description">{{build.description}}</span>
</div>
<div class="fci-build-logs">
{{logs.length > 0 ? logs : 'Connecting...'}}
<ng-container *ngIf="logs.length <= 0; else hasLogs">Connecting...</ng-container>
<ng-container #hasLogs *ngFor="let log of logs">
{{log.message}}
<br>
</ng-container>
</div>
</div>
<div class="fci-right-container">
<mat-card class="fci-build-details">
<h3>Build Info</h3>
<mat-spinner *ngIf="!build" mode="indeterminate"></mat-spinner>
<mat-spinner *ngIf="!build" mode="indeterminate" class="fci-loading-spinner"></mat-spinner>
<ng-container *ngIf="build">
<h5>Trigger</h5>
<div>{{build.trigger}}</div>
Expand All @@ -29,5 +33,12 @@ <h5>Duration</h5>
</ng-container>
</ng-container>
</mat-card>
<mat-card class="fci-artifacts">
<h3>Artifacts</h3>
<mat-spinner *ngIf="!build" mode="indeterminate" class="fci-loading-spinner"></mat-spinner>
<ng-container *ngIf="build">
<div *ngFor="let artifact of build.artifacts" class="fci-artifact">{{artifact.name}}</div>
</ng-container>
</mat-card>
</div>
</div>
14 changes: 13 additions & 1 deletion web/app/build/build.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,24 @@ $TOOLBAR_HEIGHT:80px;
}
.fci-right-container {
padding-left: 16px;
.fci-build-details {
.fci-build-details,
.fci-artifacts {
width: 296px;
margin-bottom: 25px;
h5 {
margin-bottom: 0;
text-transform: uppercase;
}
.fci-artifact {
font-size: 14px;
&:not(:last-child) {
margin-bottom: 18px;
}
}
}
}
}

.fci-loading-spinner {
margin: 32px auto;
}
53 changes: 45 additions & 8 deletions web/app/build/build.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,12 @@ describe('BuildComponent', () => {
it('should update logs as they come in', () => {
fixture.detectChanges();
expect(component.logs).toEqual([]);
socketSubject.next(new MessageEvent('type', {data: 'log1'}));
expect(component.logs).toEqual(['log1']);
socketSubject.next(new MessageEvent('type', {data: 'log2'}));
expect(component.logs).toEqual(['log1', 'log2']);
socketSubject.next(
new MessageEvent('type', {data: '{"message": "log1"}'}));
expect(component.logs).toEqual([{message: 'log1'}]);
socketSubject.next(
new MessageEvent('type', {data: '{"message": "log2"}'}));
expect(component.logs).toEqual([{message: 'log1'}, {message: 'log2'}]);
});

it('should update breadcrumb urls after loading params', () => {
Expand Down Expand Up @@ -133,10 +135,11 @@ describe('BuildComponent', () => {
expect(component.logs.length).toBe(0);
expect(logsEl.innerText).toBe('Connecting...');

socketSubject.next(new MessageEvent('type', {data: 'this is a log'}));
socketSubject.next(
new MessageEvent('type', {data: '{"message": "this is a log"}'}));
fixture.detectChanges();

expect(logsEl.innerText).toBe('this is a log');
expect(logsEl.innerText.trim()).toBe('this is a log');
});

describe('header', () => {
Expand Down Expand Up @@ -192,12 +195,14 @@ describe('BuildComponent', () => {
});

it('should show spinner while loading', () => {
expect(detailsEl.queryAll(By.css('.mat-spinner')).length).toBe(1);
expect(detailsEl.queryAll(By.css('.fci-loading-spinner')).length)
.toBe(1);

buildSubject.next(mockBuild);
fixture.detectChanges();

expect(detailsEl.queryAll(By.css('.mat-spinner')).length).toBe(0);
expect(detailsEl.queryAll(By.css('.fci-loading-spinner')).length)
.toBe(0);
});

describe('after build loaded', () => {
Expand Down Expand Up @@ -244,5 +249,37 @@ describe('BuildComponent', () => {
});
});
});

describe('artifacts card', () => {
let cardEl: DebugElement;

beforeEach(() => {
cardEl = fixture.debugElement.query(By.css('.fci-artifacts'));
});

it('should show spinner while loading', () => {
expect(cardEl.queryAll(By.css('.fci-loading-spinner')).length).toBe(1);

buildSubject.next(mockBuild);
fixture.detectChanges();

expect(cardEl.queryAll(By.css('.fci-loading-spinner')).length).toBe(0);
});

describe('after build loaded', () => {
beforeEach(() => {
buildSubject.next(mockBuild);
fixture.detectChanges();
});

it('should show artifacts', () => {
const artifactEls = cardEl.queryAll(By.css('div.fci-artifact'));

expect(artifactEls.length).toBe(2);
expect(artifactEls[0].nativeElement.innerText).toBe('fastlane.log');
expect(artifactEls[1].nativeElement.innerText).toBe('hack.exe');
});
});
});
});
});
4 changes: 2 additions & 2 deletions web/app/build/build.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export class BuildComponent implements OnInit {
@HostBinding('class') classes = ['fci-full-height-container'];
build: Build;
// TODO: define interface for the logs
logs: string[] = [];
logs: Object[] = [];
readonly BuildStatus = BuildStatus;

readonly breadcrumbs: Breadcrumb[] =
Expand Down Expand Up @@ -48,7 +48,7 @@ export class BuildComponent implements OnInit {
this.buildLogSocketService.connect(projectId, buildNumber)
.subscribe((message) => {
// TODO: define a log line model.
this.logs.push(message.data);
this.logs.push(JSON.parse(message.data));
});
}

Expand Down
10 changes: 8 additions & 2 deletions web/app/common/test_helpers/mock_build_data.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Build, BuildResponse} from '../../models/build';
import {Build, BuildArtifactResponse, BuildResponse} from '../../models/build';
import {BuildSummary, BuildSummaryResponse} from '../../models/build_summary';

// TODO: move all these mocks to common/ since they're being re-used.
Expand All @@ -24,6 +24,11 @@ export const mockBuildSummaryResponse_success: BuildSummaryResponse = {
timestamp: '2018-04-04 16:11:58 -0700'
};

export const mockBuildArtifactResponse_log: BuildArtifactResponse = {
id: '12345',
type: 'fastlane.log'
};

export const mockBuildResponse: BuildResponse = {
project_id: 'a32ef71e-368c-4091-9344-7fdc8c1ff390',
number: 3,
Expand All @@ -40,7 +45,8 @@ export const mockBuildResponse: BuildResponse = {
branch: 'test-branch',
clone_url: 'https://github.com/nakhbari/HelloWorld.git',
ref: 'pull/1/head',
sha: '5903a0a7d2238846218c08ad9d5e278db7cf46c7'
sha: '5903a0a7d2238846218c08ad9d5e278db7cf46c7',
artifacts: [mockBuildArtifactResponse_log, {id: '54321', type: 'hack.exe'}]
};

export const mockBuild: Build = new Build(mockBuildResponse);
Expand Down
12 changes: 12 additions & 0 deletions web/app/models/artifact.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {mockBuildArtifactResponse_log} from '../common/test_helpers/mock_build_data';

import {Artifact} from './artifact';

describe('Artifact Model', () => {
it('should convert build artifact successfully', () => {
const artifact = new Artifact(mockBuildArtifactResponse_log);

expect(artifact.id).toBe('12345');
expect(artifact.name).toBe('fastlane.log');
});
});
11 changes: 11 additions & 0 deletions web/app/models/artifact.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {BuildArtifactResponse} from './build';

export class Artifact {
readonly id: string;
readonly name: string;

constructor(artifact: BuildArtifactResponse) {
this.id = artifact.id;
this.name = artifact.type;
}
}
3 changes: 3 additions & 0 deletions web/app/models/build.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ describe('Build Model', () => {
expect(build.branch).toBe('test-branch');
expect(build.ref).toBe('pull/1/head');
expect(build.buildTools).toEqual({'xcode_version': '9.1'});
expect(build.artifacts.length).toBe(2);
expect(build.artifacts[0].id).toBe('12345');
expect(build.artifacts[1].name).toBe('hack.exe');

// TODO: update this with real values once implemented on backend
expect(build.parameters).toBe(null);
Expand Down

0 comments on commit da83ac8

Please sign in to comment.